<?php
/** 
*   @class ImpexParamManager.php
*   @brief  Simations parameters Manager (Simulations db client) 
* 
*/
  
class ImpexParamManager  
{
	// input parameters
	protected $extraParam, $sampling;
	protected $dataProducer, $argStartTime, $argStopTime;
	protected $parameterID, $resourceID, $parameterKey, $parameterSize;
	protected $vectorList = null, $isSpectra = false;
	
   protected $orbitTempFolder = null;
   protected $center = null;
   
	protected $requestManager = null;
	protected $baseManager = null;
	protected $votManager = null;
	protected $impex_pairs = array("/" => "_", ":" => "_");
	protected $webAlias;
	
	public $startTime, $stopTime;
	
	private $impexParamInfo = null;
	
// 	private $scale = array("km" => 1, "Rme" => 2438, "Rv" => 6052, "Re" => 6371, "Rma" => 3396, "Rm" => 3396,
// 									"Rj" => 71492, "Rs" => 60268, "Ru" => 25559, "Rn" => 24764);

	function __construct() 
	{		
		$this->baseManager= new BaseManager();
		
		date_default_timezone_set('UTC');
		ini_set("soap.wsdl_cache_enabled", "0");
	
		$this->webAlias = webAlias.IHMConfigClass::getRelativeResultPath(); 
	}
 
	public function getImpexFullParamId($param_id, $templateArgs = NULL) {
	
		if (!$templateArgs)
			return $param_id;
		
		$fullParamId = $param_id;
		foreach ($templateArgs as $key => $value)	
			$fullParamId .= "_".$value;
			
		return $fullParamId;
	}
	
	private function initParam($param, $templateArgs = NULL)
	{		
		$this->impexParamInfo = new IHMImpexParamClass();
		
		$this->parameterID = $this->getImpexFullParamId($param, $templateArgs);
		$this->dataProducer = $this->impexParamInfo->getDataProducer($param);
		$this->resourceID = $this->impexParamInfo->getResourceID($param);
		$this->parameterSize = $this->impexParamInfo->getParameterSize($param);
		$this->vectorList = $this->impexParamInfo->getVectorList($this->resourceID);
		$this->isSpectra = $this->impexParamInfo->isSpectra($param);
	}
	
	public function createImpexParameter($param, $intervals, $templateArgs = NULL)
	{	
		$this->initParam($param, $templateArgs);
		$this->parameterKey = $this->impexParamInfo->getParameterKey($param);
		
		if (!$this->center)
			$this->center = new $this->dataProducer();

		$mask = $this->center->getMask($this->resourceID, $templateArgs);
		 
		// if VI exists (i.e. another parameter from this dataset has been already created)
		if ($this->baseManager->existsVi($mask))
		{
			$result = $this->addImpexData($param, $intervals, $templateArgs);
			$viID = $result['VIID'];

			$localFile = $this->baseManager->getFirstFileName($viID);
			
			if ($this->center->outputFormat == "VOTable")
			{
				if (!$this->votManager)
						$this->votManager = new VOTableMgr();
						
				if (!$this->votManager->load(IHMConfigClass::getLocalBasePath().$localFile))
						throw new Exception('Cannot load '.$localFile); 
			}			
		}
		else 
		{
			$start = $intervals[0]->getStart();
			$duration = $intervals[0]->getDuration();
			
			$startTime = CommonClass::DDTimeToIso($start);
			$stopTime = CommonClass::DDStartIntervalToStopIso($start,$duration);
			$this->argStartTime = $startTime;
			$this->argStopTime = $stopTime;
									
			if (is_array($templateArgs))
				$templateArgs = (object) $templateArgs;
				
			if ($templateArgs->url_XYZ)  
			{
				$url_XYZ = $this->getOrbit($startTime, $stopTime, $templateArgs->url_XYZ);	
				$params = $this->makeRequest($templateArgs, $url_XYZ);
			}
			else 
			{
				 $params = $this->makeRequest($templateArgs);
			}
	    	
			$remoteFile = $this->center->getData($params, $this->isSpectra);
			
			$localFile = $this->center->getFileName($this->resourceID, $templateArgs,$start);
				
			if (!copy($remoteFile, IHMConfigClass::getLocalBasePath().$localFile)) {			
				if ($this->orbitTempFolder)
					CommonClass::rrmdir($this->orbitTempFolder);
					
				throw new Exception('Cannot wget '.$remoteFile); 				
			}
			
			if ($this->center->outputFormat == "VOTable")
			{
				if (!$this->votManager)
						$this->votManager = new VOTableMgr();
						
				if (!$this->votManager->load(IHMConfigClass::getLocalBasePath().$localFile))				
				{
					if ($this->orbitTempFolder)
						CommonClass::rrmdir($this->orbitTempFolder);
						
					throw new Exception('Cannot load '.$localFile);
				}
				
				if (!$this->votManager->isData()) 
				{
					unlink(IHMConfigClass::getLocalBasePath().$localFile);
					if ($this->orbitTempFolder)
						CommonClass::rrmdir($this->orbitTempFolder);
						
					throw new Exception('Empty file '.$localFile);					
				}
				
				if ($this->vectorList)
				{
					//TODO if it is needed to reload xml in case of several vectors
					foreach ($this->vectorList as $vector)
					{
						$this->votManager->addVectorToVot($vector,IHMConfigClass::getLocalBasePath().$localFile);
					}
				}
				$viID = $this->addFileToDb($mask, $localFile, $startTime, $stopTime);
			}
			elseif ($this->center->outputFormat == "CDF")
			{
				$viID = $this->addFileToDb($mask, $localFile, $startTime, $stopTime, 'cdf');
			}
			 			
		   if ($this->orbitTempFolder)
				CommonClass::rrmdir($this->orbitTempFolder);
		}
		
		$res = $this->getInfoFromFile($localFile);	

		$res["success"] = true;		
		$res["param"]["id"] = $this->parameterID;
		$res["param"]["dateModif"] = time(); 
		$res["param"]["info"]["viId"] = $viID;
		$res["param"]["info"]["name"] = $this->parameterKey;
		$res["param"]["info"]["yTitle"] =  $this->parameterKey;
		$res["param"]["info"]["units"] = $this->impexParamInfo->getUnits($param);
		
		
		//TODO define in DataCenter Class
		// special info on EnergyRange Table for Spectra : LATMOS, FMI_HYBRID
		if ($this->isSpectra)		
		{
			$res["param"]["info"]["tableDef"] = $this->center->getTableDefinition();
			$res["param"]["info"]["yTitle"] =  $this->center->tableTitle;
			$res["param"]["info"]["yUnits"] = $this->impexParamInfo->getEnergyUnits($param);
		}
		if ($this->dataProducer == "IPIM")		
		{
			$res["param"]["info"]["tableDef"] = $this->center->getTableDefinition(); // ($viID);
			$res["param"]["info"]["yTitle"] = $this->center->energyTableName;
			$res["param"]["info"]["yUnits"] =  'km';
		}
		return $res;
	}
	
	public function addImpexData($param, $intervals, $templateArgs = NULL)
	{
		$this->initParam($param, $templateArgs);
		
		$start = $intervals[0]->getStart();
		$duration = $intervals[0]->getDuration();				 

		if (!$this->center)
			$this->center = new $this->dataProducer();
		
		$mask = $this->center->getMask($this->resourceID, $templateArgs); 
		
		$startStamp = CommonClass::DDTimeToTimeStamp($start);
		$stopStamp = $startStamp + CommonClass::DDTimeToTimeStamp($duration);
		 
		$intervalsToGet = $this->baseManager->intervalsToGet($startStamp, $stopStamp, $mask);
  
		$startT = $intervalsToGet['start'];
		$stopT = $intervalsToGet['stop']; 
		
		if ( is_array($templateArgs) )
				$templateArgs = (object) $templateArgs;
				
		if (count($startT) > 0)
		{
			for ( $i = 0; $i < count($startT); $i++ )
			{
				$startTime = date("Y-m-d\TH:i:s",$startT[$i]);
				$stopTime = date("Y-m-d\TH:i:s",$stopT[$i]);
				
				$this->argStartTime = $startTime;
				$this->argStopTime = $stopTime;
				
				if ($templateArgs->url_XYZ)  
				{
					$url_XYZ = $this->getOrbit($startTime, $stopTime, $templateArgs->url_XYZ);	
					$params = $this->makeRequest($templateArgs, $url_XYZ);
				}
				else 
				{
					$params = $this->makeRequest($templateArgs);
				}			
							
								   				
				$remoteFile = $this->center->getData($params, $this->isSpectra);				
				
				$localFile = $this->center->getFileName($this->resourceID,$templateArgs,$start);
										
				if (!copy($remoteFile, IHMConfigClass::getLocalBasePath().$localFile)) {
					throw new Exception('Cannot wget '.$remoteFile);       
				}
				
				if ($this->center->outputFormat == "VOTable")
				{
					if (!$this->votManager)
						$this->votManager = new VOTableMgr();
					
					if (!$this->votManager->load(IHMConfigClass::getLocalBasePath().$localFile))
						throw new Exception('Cannot load '.$localFile);   
				
					if (!$this->votManager->isData()) 
					{
						unlink(IHMConfigClass::getLocalBasePath().$localFile);
						throw new Exception('Empty file '.$localFile);	
					}
					
					if ($this->vectorList)
					{
						foreach ($this->vectorList as $vector)
						{
							$this->votManager->addVectorToVot($vector,IHMConfigClass::getLocalBasePath().$localFile);
						}
					}
						
					$viID = $this->addFileToDb($mask, $localFile, $startTime, $stopTime);				 	
				}
				else if ($this->center->outputFormat == "CDF")
				{				
					$viID = $this->addFileToDb($mask, $localFile, $startTime, $stopTime, 'cdf');
				}
				
				if ($this->orbitTempFolder)
					CommonClass::rrmdir($this->orbitTempFolder);					
				
			}
		}
		// nothing to add
		else 
		{
			$viID = $this->baseManager->getVI($mask);
		}
		
		$startStop = $this->baseManager->getViDesc($viID);	
		
		$res = array('VIID' => $viID, 'StartStop' => $startStop);
		
		return $res;
	}
		
	private function getInfoFromFile($localFile)
	{
		$res = array();
		$res["param"] = array();
		$res["param"]["info"] = array();
		
		if ($this->center->outputFormat == "VOTable")
		{
			if (!$this->votManager)
				$this->votManager = new VOTableMgr();
				
			// reload xml after adding vector field	
			if (!$this->votManager->load(IHMConfigClass::getLocalBasePath().$localFile))
				throw new Exception('Cannot load '.$localFile);
				
			$infos = $this->votManager->getFieldInfoByID($this->parameterKey);
			$samplings = $this->votManager->getSamplings();	  			 			 			 
			$res["param"]["info"]["realVar"] = $infos["id"];
			$res["param"]["info"]["type"] = $infos["type"];
			$res["param"]["info"]["unit"] = $infos["unit"];
			$res["param"]["info"]["ucd"] = $infos["ucd"];
			$res["param"]["info"]["size"] = $infos["size"];
			$res["param"]["info"]["minSampling"] = $samplings["minSampling"];
			$res["param"]["info"]["maxSampling"] = $samplings["maxSampling"];
			$res["param"]["info"]["plotType"] = "Time Series";
		}
		else if ($this->center->outputFormat == "CDF")
		{		
			$filesMgr = new FilesMgr();
			$filesMgr->setFileName($localFile);
			
			$varInfo = $filesMgr->getCdfVarInfo($this->parameterKey);
		   $varSampling = $filesMgr->getCdfSampling();
		   
			$res["param"]["info"]["realVar"] = $this->parameterKey;
			$res["param"]["info"]["type"] = $varInfo['type'];
			$res["param"]["info"]["minSampling"] = $varSampling[4];
			$res["param"]["info"]["maxSampling"] = $varSampling[4];
			$res["param"]["info"]["plotType"] = "Spectro";
			$res["param"]["info"]["size"] = $varInfo['size'];
		}
		return $res;
	}
      
	private function addFileToDb($maskName, $fileName, $startTime, $stopTime, $format = null)
	{			
		if (!$format)
			$format = "vot";
			
		if (!$this->baseManager->existsVi($maskName))
		{ 			
			$viID = $this->baseManager->addVI($maskName, $format);
		}
		else 
		{
			$viID = $this->baseManager->getVI($maskName);
		}
		
		$start = strtotime($startTime);
		$stop = strtotime($stopTime);
		 
		$mask = $this->baseManager->addFile($fileName, $start, $stop); 
		
		return $viID;
	}
      
	public function getOrbit($startTime, $stopTime, $paramId)
	{
	   $params = array();	   
		$params[] = (object)array("paramid" => $paramId);
	   	   
		$obj = (object)array(
				"nodeType"         => "download",
				"downloadSrc"      => "0",
				"structure"        => 2,
				"refparamSampling" => false,
				"sampling"         => 60,
				"timesrc"          => "Interval",
				"startDate"        => $startTime,
				"stopDate"         => $stopTime,
				"list"             => $params,
				"fileformat"       => "vot",  
				"timeformat"       => "YYYY-MM-DDThh:mm:ss",
				"compression"      => "gzip" ,
				"disablebatch"     => true
		);
		
		if (!isset($this->requestManager))
			$this->requestManager = new RequestManagerClass();
			
		$userID = IHMConfigClass::getUserName();
		$userHost = IHMConfigClass::getUserHost();
		 	   
		try 
		{
			$downloadResult = $this->requestManager->runIHMRequest($userID, $userHost, FunctionTypeEnumClass::PARAMS, $obj);
		} 
		catch (Exception $e) 
		{
			  throw new Exception($e->getMessage());
		} 

		$this->orbitTempFolder = IHMConfigClass::getRequestPath().$downloadResult['folder'];
	  
		try 
		{
		   $this->convertVot($paramId, $downloadResult['result']);
			$orbitURL = $this->webAlias.$downloadResult['folder']."/".$downloadResult['result'].".vot";
					
			return $orbitURL;
		}
		catch (Exception $e) 
		{
			  throw new Exception($e->getMessage());
		}  		
	}
	
	public function makeRequest($templateArgs = null, $url_XYZ = null)
	{ 
		$params = array();
		
		if ($templateArgs)
		{
			$extraParams = array();
			
			foreach ($templateArgs as $key => $value)
			{
				if ($key != 'url_XYZ')
					$extraParams[$key] = $value;
			}
			
			$extraParams['OutputFileType'] = $this->center->outputFormat;
			
			if ($this->center->additionalArgs)
			{
				$args = $this->center->additionalArgs[$this->resourceID];
				foreach ($args as $key => $type)
				{
					if ($key == "StartTime") $params[$key] = $this->argStartTime;
					if ($key == "StopTime") $params[$key] = $this->argStopTime;
					if ($key == "Sampling") $params[$key] = 60;
				}
			}
			
			if ($url_XYZ)
			{
				$params['url_XYZ'] = $url_XYZ;
			}
			 
			$params['extraParams'] = $extraParams;				  
		}
		else 
		{
			$params['accessUrl'] = $this->impexParamInfo->getAccessUrl($this->resourceID);
		}
		
		$params['ResourceID'] = $this->resourceID;
		
		return $params;		 	
	}
	
	private function convertVot($paramID, $fileName)
	{
		$comps = array('x', 'y', 'z');

		$xmlFile = $this->orbitTempFolder."/".$fileName.'.vot';
		
		exec("gunzip ".$xmlFile.".gz");
				
		$dom =  new DomDocument("1.0"); 
		$dom->formatOutput = false;
		$dom->preserveWhiteSpace = false;
		$dom->load($xmlFile);
		$xp = new domxpath($dom);
		
		$fields = $dom->getElementsByTagName('FIELD');
		$table = $dom->getElementsByTagName('TABLE')->item(0);
		$data = $dom->getElementsByTagName('DATA')->item(0);
		
		$i=0;
			
		foreach ($fields as $field)
		{
			if ($field->getAttribute('ID') == $paramID)
			{
				$unit = $field->getAttribute('unit');
				$ucd  = $field->getAttribute('ucd');
				$datatype  = $field->getAttribute('datatype');
				$firstTD = $i;
			}
			$i++;
		}
		//TODO unit from output VOT file
		/*----------------- temporary-----------------*/
// 		  $temp =  new DomDocument("1.0");
// 		  $temp->load(IHMConfigClass::getLocalParamDBPath().$paramID.".xml");
// 		  $unit = $temp->getElementsByTagName('units')->item(0)->nodeValue;
		
		 $unit = 'km';
		/*----------------- temporary-----------------*/
		if ($firstTD > 0)
		{			
			/*if (array_key_exists($unit, $this->scale)) 
				$unitScale = $this->scale[$unit];
			else
				throw new Exception("Undefined unit ".$unit);*/	
			
			$table->removeChild($fields->item($firstTD));
			
			foreach ($comps as $comp)
			{
				$new_field = $dom->createElement('FIELD');
				$new_field->appendChild(new DOMAttr('ID', $comp));
				$new_field->appendChild(new DOMAttr('name', $comp));
				$new_field->appendChild(new DOMAttr('datatype', $datatype));				 
				$new_field->appendChild(new DOMAttr('unit',  $unit)); // $unit
				$new_field->appendChild(new DOMAttr('ucd', 'pos.cartesian.'.$comp));
				
				$table->insertBefore($new_field,$data);
			}
			
			$trs = $dom->getElementsByTagName('TR');
			foreach($trs as $tr)
			{
				$tds = $tr->getElementsByTagName('TD');
				$values = explode(' ',$tds->item($firstTD)->nodeValue);
				$toRemote  = $tds->item($firstTD);
				$tr->removeChild($toRemote);
				
				foreach ($values as $value)
				{
					//$td = $dom->createElement('TD', $value*$unitScale); //3400
					$td = $dom->createElement('TD', $value);
					$tr->appendChild($td);
				}
			}	
				
			$dom->save($xmlFile);
		}
	}
	
	/*
	*  Delete impex params descriptions in User WS dir (and in Plot?)
	*/
	public function deleteImpexParams()
	{
		$dom = new DomDocument("1.0");
		$params = glob(IHMConfigClass::getUserWSPath().IHMImpexParamClass::$paramPrefix.'*.xml');

		$vis = array();
		foreach ($params as $param)
		{
			$dom->load($param);
			$vi = $dom->getElementsByTagName('localvi');
			if ($vi->length == 0) {
			//	throw new Exception('No localVi tag in '.$param);
				continue;
			}
			$viId = $vi->item(0)->getAttribute('id');	
			if (!in_array ($viId, $vis))
				$vis[] = $viId;
	   }
	   
	   foreach ($params as $param)
		{
			unlink($param);
		}
		
		// Delete params in Plot/params
		foreach (glob(IHMConfigClass::getRequestPath().'Plot_/params/'.IHMImpexParamClass::$paramPrefix.'*.xml') as $param)
		{
			unlink($param);
		}
		
	   return $vis;
	}
	
	/*
	*  Delete impex VIs and Files in User DATA dir
	*/
	public function deleteImpexStaff()
	{
		$vis = $this->deleteImpexParams();
		
	   foreach ($vis as $vi)
	   {	   
			$this->baseManager->deleteViTotal($vi);	   
	   }
	}
}