<?php
namespace App\GenDocument\SpecialObject;

class FlightItinerary extends GeneralAbstract
{
	protected $debug = false;

	protected $attributes = [
		'layer' => 0,
	];

	protected $stats = [
		'Ymm' => null,
	];

	protected $WmmColumn1 = 55;

	protected $fontSizeMm = [];

	public function __construct($pivot, $idPivot, $settings, $textProcessor, $extraParams)
	{
		parent::__construct($pivot, $idPivot, $settings, $textProcessor, $extraParams);

		$remappedResults = array_map(function($font) {
			return [$font['id'], $font['charSize']];
		}, \App\Utils\FopManager\Installer::getInstance()->getAvailableFonts());

		$this->fontSizeMm = array_column($remappedResults, 1, 0);
	}

	public function render()
	{
		/////////////////////////////////////////////////////////////////////
		// GET SERVICE ITINERARY ////////////////////////////////////////////
		////////////////////////////////////////////////////////////////////
		$importedServiceEntity = \Entity\ImportedService::select($this->idPivot);
		$idExternalSystem = $importedServiceEntity->idSystem;
		$importedServiceObject = $importedServiceEntity->object;
		$chosenOfferObject = $importedServiceObject->chosenOffer;

		if (!$chosenOfferObject) {
			return false;
		}

		$itineraryObject = $chosenOfferObject->itinerary;
		/* @var $itineraryObject \App\ImportedOrder\Itinerary */

		if (!$itineraryObject) {
			return false;
		}

		// $em = 2.3;	// equivalent to the HTMl em unit
		// $LS = 2.8;	// line-spacing
		$em = 0.55*$this->settings['setting_fontSize'] * $this->fontSizeMm[$this->settings['setting_fontFamily']];
		$LS = 1.21*$em;

		$this->stats['em'] = $em;
		$this->stats['LS'] = $LS;

		$output = [];

		// the special object is set as relative
		if ($this->settings['fixed'])  {
			$this->stats['Ymm'] = $this->settings['setting_Ymm'];
		}
		else {
			$this->stats['Ymm'] = $this->settings['Ymm'];
		}

		$segments = (array)$itineraryObject->segments;

		foreach ($segments as $segmentObject) {
			$XmmColumn2 = $this->settings['Xmm'] + $this->WmmColumn1 + 1;

			// HORIZONTAL RED LINE ///////////////////////////////////////////////////////////////////////////////////////////////////////////
			$output = $this->renderHorizontalLine($output, $this->stats['Ymm'], 0.4, $this->settings['setting_lineColor']);

			// SEGMENT GENERAL DETAILS (FROM => TO) ////////////////////////////////////////////////////////////////////////////////////////////
			$segmentGeneralDetails = $this->getSegmentGeneralDetails($segmentObject, $idExternalSystem);
			$output = $this->renderText($output, $this->stats['Ymm'] + 0.5*$LS, $this->settings['Xmm'], $segmentGeneralDetails, 0.8);

			// SEGMENT DEPARTURE DETAILS - DEPARTURE DATE, FLIGHT DURATION , SEGMENT STATUS
			$departureDateTimeObject = $segmentObject->departureDateTime;
			$departureDateTimeText = '-';
			$departureDateTimeHours = '-';
			if ($departureDateTimeObject) {
				$departureDateTimeHours = $departureDateTimeObject->format('H:i');
				$departureDateTimeText = sprintf("<b>%s, %s, %s </b>|", $departureDateTimeObject->format('l'), $departureDateTimeObject->format('d M Y'), $departureDateTimeHours);
			}
			$flightDuration = sprintf("Flight duration: %s |", ($segmentObject->duration?substr($segmentObject->duration, 0, 5):'-'));
			$status = "Status: CONFIRMED";
			$output = $this->renderText($output, $this->stats['Ymm'] + 2*$LS, $this->settings['Xmm'], sprintf("%s %s %s", $departureDateTimeText, $flightDuration, $status), false);

			// AIRLINE DETAILS ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$supplierObject = $segmentObject->supplier;
			$supplierName = null;
			$supplierIataCode = null;
			if ($supplierObject) {
				$supplierMatchedId = $supplierObject->getMatchedId($idExternalSystem);
				if ($supplierMatchedId) {
					$supplierEntity = 	\Entity\Supplier::select($supplierMatchedId);
					$supplierName = 	$supplierEntity->companyFull;
					$supplierIataCode = $supplierEntity->codeIata;
				}

				if (!$supplierIataCode) {
					$supplierIataCode = $supplierObject->codes ? $supplierObject->codes['iata'] : '';
				}
			}

			$airlineDetails = sprintf("%s %s%s", $supplierName, $supplierIataCode, $segmentObject->transportNumber);

			// operated by
			$operatedBy = $segmentObject->operatedBy;
			if ($operatedBy) {
				$airlineDetails .= sprintf(" | Operated by: %s", $operatedBy->name);
			}

			$output = $this->renderText($output, $this->stats['Ymm'] + $LS, $this->settings['Xmm'], $airlineDetails, false);

			// HORIZONTAL GREY LINE //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$output = $this->renderHorizontalLine($output, $this->stats['Ymm'] + 1.5*$em, 0.2, '#BFBFBF');

			// DEPARTURE FROM ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$departureCoordYmm = $this->stats['Ymm'] + $LS;
			$output = $this->renderTextWithBorder($output, $departureCoordYmm, $this->settings['Xmm'], null, "Departure from: ", true, "#EAEAEA");

			// populate terminal checkin
			$terminalCheckIn = $segmentObject->terminalCheckIn;
			if (!$terminalCheckIn) {
				$terminalCheckIn = 'not available';
			}

			$departureFromText = sprintf("<b>%s</b> | %s | TERMINAL %s", $departureDateTimeHours, $this->getDepartureCityAndStation($segmentObject, $idExternalSystem), $terminalCheckIn);
			$output = $this->renderText($output, $departureCoordYmm, $XmmColumn2, $departureFromText, false);

			// ARRIVAL TO /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$Ymm = $this->stats['Ymm'] + 0.5*$LS;
			$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "Arrival to: ", true, "#EAEAEA");

			$arrivalDateTimeObject = $segmentObject->arrivalDateTime;
			$arrivalDateTimeHours = '-';
			if ($arrivalDateTimeObject) {
				$arrivalDateTimeHours = $arrivalDateTimeObject->format('H:i');
			}

			// populate terminal checkout
			$terminalCheckOut = $segmentObject->terminalCheckOut;
			if (!$terminalCheckOut) {
				$terminalCheckOut = 'not available';
			}

			$arrivalToText = sprintf("<b>%s</b> | %s | TERMINAL %s", $arrivalDateTimeHours, $this->getArrivalCityAndStation($segmentObject, $idExternalSystem), $terminalCheckOut);
			$output = $this->renderText($output, $Ymm, $XmmColumn2, $arrivalToText, false);

			// DISTANCE //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$distance = 		$segmentObject->distance;
			$distanceUnit = 	$segmentObject->distanceUnit;

			if ($distance) {
				$Ymm = $this->stats['Ymm'] + 0.5*$LS;

				$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "Distance: ", true, "#EAEAEA");
				$distanceText = sprintf("%s %s", $distance, $distanceUnit);
				$output = $this->renderText($output, $Ymm, $XmmColumn2, $distanceText, false);
			}

			//////////// STOPS ////////////////////////////////////////////////////////////////////////////////////////////////////////
			$Ymm = $this->stats['Ymm'] + 0.5*$LS;

			$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "Stop(s): ", true, "#EAEAEA");

			$numberOfStops = $segmentObject->stopCounts;
			if ($numberOfStops) {
				$stopLocations = [];

				if ($segmentObject->stopLocations) {
					foreach ($segmentObject->stopLocations as $place) {
						$stationObject = $place->station;
						if ($stationObject) {
							$matchedStationCode = $stationObject->getMatchedId($idExternalSystem);
							if ($matchedStationCode) {
								$airportStopName = \Entity\Station::select($matchedStationCode)->name;
							}
							else {
								$airportStopName = $stationObject->code3;
							}
						}

						$stopLocations[] = $airportStopName;
					}
					if ($stopLocations) {
						$numberOfStops.= " (".implode(", ", $stopLocations).")";
					}
				}
			}

			$output = $this->renderText($output, $Ymm, $XmmColumn2, $numberOfStops, false);

			// HORIZONTAL GREY LINE
			$output = $this->renderHorizontalLine($output, $this->stats['Ymm'] + $LS, 0.2, '#BFBFBF');


			// BAGGAGE ALLOWANCE /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$Ymm = $this->stats['Ymm'] + 0.5*$LS;
			$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "Baggage allowance:", true, "#EAEAEA");
			$baggageCode = $segmentObject->baggageCode;
			if (!$baggageCode) {
				$baggageCode = 'not available';
			}
			$output = $this->renderText($output, $Ymm, $XmmColumn2, sprintf("%s", $baggageCode), false);

			// SPECIAL REQUEST ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$ssrRecords = (array)$segmentObject->ssrRecords;
			$allowedSSRCategories = ["MEAL", "DISABLED", "OTHERS"];
			$specialRequests = [];
			foreach ($ssrRecords as $ssrRecord) {
				if (in_array($ssrRecord->category, $allowedSSRCategories)) {
					$specialRequests[] = $ssrRecord->description;
				}
			}

			if ($specialRequests) {
				$Ymm = $this->stats['Ymm'] + 0.5*$LS;
				$specialRequestHmm = count($specialRequests) * ($em+0.8*$LS);
				$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], $specialRequestHmm, "Special request:", true, "#EAEAEA");

				$requestCoordYmm = $Ymm;
				foreach ($specialRequests as $specialRequest) {
					$output = $this->renderText($output, $requestCoordYmm, $XmmColumn2, $specialRequest, false);
					$requestCoordYmm += $em+0.8*$LS;
				}
			}

			// SERVICE CLASS ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$Ymm = $this->stats['Ymm'] + 0.5*$LS;
			$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "Class:", true, "#EAEAEA");
			$serviceClassName = strtoupper($segmentObject->className);
			if ($segmentObject->classCode) {
				$serviceClassName .= " (".$segmentObject->classCode.")";
			}
			$output = $this->renderText($output, $Ymm, $XmmColumn2, $serviceClassName, false);

			// ON BOARD /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$Ymm = $this->stats['Ymm'] + 0.5*$LS;
			$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "On board:", true, "#EAEAEA");
			$mealDescription = $segmentObject->mealDescription;

			if (!$mealDescription) {
				$mealDescription = $segmentObject->mealCode;
			}

			if (!$mealDescription) {
				$mealDescription = 'not available';
			}

			$output = $this->renderText($output, $Ymm, $XmmColumn2, $mealDescription, false);

			// SEAT NUMBER //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			$seatNumber = $segmentObject->seatNumber;
			if (!$seatNumber) {
				$seatNumber = 'check-in required';
			}

			$Ymm = $this->stats['Ymm'] + 0.5*$LS;
			$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "Seat number:", true, "#EAEAEA");
			$output = $this->renderText($output, $Ymm, $XmmColumn2, sprintf("%s", $seatNumber), false);


			// AIRCRAFT //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			if ($segmentObject->transportUnit) {
				$Ymm = $this->stats['Ymm'] + 0.5*$LS;
				$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "Aircraft:", true, "#EAEAEA");
				$output = $this->renderText($output, $Ymm, $XmmColumn2, sprintf("%s", $segmentObject->transportUnit), false);
			}

			//  AIRLINE RESERVATION CODE///////////////////////////////////////////////////////////////////////////////////////////////////////////////
			if ($segmentObject->supplierRecordLocator) {
				$Ymm = $this->stats['Ymm'] + 0.5*$LS;
				$output = $this->renderTextWithBorder($output, $Ymm, $this->settings['Xmm'], null, "Airline reservation code: ", true, "#EAEAEA");
				$output = $this->renderText($output, $Ymm, $XmmColumn2, sprintf("%s", $segmentObject->supplierRecordLocator), false);
			}

			$this->stats['Ymm']+= 2*$LS;
		}


		// ADD BLOCK TEXT
		$Ymm = $this->stats['Ymm'] + 0.5*$LS;
		$output = $this->renderTextFromInterface($output, $Ymm, $this->settings['Xmm']);

		// if the special object is set as relative, add text element in order to render the object relative with other elements in page
		if ($this->settings['fixed']) {
			$Ymm = $this->stats['Ymm'];
			if ($this->settings['fixed'])  {
				$Ymm-= $this->settings['setting_Ymm'];
			}
			else {
				$Ymm-= $this->settings['Ymm'];
			}
		}

		return $output;
	}

	/**
	 * Get segment general details (departure city name -> arrival city name)
	 * @param \App\ImportedOrder\Itinerary_Segment $segmentObject
	 * @param string $idExternalSystem
	 * @return string
	 */
	protected function getSegmentGeneralDetails(\App\ImportedOrder\Itinerary_Segment $segmentObject, $idExternalSystem)
	{
		$departurePlaceObject = $segmentObject->departurePlace;
		$arrivalPlaceObject = $segmentObject->arrivalPlace;

		$departurePlace = '-';
		$arrivalPlace = '-';

		if ($departurePlaceObject) {
			$stationObject = $departurePlaceObject->station;
			if ($stationObject) {
				$matchedStationCode = $stationObject->getMatchedId($idExternalSystem);
				if ($matchedStationCode) {
					$departurePlace = \Entity\Station::select($matchedStationCode)->city->name;
				}
				else {
					$departurePlace = $stationObject->code3;
				}
			}
		}

		if ($arrivalPlaceObject) {
			$stationObject = $arrivalPlaceObject->station;
			$matchedStationCode = $stationObject->getMatchedId($idExternalSystem);
			if ($matchedStationCode) {
				$arrivalPlace = \Entity\Station::select($matchedStationCode)->city->name;
			}
			else {
				$arrivalPlace = $stationObject->code3;
			}
		}

		return sprintf("From %s to %s", strtoupper($departurePlace), strtoupper($arrivalPlace));
	}

	protected function getDepartureCityAndStation(\App\ImportedOrder\Itinerary_Segment $segmentObject, $idExternalSystem)
	{
		$departurePlaceObject = $segmentObject->departurePlace;
		$cityName = '-';
		$stationName = '-';

		if ($departurePlaceObject) {
			$stationObject = $departurePlaceObject->station;
			$matchedStationCode = $stationObject->getMatchedId($idExternalSystem);
			if ($matchedStationCode) {
				$stationEntity = \Entity\Station::select($matchedStationCode);
				$stationName = $stationEntity->name;
				$cityName = $stationEntity->city->name;
			}
			else {
				$stationName = $stationObject->code3;
			}
		}

		return sprintf("%s %s", $cityName, $stationName);
	}

	protected function getArrivalCityAndStation(\App\ImportedOrder\Itinerary_Segment $segmentObject, $idExternalSystem)
	{
		$arrivalPlaceObject = $segmentObject->arrivalPlace;
		$cityName = '-';
		$stationName = '-';

		if ($arrivalPlaceObject) {
			$stationObject = $arrivalPlaceObject->station;
			$matchedStationCode = $stationObject->getMatchedId($idExternalSystem);
			if ($matchedStationCode) {
				$stationEntity = \Entity\Station::select($matchedStationCode);
				$stationName = $stationEntity->name;
				$cityName = $stationEntity->city->name;
			}
			else {
				$stationName = $stationObject->code3;
			}
		}

		return sprintf("%s %s", $cityName, $stationName);
	}

	/**
	 * Render horizontal line
	 * @param array $output
	 * @param string $Ymm
	 * @param string $Hmm
	 * @param string $color
	 * @return array
	 */
	protected function renderHorizontalLine(array $output, $Ymm, $Hmm, $color)
	{
		$attributes['attributes'] = [
			'Xmm' => 			$this->settings['Xmm'],
			'Ymm' => 			$Ymm,
			'Wmm' => 			$this->settings['setting_Wmm'],
			'Hmm' => 			$Hmm,
			'fixed' => 			false, // this special object cannot be set as `fixed`
			'block'=>  			false,
			//	'orderIndex'=>$child->attributes['orderIndex'],
			'opacity'=> 		'100',
			'color' => 			$color,
			'border_top' =>		false,
			'border_bottom' =>	false,
			'border_left' =>	false,
			'border_right' =>	false,
			'padding_top' =>	0,
			'padding_bottom' =>	0,
			'padding_left' =>	0,
			'padding_right' =>	0,
			'margin_top' =>		0,
			'margin_left' =>	0,
			'margin_bottom' =>	0,
			'margin_right' =>	0,
			'style' =>			'solid',
			'layer' => 			$this->attributes['layer'],
		];

		$this->stats['Ymm'] = $Ymm + $Hmm;

		$horizontalLineObject = new \DTMControl_horizontalLine($attributes);

		$output[] = $horizontalLineObject->exportAsControl();

		return $output;
	}

	/**
	 * Render text object
	 * @param array $output
	 * @param string $Ymm
	 * @param string $text
	 * @return array
	 */
	protected function renderText(array $output, $Ymm, $Xmm, $text, $textBold=true)
	{
		$borderColor = "#FFFFFF";
		$borderTop = false;
		$borderBottom = false;
		$borderLeft = false;
		$borderRight = false;

		if ($this->debug) {
			$borderColor = "#000000";
			$borderTop = true;
			$borderBottom = true;
			$borderLeft = true;
			$borderRight = true;
		}

		// create DTM text
		$attributes['attributes'] = [
			'text' => 			$text,
			'Xmm' => 			$Xmm,
			'Ymm' => 			$Ymm,
			//	'Wmm'=>75,
			//	'Hmm'=>10,
			'fixed' => 			false,
			'block'=>  			false,
			'opacity'=> 		'100',
			'color' => 			'#000000',
			'fontFamily' =>		$this->settings['setting_fontFamily'],
			'fontSize' => 		$this->settings['setting_fontSize'],
			'style_bold' =>		$textBold,
			'borderColor' =>	$borderColor,
			'border_top' =>		$borderTop,
			'border_bottom' =>	$borderBottom,
			'border_left' =>	$borderLeft,
			'border_right' =>	$borderRight,
			'padding_top' =>	0,
			'padding_bottom' =>	0,
			'padding_left' =>	0,
			'padding_right' =>	0,
			'margin_top' =>		0,
			'margin_left' =>	0,
			'margin_bottom' =>	0,
			'margin_right' =>	0,
			'layer' => 			$this->attributes['layer'],
		];

		$this->stats['Ymm'] = $Ymm + $this->stats['em'] + $this->stats['LS'];

		$textObject = new \DTMControl_text($attributes);

		$output[] = $textObject->exportAsControl();

		return $output;
	}

	protected function renderTextWithBorder(array $output, $Ymm, $Xmm, $Hmm, $text, $textBold, $borderColor)
	{

		$borderTop = false;
		$borderLeft = false;

		if ($this->debug) {
			$borderTop = true;
			$borderLeft = true;
		}

		// create DTM text
		$attributes['attributes'] = [
			'text' => 			$text,
			'Xmm' => 			$Xmm,
			'Ymm' => 			$Ymm,
			'Wmm'=>				$this->WmmColumn1,
			'Hmm'=> 			$Hmm,
			'fixed' => 			false,
			'block'=>  			false,
			'opacity'=> 		'100',
			'color' => 			'#000000',
			'fontFamily' =>		$this->settings['setting_fontFamily'],
			'fontSize' => 		$this->settings['setting_fontSize'],
			'style_bold' =>		$textBold,
			'borderColor' =>	$borderColor,
			'border_top' =>		$borderTop,
			'border_bottom' =>	0.2,
			'border_left' =>	$borderLeft,
			'border_right' =>	0.2,
			'padding_top' =>	0,
			'padding_bottom' =>	0,
			'padding_left' =>	0,
			'padding_right' =>	0,
			'margin_top' =>		0,
			'margin_left' =>	0,
			'margin_bottom' =>	0,
			'margin_right' =>	0,
			'layer' => 			$this->attributes['layer'],
		];

		$this->stats['Ymm'] = $Ymm + $this->stats['em'] + $this->stats['LS'];

		$textObject = new \DTMControl_text($attributes);

		$output[] = $textObject->exportAsControl();

		return $output;
	}


	/**
	 * Render text input with information from interface
	 */
	protected function renderTextFromInterface($output, $Ymm, $Xmm)
	{
		$borderColor = "#FFFFFF";
		$borderTop = false;
		$borderBottom = false;
		$borderLeft = false;
		$borderRight = false;

		if ($this->debug) {
			$borderColor = "#000000";
			$borderTop = true;
			$borderBottom = true;
			$borderLeft = true;
			$borderRight = true;
		}

		$pgH = 280; // A4 page height
		$remainingYmmUntilNewPage = ($pgH - (round($Ymm) % $pgH));
		$lineHeight = ($this->stats['em'] + $this->stats['LS']);

		$remainingLines = ceil($remainingYmmUntilNewPage/$lineHeight);
		$remainingLinesHeight = $remainingLines*$lineHeight;

		$attributes['attributes'] = [
				'Xmm' => 			$Xmm,
				'text' => 			$this->settings['column_column1Text'],
				'align' =>			$this->settings['column_column1Alignment'],
				//	'Hmm'=>10,
				'fixed' => 			true,
				'block'=>  			true,

				'orderIndex'=>      $this->settings['orderIndex'],

				'opacity'=> 		'100',
				'color' => 			$this->settings['column_column1TextColor'],
				'backgroundColor' => $this->settings['column_column1BackgroundColor'],
				'fontFamily' =>		$this->settings['column_column1Font'],
				'fontSize' => 		$this->settings['column_column1FontSize'],
				'style_bold' =>		(bool)$this->settings['column_column1TextStyle']['bold'],
				'style_italic' =>	(bool)$this->settings['column_column1TextStyle']['italic'],
				'style_underline'=>	(bool)$this->settings['column_column1TextStyle']['underline'],
				'padding_top' =>	0,
				'padding_bottom' =>	0,
				'padding_left' =>	$this->settings['column_column1InternalMarginLeft'],
				'padding_right' =>	$this->settings['column_column1InternalMarginRight'],
				'margin_left' =>	0,
				'margin_bottom' =>	0,
				'margin_right' =>	0,

				'borderColor' =>	$borderColor,
				'border_top' =>		$borderTop,
				'border_bottom' =>	$borderBottom,
				'border_left' =>	$borderLeft,
				'border_right' =>	$borderRight,
				'layer' => 			4,
		];

		if ($remainingYmmUntilNewPage < $lineHeight) {
			// create DTM text
			$attributes['attributes']['Ymm'] = $Ymm + $remainingLinesHeight; // forces "new page"
			$attributes['attributes']['margin_top'] = 6; // aligns to top of page
		}
		else {
			$attributes['attributes']['Ymm'] = $Ymm;
			$attributes['attributes']['margin_top'] = $pgH - $remainingLinesHeight + $lineHeight + 6; // offset in the current page
		}

		$this->stats['Ymm'] = $Ymm + $this->stats['em'] + $this->stats['LS'];

		$textObject = new \DTMControl_text($attributes);

		$output[] = $textObject->exportAsControl();

		return $output;
	}
}