<?php

/**
	 * This is a forked library modified for use in Formea extension,
	 * Credit goes to original author(s) Eduardo Gulias Davis at https://github.com/egulias/EmailValidator.
	 * See LICENSE
	 *
	 * @version     1.0.0
	 * @package     Formea Email Validation
	 * @subpackage  Lexer
	 * @author      Feseur Sdn Bhd
	 * @copyright   Copyright (C) 2010-2023 Feseur Sdn Bhd. All rights reserved.
	 * @license     GNU General Public License version 2 or later; see LICENSE.txt
	 */

	namespace Egulias\EmailValidator\Parser;

	use Egulias\EmailValidator\EmailLexer;
	use Egulias\EmailValidator\Result\ValidEmail;
	use Egulias\EmailValidator\Result\InvalidEmail;
	use Egulias\EmailValidator\Warning\CFWSWithFWS;
	use Egulias\EmailValidator\Warning\QuotedString;
	use Egulias\EmailValidator\Result\Reason\ExpectingATEXT;
	use Egulias\EmailValidator\Result\Reason\UnclosedQuotedString;
	use Egulias\EmailValidator\Result\Result;
	use Exception;

	class DoubleQuote extends PartParser
	{
		public function parse(): Result
		{

			$validQuotedString = $this->checkDQUOTE();
			if ($validQuotedString->isInvalid()) return $validQuotedString;

			$special = [
				EmailLexer::S_CR   => true,
				EmailLexer::S_HTAB => true,
				EmailLexer::S_LF   => true
			];

			$invalid = [
				EmailLexer::C_NUL  => true,
				EmailLexer::S_HTAB => true,
				EmailLexer::S_CR   => true,
				EmailLexer::S_LF   => true
			];

			$setSpecialsWarning = true;

			$this->lexer->moveNext();

			while (((array) $this->lexer->token)['type'] !== EmailLexer::S_DQUOTE && null !== ((array) $this->lexer->token)['type'])
			{
				if (isset($special[((array) $this->lexer->token)['type']]) && $setSpecialsWarning)
				{
					$this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
					$setSpecialsWarning                = false;
				}
				if (((array) $this->lexer->token)['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE))
				{
					$this->lexer->moveNext();
				}

				$this->lexer->moveNext();

				if (!$this->escaped() && isset($invalid[((array) $this->lexer->token)['type']]))
				{
					return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), ((array) $this->lexer->token)['value']);
				}
			}

			$prev = $this->lexer->getPrevious();

			if ($prev['type'] === EmailLexer::S_BACKSLASH)
			{
				$validQuotedString = $this->checkDQUOTE();
				if ($validQuotedString->isInvalid()) return $validQuotedString;
			}

			if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH)
			{
				return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), ((array) $this->lexer->token)['value']);
			}

			return new ValidEmail();
		}

		protected function checkDQUOTE(): Result
		{
			$previous = $this->lexer->getPrevious();

			if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC)
			{
				$description = 'https://tools.ietf.org/html/rfc5322#section-3.2.4 - quoted string should be a unit';

				return new InvalidEmail(new ExpectingATEXT($description), ((array) $this->lexer->token)['value']);
			}

			try
			{
				$this->lexer->find(EmailLexer::S_DQUOTE);
			}
			catch (Exception $e)
			{
				return new InvalidEmail(new UnclosedQuotedString(), ((array) $this->lexer->token)['value']);
			}
			$this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], ((array) $this->lexer->token)['value']);

			return new ValidEmail();
		}

	}
