<?php
namespace App\Utils\BaseParser\Utils;

/**
 * Extract conjunctions tickets from ticketNumber (eg:"199999999-01")
 * @author Oana Stan
 */
class ConjunctionsTicketsConvertor
{
	use \App\Utils\BaseParser\SingletonTrait;

	/**
	 * Convert from a dash-delimited format to a list of tickets.
	 * Input format: {$firstTicketInSeries}-{$lastTicketSuffix}
	 * Possible inputs: "1234567890-91", "1234567890", "1234567890-891"
	 * @param string $ticketStr
	 * @throws \Exception
	 * @return array
	 */
	public function extractFromDashNotation($ticketStr)
	{

		// check for conjunctions
		$dashpos = strpos($ticketStr, "-");
		if ($dashpos===false) {
			return [$ticketStr];
		}

		$ticketsLen = strlen($ticketStr);

		// handle big numbers(>9 chars length). Working with these types of numbers directly as INTs will fail on 32-bit PHP
		$originalTicketNumberPrefix = '';
		if ($ticketsLen>9) {
			$originalTicketNumberRaw = 		substr($ticketStr, 0, $dashpos);
			$originalTicketNumber = 		substr($originalTicketNumberRaw, -9);
			$originalTicketNumberPrefix = 	substr($originalTicketNumberRaw, 0, -9);
		}
		else {
			$originalTicketNumber = substr($ticketStr, 0, $dashpos);
		}

		// check that the ticket and the prefix are numeric
		if (($originalTicketNumber && !is_numeric($originalTicketNumber)) || ($originalTicketNumberPrefix && !is_numeric($originalTicketNumberPrefix))) {
			throw new \RuntimeException('Either the original ticket or the prefix are not numeric. Ticket no: '.$originalTicketNumber);
		}

		// get last ticket number
		$endTicketNumber = substr($originalTicketNumber, 0, -($ticketsLen-$dashpos-1)) . substr($ticketStr, -($ticketsLen-$dashpos-1));

		// handle big numbers(>9 chars length). Working with these types of numbers directly as INTs will fail on 32-bit PHP
		$endTicketNumberLen = strlen($endTicketNumber);
		$endTicketNumberPrefix = '';
		if ($endTicketNumberLen>9) {
			$endTicketNumberRaw = $endTicketNumber;
			$endTicketNumber = substr($endTicketNumberRaw, -9);
			$endTicketNumberPrefix = substr($endTicketNumberRaw, 0, -9);

			// do some validations
			if($endTicketNumberPrefix && $originalTicketNumberPrefix) {
				if (strrpos($originalTicketNumberPrefix, $endTicketNumberPrefix)!==0) {
					throw new \Exception(sprintf("Cannot handle ticket number: %s. It implies too many changes. endTicketNumberPrefix doesn't match originalTicketNumberPrefix", $ticketStr));
				}

				if (strlen($endTicketNumberPrefix) > strlen($originalTicketNumberPrefix)) {
					throw new \Exception(sprintf("Cannot handle ticket number: %s. It implies too many changes. endTicketNumberPrefix is longer than originalTicketNumberPrefix", $ticketStr));
				}
			}
		}

		// compose the last ticket number in the series
		if ($endTicketNumber < $originalTicketNumber) {
			$endTicketNumber = sprintf("%0{$endTicketNumberLen}d", ((int)$endTicketNumber + pow(10, $ticketsLen-$dashpos-1)));

			if (strlen($endTicketNumber) != strlen($originalTicketNumber)) {
				throw new \Exception(sprintf("Cannot handle ticket number: %s. It implies too many changes. endTicketNumber is longer than originalTicketNumber", $ticketStr));
			}
		}

		$conjunctionsList = [];

		$tkt = $originalTicketNumber;
		$ol = strlen($originalTicketNumber);
		while ($tkt <= $endTicketNumber) {
			$conjunctionsList[] = $originalTicketNumberPrefix.sprintf("%0{$ol}s", $tkt);
			$tkt++;
		}

		return $conjunctionsList;
	}

	/**
	 * Convert from a dash-delimited format to a list of tickets.
	 * Possible inputs: ("1234567890", 0), ("1234567890", 1), ("1234567890", 123)
	 * Internally uses $this->extractFromDashNotation()
	 * @param string $ticketStr
	 * @param int $ticketCount
	 * @throws \Exception
	 * @return array
	 */
	public function extractFromTicketAndCount($ticketStr, $ticketCount)
	{
		if ($ticketCount<0) {
			throw new \Exception(sprintf("Cannot handle ticket number: %s with count %d. ticketCount should be positive", $ticketStr, $ticketCount));
		}

		$optimalLength = strlen($ticketCount)+1;
		$remainder = substr($ticketStr, -1*$optimalLength);
		$loops = 100;
		while ($loops-- && strlen($remainder+$ticketCount)>$optimalLength) {
			$optimalLength+=1;
			$remainder = substr($ticketStr, -1*$optimalLength);
		}

		if ($loops<=0) {
			throw new \Exception(sprintf("Cannot handle ticket number: %s. Infinite loop detected while figuring out optimalLength", $ticketStr));
		}

		$newTicketStr = sprintf("%s-%s", $ticketStr, (int)$remainder+$ticketCount);

		return $this->extractFromDashNotation($newTicketStr);
	}
}