<?php

namespace Franzz\Spot;
use Franzz\Objects\PhpObject;
use Franzz\Objects\Db;
use \Settings;

class Project extends PhpObject {

	//Spot Mode
	const MODE_PREVIZ = 'P';
	const MODE_BLOG = 'B';
	const MODE_HISTO = 'H';
	const MODES = array('previz'=>self::MODE_PREVIZ, 'blog'=>self::MODE_BLOG, 'histo'=>self::MODE_HISTO);

	//DB Tables
	const PROJ_TABLE = 'projects';

	/**
	 * Database Handle
	 * @var Db
	 */
	private $oDb;


	private $iProjectId;
	private $sName;
	private $sCodeName;
	private $sMode;
	private $asActive;
	private $asGeo;

	public function __construct(Db &$oDb, $iProjectId=0) {
		parent::__construct(__CLASS__);
		$this->oDb = &$oDb;
		if($iProjectId > 0) $this->setProjectId($iProjectId);
	}

	public function getProjectId() {
		return $this->iProjectId;
	}

	public function setProjectId($iProjectId=0) {
		if($iProjectId > 0) {
			$this->iProjectId = $iProjectId;
		}
		else {
			/**
			 * Project 1		      [-----------------]
			 * Project 2		                                [---------------------------]
			 * Project 3		                                                                      [-----------]
			 * Selected Project	[-------Project 1-------][------------Project 2-------------][---------------Project 3------------------
			 * Mode				--P--][--------B--------][--P--][-----------B---------------][---P---][-----B-----][---------H----------
			 */
			$sQuery =
				"SELECT MAX(id_project) ".
				"FROM projects ".
				"WHERE active_to = (".
					"SELECT MIN(active_to) ".	//Select closest project in the future
					"FROM projects ".
					"WHERE active_to > NOW() ".	//Select Next project
					"OR active_to = (".			//In case there is no next project, select the last one
						"SELECT MAX(active_to) ".
						"FROM projects".
					")".
				")";
			$asResult = $this->oDb->getArrayQuery($sQuery, true);
			$this->iProjectId = array_shift($asResult);
		}

		$this->setProjectInfo();
	}

	public function createProjectId() {
		$this->setProjectId($this->oDb->insertRow(self::PROJ_TABLE, array('codename'=>'')));
		return $this->getProjectId();
	}

	public function getMode() {
		return $this->sMode;
	}

	public function getProjectName() {
		return $this->sName;
	}

	public function setProjectName($sName) {
		return $this->updateField('name', $sName);
	}

	public function getProjectCodeName() {
		return $this->sCodeName;
	}

	public function setProjectCodeName($sCodeName) {
		return $this->updateField('codename', $sCodeName);
	}

	public function getActivePeriod($sFromTo='') {
		return ($sFromTo=='')?$this->asActive:$this->asActive[$sFromTo];
	}

	public function setActivePeriod($oValue, $sFromTo='') {
		if($sFromTo=='') {
			$this->updateField('active_from', $oValue['from']);
			return $this->updateField('active_to', $oValue['to']);
		}
		else {
			return $this->updateField('active_'.$sFromTo, $oValue);
		}
	}

	public function getFeedIds() {
		return $this->oDb->selectColumn(
			Feed::FEED_TABLE,
			Db::getId(Feed::FEED_TABLE),
			array(Db::getId(self::PROJ_TABLE) => $this->getProjectId())
		);
	}

	public function getProjects($iProjectId=0) {
		$bSpecificProj = ($iProjectId > 0);
		$sDefaultProjectCodeName = $this->getProjectCodeName();
		$asInfo = array(
			'select'=> array(
				Db::getId(self::PROJ_TABLE)." AS id",
				'codename',
				'name',
				'latitude',
				'longitude',
				'active_from',
				'active_to',
				"IF(NOW() BETWEEN active_from AND active_to, 1, IF(NOW() < active_from, 0, 2)) AS mode"
			),
			'from'	=> self::PROJ_TABLE,
			'orderBy' => array('active_from' => 'ASC')
		);
		if($bSpecificProj) $asInfo['constraint'] = array(Db::getId(self::PROJ_TABLE)=>$iProjectId);

		$asProjects = $this->oDb->selectRows($asInfo, 'codename');
		foreach($asProjects as $sCodeName=>&$asProject) {
			switch($asProject['mode']) {
				case 0: $asProject['mode'] = self::MODE_PREVIZ; break;
				case 1: $asProject['mode'] = self::MODE_BLOG; break;
				case 2: $asProject['mode'] = self::MODE_HISTO; break;
			}
			$asProject['editable'] = $this->isModeEditable($asProject['mode']);
			$asProject['gpxfilepath'] = Spot::addTimestampToFilePath(Gpx::getFrontendFilePath($sCodeName));
			$asProject['codename'] = $sCodeName;
			$asProject['default'] = ($sCodeName == $sDefaultProjectCodeName);
		}
		return $bSpecificProj?$asProject:$asProjects;
	}

	public function getGeoJson() {
		if($this->sCodeName != '' && !Converter::isGeoJsonValid($this->sCodeName)){
			$aiCenter = Converter::convertToGeoJson($this->sCodeName)['center'];
			$this->oDb->updateRow(self::PROJ_TABLE, $this->iProjectId, ['latitude' => $aiCenter[1], 'longitude' => $aiCenter[0]]);
		}

		return json_decode(file_get_contents(GeoJson::getBackendFilePath($this->sCodeName)), true);
	}

	public function getProject() {
		return $this->getProjects($this->getProjectId());
	}

	public function getLastUpdate(): int {
		$iLastUpdate = INF;

		$asFeedIds = $this->getFeedIds();
		foreach($asFeedIds as $iFeedId) {
			$iLastUpdate = min($iLastUpdate, (new Feed($this->oDb, $iFeedId))->getLastUpdate());
		}

		return $iLastUpdate;
	}

	public function getLastMessageId($asConstraints=array()): int {
		$iLastMsg = 0;

		$asFeedIds = $this->getFeedIds();
		foreach($asFeedIds as $iFeedId) {
			$iLastMsg = max($iLastMsg, (new Feed($this->oDb, $iFeedId))->getLastMessageId($asConstraints));
		}

		return $iLastMsg;
	}

	private function setProjectInfo() {
		if($this->getProjectId() > 0) {
			$asProject = $this->getProject();

			$this->sName = $asProject['name'];
			$this->sCodeName = $asProject['codename'];
			$this->sMode = $asProject['mode'];
			$this->asActive = array('from'=>$asProject['active_from'], 'to'=>$asProject['active_to']);
			$this->asGeo = array(/*'geofile'=>$asProject['geofilepath'], */'gpxfile'=>$asProject['gpxfilepath']);
		}
		else $this->addError('Error while setting project: no project ID');
	}

	private function updateField($sField, $oValue) {
		$bResult = ($this->oDb->updateRow(self::PROJ_TABLE, $this->getProjectId(), array($sField=>$oValue)) > 0);
		$this->setProjectInfo();

		return $bResult;
	}

	public function delete() {
		$asResult = array();
		if($this->getProjectId() > 0) {
			$asFeedIds = $this->getFeedIds();
			foreach($asFeedIds as $iFeedId) {
				$asResult['feed'][] = (new Feed($this->oDb, $iFeedId))->delete();
			}

			$asResult['project'][] = array(
				'id'	=> $this->getProjectId(),
				'del'	=> $this->oDb->deleteRow(self::PROJ_TABLE, $this->getProjectId()),
				'desc'	=> $this->oDb->getLastError()
			);
		}
		else $asResult['project'][] = array('del'=>false, 'desc'=>'Error while setting project: no project ID');

		return $asResult;
	}

	public function isEditable() {
		return self::isModeEditable($this->getMode());
	}

	static public function isModeEditable($sMode) {
		return ($sMode != self::MODE_HISTO);
	}
}
