<?php

/**
 * @class TimeTableMgr
 * @version $Id: TimeTableMgr.php 2809 2015-03-05 09:50:52Z natacha $
 * @todo MANAGE TT created by Search and Plot interactive - HERE?
 *
 */

class TimeTableMgr extends AmdaObjectMgr
{
	/**
	 * TimeTableMgr constructor.
	 * @param null $user The user
	 * @param bool $sharedObject Shared object
	 */
	public function __construct($user = null, $sharedObject = false)
	{
		parent::__construct('Tt.xml');
		$this->contentRootId = 'timeTable-treeRootNode';
		$this->contentRootTag = 'timetabList';
		$this->attributes = ['name' => '', 'intervals' => ''];
		$this->optionalAttributes = [];
		$this->objTagName = 'timetab';
		$this->id_prefix = 'tt_';

		if (!$sharedObject && !file_exists($this->xmlName)) {
			$this->createDom();
			$this->xp = new domxpath($this->contentDom);
		}
	}

	protected function createDom()
	{
		$types = ['timetab' => 'timeTable', 'catalog' => 'catalog'];

		$rootElement = $this->contentDom->createElement('ws');

		foreach ($types as $key => $value) {
			$contentId = $value . '-treeRootNode';
			$contentTag = $key . 'List';
			$typeElement = $this->contentDom->createElement($contentTag);
			$typeElement->setAttribute('xml:id', $contentId);
			$rootElement->appendChild($typeElement);
		}
		$this->contentDom->appendChild($rootElement);
		$this->contentDom->save($this->xmlName);
	}

	/**
	 * Get object
	 * @param $id
	 * @param $nodeType
	 * @return array
	 */
	public function getObject($id, $nodeType = null)
	{
		if (substr($nodeType, 0, 6) == 'shared') {
			//Shared object
			$sharedObjMgr = new SharedObjectsMgr();
			$path = $sharedObjMgr->getDataFilePath(str_replace('shared', '', $nodeType), $id);
		} else {
			$path = USERTTDIR . $id . '.xml';
		}

		if (!file_exists($path)) {
			return ['error' => NO_OBJECT_FILE];
		}
		$this->objectDom->load($path);
		if (!($objToGet = $this->objectDom->getElementById($id))) {
			return ['error' => NO_SUCH_ID];
		}
		$attributesToReturn['id'] = $objToGet->getAttribute('xml:id');
		$attributes = $objToGet->childNodes;

		$nbInt = 0;
		foreach ($attributes as $attribute) {
			if ($attribute->nodeType == XML_ELEMENT_NODE) {
				/*if ($attribute->tagName == 'intervals') {
					$start = $attribute -> getElementsByTagName('start')->item(0) -> nodeValue;
					$stop = $attribute -> getElementsByTagName('stop')->item(0) -> nodeValue;
					$attributesToReturn['intervals'][] = array('start' => $start, 'stop' => $stop);
				}
				else
				$attributesToReturn[$attribute->tagName] =  $attribute->nodeValue;*/
				//BRE - load all except intervals - Intervals will be loaded later with 'loadIntervalsFromTT' function
				if ($attribute->tagName != 'intervals') {
					$attributesToReturn[$attribute->tagName] = $attribute->nodeValue;
				} else {
					$nbInt++;
				}
			}
		}
		$attributesToReturn['nbIntervals'] = $nbInt;

		return $attributesToReturn;
	}

	/**
	 * Modify an object
	 * @param $p
	 * @return array
	 */
	public function modifyObject($p)
	{
		$folder = $this->getObjectFolder($p->id);

		//Copy TT in a tempory file
		$ttFilePath = USERTTDIR . $p->id . '.xml';
		$tmpFileExist = false;
		if (file_exists($ttFilePath)) {
			$tmpFileExist = copy($ttFilePath, $ttFilePath . ".tmp");
		}

		//Delete TT
		$this->deleteObject($p);

		//Save modifications
		try {
			$result = $this->createObject($p, $folder);
			if ($result['error']) {
				throw new Exception($result['error']);
			}
			if ($tmpFileExist) {
				unlink($ttFilePath . ".tmp");
			}
			return ['id' => $p->id, 'info' => $result['info']];
		} catch (Exception $exception) {
			//Restore TT file
			if ($tmpFileExist) {
				copy($ttFilePath . ".tmp", $ttFilePath);
				unlink($ttFilePath . ".tmp");
			}
			return ['error' => $exception->getMessage()];
		}
	}

	/**
	 * Create an object
	 * @param $p
	 * @param $folder
	 * @return array
	 */
	public function createObject($p, $folder)
	{
		if ($p->leaf) {
			$result = $this->createParameter($p, $folder);
			if ($result['error']) {
				return $result;
			}
			$cacheMgr = new TimeTableCacheMgr();
			if (isset($p->cacheToken) && ($p->cacheToken != '')) {
				$resultSaveInt = $cacheMgr->saveInTT($result['id'], "update", $p->cacheToken);
				if (!$resultSaveInt['success']) {
					if ($resultSaveInt['message']) {
						return ['error' => $resultSaveInt['message']];
					} else {
						return ['error' => 'Unknown error during intervals save'];
					}
				}
			}
			return $result;
		} else {
			return ['error' => 'createFolder should be called from RENAME'];
			// return $this->createFolder($p);
			// TODO check if this is possible?
		}
	}

	/**
	 * Create parameter (in case of catalogs)
	 * @param $p
	 * @param $folder
	 * @return array
	 */
	protected function createParameter($p, $folder)
	{
		if ($this->objectExistsByName($p->name)) {
			$p->id = $this->getObjectIdByName($p->name);
			$this->deleteObject($p);
		}

		$this->id = $this->setId();
		$this->created = date('Y-m-d\TH:i:s');
		if (!$this->id) {
			return ['error' => ID_CREATION_ERROR];
		}

		$this->resFileName = USERTTDIR . $this->id . '.xml';
		// TODO catalog root element = 'timetable'
		$rootElement = $this->objectDom->createElement('timetable');
		$rootElement->setAttribute('xml:id', $this->id);

		foreach ($p as $key => $value) {
			if ($key != 'id' && $key != 'leaf' && $key != 'nodeType' &&
				$key != 'objName' && $key != 'objFormat' && $key != 'folderId' && $key != 'cacheToken') {
				if ($key == 'created') {
					$rootElement->appendChild($this->objectDom->createElement($key, $this->created));
				} // it is catalog
				else {
					if ($key == 'parameters') {
						$paramsElement = $this->setParamDescription($value);
						if ($paramsElement) {
							$rootElement->appendChild($paramsElement);
						}
					} else {
						if ($key != 'intervals') {
							$rootElement->appendChild($this->objectDom->createElement($key, htmlspecialchars($value)));
						}
					}
				}
			}
		}

		$this->objectDom->appendChild($rootElement);
		$this->objectDom->save($this->resFileName);
		$obj = new stdClass();
		$obj->name = $p->name;
		$obj->intervals = $p->nbIntervals;
		$this->addToContent($obj, $folder);
		// FIXME field created is undefined
		return ['id' => $this->id, 'created' => $this->created, 'info' => $obj->intervals . ' intervals'];
	}

	/**
	 * Set parameter description
	 * TODO
	 * @param $param string The parameter
	 * @return DOMNode
	 */
	protected function setParamDescription($param)
	{
		return new DOMNode();
	}

	/**
	 * Get uploaded object
	 * @param $name
	 * @param $format
	 * @param bool $onlyDescription
	 * @return mixed
	 */
	public function getUploadedObject($name, $format, $onlyDescription = false)
	{
		if (strpos($name, '.txt') !== false || strpos($name, '.asc') !== false || strpos($name, '.') == false) {
			$attributesToReturn = $this->textToAmda(USERTEMPDIR . $name, $onlyDescription);
			$attributesToReturn['objName'] = $name;
			$attributesToReturn['objFormat'] = $format;

			return $attributesToReturn;
		}

		if ($format == 'VOT') {
			$attributesToReturn = $this->vot2amda(USERTEMPDIR . $name, $onlyDescription);
			$attributesToReturn['objName'] = $name;
			$attributesToReturn['objFormat'] = $format;

			return $attributesToReturn;
		}

		if (strpos($name, '.xml') !== false) {
			$temp = explode('.xml', $name);
			$name = $temp[0];
		}

		if (!file_exists(USERTEMPDIR . $name . '.xml')) {
			return ['error' => 'no such name'];
		}

		$this->objectDom->load(USERTEMPDIR . $name . '.xml');
		if (!($objToGet = $this->objectDom->getElementsByTagName('timetable')->item(0)) &&
			!($objToGet = $this->objectDom->getElementsByTagName('TimeTable')->item(0))) {
			return ['error' => 'no time table'];
		}

		$attributes = $objToGet->childNodes;
		$attributesToReturn['name'] = $name;
		$attributesToReturn['objName'] = $name;
		$attributesToReturn['objFormat'] = $format;

		/** @var DOMElement $attribute */
		foreach ($attributes as $attribute) {
			if ($attribute->nodeType == XML_ELEMENT_NODE) {
				if ($attribute->tagName == 'intervals') {
					$start = $attribute->getElementsByTagName('start')->item(0)->nodeValue;
					$stop = $attribute->getElementsByTagName('stop')->item(0)->nodeValue;
					if (!$onlyDescription) {
						$attributesToReturn['intervals'][] = ['start' => $start, 'stop' => $stop];
					}
				} else {
					if ($attribute->tagName == 'Interval') {
						$start = $attribute->getElementsByTagName('Start')->item(0)->nodeValue;
						$stop = $attribute->getElementsByTagName('Stop')->item(0)->nodeValue;
						if (!$onlyDescription) {
							$attributesToReturn['intervals'][] = ['start' => $start, 'stop' => $stop];
						}
					} else {
						switch (strtolower($attribute->tagName)) {
							case 'created':
								$attributesToReturn['created'] = $attribute->nodeValue;
								break;
							case 'chain':
							case 'source':
								$attributesToReturn['description'] = $attribute->nodeValue;
								break;
							default:
								break;
						}
					}
				}
			}
		}
		return $attributesToReturn;
	}

	/*
	* Uploaded text file => convert to array
	*/

	/**
	 * Convert text to AMDA attributes
	 * @param $tmp_file
	 * @param bool $onlyDescription
	 * @return mixed
	 */
	protected function textToAmda($tmp_file, $onlyDescription = false)
	{
		$suffix = explode('.', basename($tmp_file));
		$lines = file($tmp_file, FILE_SKIP_EMPTY_LINES);
		$description = "Uploaded Time Table" . PHP_EOL;

		$recordsNumber = count($lines);
		$descNumber = 0;

		foreach ($lines as $line) {
			$line = trim($line);
			if ($line[0] == '#') { // Comment
				$description = $description . PHP_EOL . substr($line, 1, -1);
			} else {
				$line = preg_replace('/[-:\/T\s]+/', ' ', $line);
				$isoFormat = 'Y-m-dTH:i:s';
				$doyFormat = 'Y z H i s';
				$doyRegex = '(\d{4}) (\d{3}) (\d{2}) (\d{2}) (\d{2})( \d{2})?';

				if (preg_match('/^' . $doyRegex . ' ' . $doyRegex . '$/', $line)) {
					$start = DateTime::createFromFormat($doyFormat, substr($line, 0, 17));
					$stop = DateTime::createFromFormat($doyFormat, substr($line, 18));
					$startDate = $start->sub(new DateInterval('P1D'))->format($isoFormat);
					$stopDate = $stop->sub(new DateInterval('P1D'))->format($isoFormat);
				} else {
					$dateLength = round((strlen($line)-1) / 2);

					$start = explode(' ', substr($line, 0, $dateLength) . ' 00');
					$startTime = strtotime("$start[0]/$start[1]/$start[2] $start[3]:$start[4]:$start[5]");

					$stop = explode(' ', substr($line, $dateLength + 1) . ' 00');
					$stopTime = strtotime("$stop[0]/$stop[1]/$stop[2] $stop[3]:$stop[4]:$stop[5]");
					if (is_numeric($startTime) && is_numeric($stopTime)) {
						$startDate = date($isoFormat, $startTime);
						$stopDate = date($isoFormat, $stopTime);
					} else {
						$description = $description . PHP_EOL . $line;
						$descNumber++;
						continue;
					}
				}

				if (!$onlyDescription) {
					$attributesToReturn['intervals'][] = ['start' => $startDate, 'stop' => $stopDate];
				}
			}
		}
		if ($recordsNumber == $descNumber) {
			$description = 'Looks like we can not read your time format...' . PHP_EOL . $description;
		}

		$attributesToReturn['description'] = $description;
		$attributesToReturn['name'] = basename($tmp_file, '.' . $suffix[1]);
		$attributesToReturn['created'] = date('Y-m-d\TH:i:s');
		return $attributesToReturn;
	}

	/**
	 * Convert VOTable time table to AMDA attributes
	 * @param $tmp_file
	 * @param bool $onlyDescription
	 * @return mixed
	 */
	protected function vot2amda($tmp_file, $onlyDescription = false)
	{
		// Load Time table
		$this->objectDom->load($tmp_file);
		$objToGet = $this->objectDom->getElementsByTagName('TABLEDATA')->item(0);
		$attributesToReturn['name'] = $tmp_file;
		$attributes = $objToGet->childNodes;

		/** @var DOMElement $attribute */
		foreach ($attributes as $attribute) {
			if ($attribute->tagName == 'TR') {
				$start = $attribute->getElementsByTagName('TD')->item(0)->nodeValue;
				$stop = $attribute->getElementsByTagName('TD')->item(1)->nodeValue;
				if (!$onlyDescription) {
					$attributesToReturn['intervals'][] = ['start' => $start, 'stop' => $stop];
				}
			}
		}
		$suffix = explode('.', basename($tmp_file));
		$attributesToReturn['name'] = basename($tmp_file, '.' . $suffix[1]);
		$attributesToReturn['created'] = date('Y-m-d') . "T" . date('H:i:s');
		$description = $this->objectDom->getElementsByTagName('DESCRIPTION')->item(0)->nodeValue;
		$attributesToReturn['description'] = htmlspecialchars($description);
		return ($attributesToReturn);
	}

	/*****************************************************************
	 *                           PUBLIC FUNCTIONS
	 *****************************************************************/

	/*
	 *   Get Object into Edit
	 */
	public function getTmpObject($folderId, $name, $onlyDescription = false)
	{
		$filePath = USERWORKINGDIR . $folderId . '/' . $name . '.xml';
		if (!file_exists($filePath)) {
			return ['error' => 'Cannot find result file'];
		}

		$dom = new DomDocument('1.0');
		$dom->formatOutput = true;

		if (!$dom->load($filePath)) {
			return ['error' => 'Cannot load result file'];
		}

		$descNodes = $dom->getElementsByTagName('description');
		if ($descNodes->length > 0) {
			$attributesToReturn['description'] = $descNodes->item(0)->nodeValue;
		}

		$creatNodes = $dom->getElementsByTagName('created');
		if ($creatNodes->length > 0) {
			$attributesToReturn['created'] = $creatNodes->item(0)->nodeValue;
		}

		$histNodes = $dom->getElementsByTagName('history');
		if ($histNodes->length > 0) {
			$attributesToReturn['history'] = $histNodes->item(0)->nodeValue;
		}

		$attributesToReturn['objName'] = $name;
		$attributesToReturn['folderId'] = $folderId;

		if (!$onlyDescription) {
			$intNodes = $dom->getElementsByTagName('intervals');

			/** @var DOMElement $intNode */
			foreach ($intNodes as $intNode) {
				$startNodes = $intNode->getElementsByTagName('start');
				if ($startNodes->length <= 0) {
					return ['error' => 'Error detected in result file'];
				}
				$stopNodes = $intNode->getElementsByTagName('stop');
				if ($stopNodes->length <= 0) {
					return ['error' => 'Error detected in result file'];
				}
				$attributesToReturn['intervals'][] = [
					'start' => $startNodes->item(0)->nodeValue,
					'stop' => $stopNodes->item(0)->nodeValue
				];
			}
		}

		return $attributesToReturn;
	}

	/**
	 * Merge time tables
	 * @param $obj
	 * @return array
	 */
	public function merge($obj)
	{
		/**
		 * Array of intervals, used like :
		 * [{start:'2010-01-01T23:00:00',stop:'2011-01-01T20:00:00'},{start:'2009-01-01T23:00:00',stop:'2010-01-01T20:00:00'}]
		 * $attributesToReturn['intervals'][] = array('start' => $start, 'stop' => $stop);
		 */

		$intervals = 0;
		for ($iId = 0; $iId < count($obj->ids); $iId++) {
			$table[$iId] = $this->loadIntervalsFromTT($obj->ids[$iId]);
			for ($jId = 0; $jId < count($table[$iId]['intervals']); $jId++) {
				$interval[$iId][$jId][0] = $table[$iId]['intervals'][$jId]['start'];
				$interval[$iId][$jId][1] = $table[$iId]['intervals'][$jId]['stop'];
			}
			$intervals += count($interval[$iId]);
		}
		if ($intervals > 10000) {
			set_time_limit(1800);
		}

		$final = [];
		for ($iId = 0; $iId < count($obj->ids); $iId++) {
			$final = array_merge($final, $interval[$iId]);
		}
		sort($final);

		// Algorithm of union
		$line = 0;
		$iId = 0;
		$val = $final[$iId][0];
		while ($iId < count($final) - 1) {
			if ($final[$iId + 1][1] <= $final[$iId][1]) {
				array_splice($final, $iId + 1, 1);
			} else {
				if (($final[$iId + 1][0] <= $final[$iId][1]) && ($final[$iId + 1][1] >= $final[$iId][1])) {
					$iId++;
				} else {
					$start[$line] = $val;
					$stop[$line] = $final[$iId][1];
					$iId++;
					$line++;
					$val = $final[$iId][0];
				}
			}
		}
		$start[$line] = $val;
		$stop[$line] = $final[$iId][1];

		$objTT = new stdClass();
		$objTT->name = $obj->name;
		$objTT->nodeType = 'timeTable';
		$objTT->leaf = true;
		$objTT->created = null;
		$objTT->history = $obj->history;
		for ($iId = 0; $iId < count($start); $iId++) {
			$inter = new stdClass();
			$inter->start = $start[$iId];
			$inter->stop = $stop[$iId];
			$objTT->intervals[] = $inter;
		}
		$objTT->nbIntervals = count($start);
		$this->objectDom = new DomDocument('1.0');
		$this->objectDom->formatOutput = true;

		$res = $this->createParameter($objTT, $folder); // FIXME $folder is undefined
		if ($res['error']) {
			return $res;
		}

		$this->saveIntervals($res['id'], $objTT->intervals, 'merge');
		return $res;
	}

	/**
	 * Load intervals from time table
	 * @param $id
	 * @param $typeTT
	 * @param null $start
	 * @param null $limit
	 * @return array
	 */
	public function loadIntervalsFromTT($id, $typeTT = '', $start = null, $limit = null)
	{
		if ($typeTT == 'sharedtimeTable') {
			//Shared object
			$sharedObjMgr = new SharedObjectsMgr();
			$path = $sharedObjMgr->getDataFilePath('timeTable', $id);
		} else {
			$path = USERTTDIR . $id . '.xml';
		}

		//load intervals from TT id
		if (!file_exists($path)) {
			return ['success' => false, 'message' => "Cannot find TT file " . $id];
		}

		$this->objectDom->load($path);
		if (!($objToGet = $this->objectDom->getElementById($id))) {
			return ['success' => false, 'message' => NO_SUCH_ID . " " . $id];
		}

		$xpath = new DOMXPath($this->objectDom);
		$intervals = $xpath->query('//intervals');

		$result = [];

		if (!isset($start) || !isset($limit)) {

			/** @var DOMElement $interval */
			foreach ($intervals as $interval) {
				$startTime = $interval->getElementsByTagName('start')->item(0)->nodeValue;
				$stopTime = $interval->getElementsByTagName('stop')->item(0)->nodeValue;
				array_push($result, ['start' => $startTime, 'stop' => $stopTime]);
			}
		} else {
			for ($iInt = 0; $iInt < $limit; ++$iInt) {
				if ($start + $iInt >= $intervals->length) {
					break;
				}
				$startTime = $intervals->item($start + $iInt)->getElementsByTagName('start')->item(0)->nodeValue;
				$stopTime = $intervals->item($start + $iInt)->getElementsByTagName('stop')->item(0)->nodeValue;
				array_push($result, ['start' => $startTime, 'stop' => $stopTime]);
			}
		}

		return [
			'totalCount' => $intervals->length,
			'intervals' => $result,
			'start' => isset($start) ? $start : 0,
			'limit' => isset($limit) ? $limit : 0,
			'success' => true
		];
	}

	/**
	 * Save intervals
	 * @param $id
	 * @param $intervals
	 * @param $action
	 * @return array
	 */
	public function saveIntervals($id, $intervals, $action)
	{
		if (substr($id, 0, 6) == 'shared') {
			return ['success' => false, 'message' => "Cannot save shared TimeTable"];
		} else {
			$path = USERTTDIR . $id . '.xml';
		}
		if (!file_exists($path)) {
			return ['success' => false, 'message' => "Cannot find TT file " . $id];
		}
		$this->objectDom->load($path);

		if (!($objToGet = $this->objectDom->getElementById($id))) {
			return ['success' => false, 'message' => NO_SUCH_ID . " " . $id];
		}

		//remove old intervals
		$crtNode = $objToGet->firstChild;

		while ($crtNode) {
			if (($crtNode->nodeType != XML_ELEMENT_NODE) || ($crtNode->tagName != 'intervals')) {
				$crtNode = $crtNode->nextSibling;
				continue;
			}
			$toRemove = $crtNode;
			$crtNode = $crtNode->nextSibling;
			$objToGet->removeChild($toRemove);
			unset($toRemove);
		}

		//add new intervals
		foreach ($intervals as $interval) {
			$newInterval = $this->createIntervalElement($interval);
			$this->objectDom->documentElement->appendChild($newInterval);
		}

		//save modifications
		$this->id = $id;
		$this->resFileName = USERTTDIR . $this->id . '.xml';
		$this->objectDom->save($this->resFileName);

		unset($this->objectDom);

		return ['success' => true, 'action' => $action, 'nbIntervals' => count($intervals)];
	}

	/**
	 * Create interval element
	 * @param $interval
	 * @return DOMElement
	 */
	protected function createIntervalElement($interval)
	{
		$newInterval = $this->objectDom->createElement('intervals');
		$newInterval->appendChild($this->objectDom->createElement('start', $interval->start));
		$newInterval->appendChild($this->objectDom->createElement('stop', $interval->stop));
		return $newInterval;
	}

	/**
	 * Intersect time tables
	 * @param $obj
	 * @return array|string
	 */
	public function intersect($obj)
	{
		$intervals = 0;
		for ($iId = 0; $iId < count($obj->ids); $iId++) {
			$table[$iId] = $this->loadIntervalsFromTT($obj->ids[$iId]);
			for ($jId = 0; $jId < count($table[$iId]['intervals']); $jId++) {
				$interval[$iId][$jId][0] = $table[$iId]['intervals'][$jId]['start'];
				$interval[$iId][$jId][1] = $table[$iId]['intervals'][$jId]['stop'];
			}
			$intervals += count($interval[$iId]);
		}
		if ($intervals > 10000) {
			set_time_limit(1800);
		}

		// Sort intervals in time tables
		sort($interval[0]);
		sort($interval[1]);

		$iId = 0;
		$jId = 0;
		$line = 0;

		while (($iId < count($interval[0])) && ($jId < count($interval[1]))) {
			$inter = $this->callIntersection($interval[0][$iId], $interval[1][$jId]);

			if ($inter[0][0] != 0 && $inter[0][1] != 0) {
				$start[$line] = $inter[0][0];
				$stop[$line] = $inter[0][1];
				$line++;
			}

			if ($interval[0][$iId][1] < $interval[1][$jId][1]) {
				$iId++;
			} else {
				$jId++;
			}
		}

		// Intersection is empty
		if ($line == 0) {
			$result = "empty";
		} else {
			$objTT->name = $obj->name;  // FIXME $objTT is undefined
			$objTT->nodeType = 'timeTable';
			$objTT->leaf = true;
			$objTT->created = null;
			$objTT->history = $obj->history;
			for ($iId = 0; $iId < count($start); $iId++) {
				$inter = new stdClass();
				$inter->start = $start[$iId];
				$inter->stop = $stop[$iId];
				$objTT->intervals[] = $inter;
			}
			$objTT->nbIntervals = count($start);

			if (count($objTT->intervals) == 0) {
				$result = "empty";
			} else {
				$this->objectDom = new DomDocument('1.0');
				$this->objectDom->formatOutput = true;
				$result = $this->createObject($objTT, $folder); // FIXME $folder is undefined

				if (!isset($result['error'])) {
					$this->saveIntervals($result['id'], $objTT->intervals, 'intersect');
				}
			}
		}
		return $result;
	}

	/**
	 * Call intersection
	 * @param $fst
	 * @param $snd
	 * @return array
	 */
	protected function callIntersection($fst, $snd)
	{
		$inf = ($fst[0] > $snd[0]) ? $fst[0] : $snd[0];
		$sup = ($fst[1] < $snd[1]) ? $fst[1] : $snd[1];
		$inter[] = ($inf >= $sup) ? [0, 0] : [$inf, $sup];
		return $inter;
	}

	/**
	 * Valid name object
	 * TODO getObject only!!!! => change DD_Search output
	 * @param $p
	 * @return array
	 */
	public function validNameObject($p)
	{
		// overwritten
		$res = parent::validNameObject($p);

		if (!$res['valid']) {
			return $res;
		}

		//no space
		if (strpos($p->name, ' ') === false) {
			return ['valid' => true];
		}

		return ['valid' => false, 'error' => 'Space character is not allowed'];
	}

	/**
	 * Copy time table
	 * @param $src_path
	 * @param $dst_path
	 * @param $newId
	 * @param $newName
	 * @param null $newDescription
	 * @return bool
	 */
	public function copyTT($src_path, $dst_path, $newId, $newName, $newDescription = null)
	{
		if (!file_exists($src_path)) {
			return false;
		}

		if (!is_dir($dst_path)) {
			return false;
		}

		$dom = new DomDocument('1.0');
		$dom->formatOutput = true;

		if (!$dom->load($src_path)) {
			return false;
		}

		$timeTableNodes = $dom->getElementsByTagName('timetable');
		if ($timeTableNodes->length <= 0) {
			return false;
		}

		$timeTableNode = $timeTableNodes->item(0);

		$timeTableNode->setAttribute('xml:id', $newId);

		$nameNodes = $timeTableNode->getElementsByTagName('name');

		if ($nameNodes->length <= 0) {
			//create name node (normally never append)
			$nameNode = $dom->createElement('name');
			$timeTableNode->appendChild($nameNode);
		} else {
			$nameNode = $nameNodes->item(0);
		}

		$nameNode->nodeValue = $newName;

		if (isset($newDescription) && !empty($newDescription)) {
			$descriptionNodes = $timeTableNode->getElementsByTagName('description');
			if ($descriptionNodes->length <= 0) {
				//create description node (normally never append)
				$descriptionNode = $dom->createElement('description');
				$timeTableNode->appendChild($descriptionNode);
			} else {
				$descriptionNode = $descriptionNodes->item(0);
			}

			$descriptionNode->nodeValue = $newDescription;
		}

		$dstFilePath = $dst_path . "/" . $newId . ".xml";
		if ($dom->save($dstFilePath) === false) {
			return false;
		}

		chgrp($dstFilePath, APACHE_USER);
		chmod($dstFilePath, 0775);

		return true;
	}

	/**
	 * Rename in resource
	 * @param $name
	 * @param $id
	 * @return bool
	 */
	protected function renameInResource($name, $id)
	{
		if (!file_exists(USERTTDIR . $id . '.xml')) {
			return false;
		}

		$this->objectDom->load(USERTTDIR . $id . '.xml');
		if (!($objToRename = $this->objectDom->getElementById($id))) {
			return false;
		}
		$objToRename->getElementsByTagName('name')->item(0)->nodeValue = $name;
		$this->objectDom->save(USERTTDIR . $id . '.xml');

		return true;
	}

	/**
	 * Delete parameter
	 * @param $id
	 */
	protected function deleteParameter($id)
	{
		if (file_exists(USERTTDIR . $id . '.xml')) {
			unlink(USERTTDIR . $id . '.xml');
		}
	}

	/**
	 * Rename only
	 * @param $p
	 * @return bool
	 */
	protected function renameOnly($p)
	{
		//if (!($p->intervals)) return true;
		return false;
	}
}