public function findToken($search, $offset = 0)
    {
        if ($search === null)
        {
            throw new \InvalidArgumentException('A token cannot be searched for with a null value.');
        }
        elseif (!is_int($offset))
        {
            throw new \InvalidArgumentException('On offset must be specified as an integer.');
        }

        if ($offset >= 0)
        {
            // Offset is greater than zero. Search from left to right
            $tokenizer   = clone $this;
            $is_reversed = false;
        }
        else
        {
            // Offset is negative. Search from right to left
            $tokenizer   = new Tokenizer(array_reverse($this->tokens));
            $offset      = abs($offset) - 1;
            $is_reversed = true;
        }

        // Seek to the offset and start the search from there
        $tokenizer->seek($offset);

        // Loop through the tokens and search for the target token
        while ($tokenizer->valid())
        {
            $token = $tokenizer->current();

            if ($token->code === $search || $token->name === $search || $token->value === $search)
            {
                $index = $tokenizer->key();

                // Calculate the index as if the tokenizer is not reversed
                if ($is_reversed)
                {
                    $index = count($tokenizer) - $index - 1;
                }

                return $index;
            }

            $tokenizer->next();
        }

        return false;
    }