<?php
/**
 * @class SimulationDataCenterClass 
 * @brief  
 * @details
 */
class SimulationDataCenterClass extends RemoteDataCenterClass
{

	protected $paramPrefix = "spase___IMPEX_NumericalOutput_";
	
	protected $impex_pairs = array("/" => "_", ":" => "_", "?" => "_", '+' => "_");
	
	public $alongOrbit = true;	
	
	/*
	 * @brief  init  
	*/	
	protected function getRemoteTree() 
	{	 			
		$this->tree = simplexml_load_file($this->url."/".$this->treeXML);	 
	}
	 
	protected function setDataCenterAttributes()
	 {
		$this->dataCenter->setAttribute('desc', $this->tree->Repository->ResourceHeader->Description.'<br/> ReleaseDate: '.$this->tree->Repository->ResourceHeader->ReleaseDate);
		$this->dataCenter->setAttribute('isSimulation', "true");		
	 }
	 
	 public function init() {}
	 
	 // 1-st level : "Mission" : SimulationModel
	 protected function createMissionNodes() 
	 {	 
		$missionNodes =  array();
		
		foreach ($this->tree->SimulationModel as $sm)
		{			
			$ResourceID = trim($sm->ResourceID);
						
			$simulationModel = $this->domAmda->createElement('simulationModel');

			$simulationModel->setAttribute('xml:id', $sm->ResourceID);
			$simulationModel->setAttribute('name',   $sm->ResourceHeader->ResourceName);
		
		   $simulationModel->setAttribute('desc',   $sm->ResourceHeader->Description.'<br/> ReleaseDate: '.$sm->ResourceHeader->ReleaseDate);					
			$this->setModelHelp($simulationModel,"");
			
			if ($this->tree->SimulationRun->count() > 0)			
			{
				$simulationRegionNodes = $this->createSimulationRegionNodes(trim($simulationModel->getAttribute('xml:id')));
				foreach ( $simulationRegionNodes as $node )
					$simulationModel->appendChild($node);
			}			
			$missionNodes[] = $simulationModel;
	   }
	   
	   return $missionNodes;
	 }
	 
	 protected function setModelHelp($node, $helpFile){}
	 
	 protected function setHelpAttribute($node, $helpFile)
	 {
		$node->setAttribute('att', $helpFile);	  
	 }
	 
	 // 2-nd level : SimulatedRegion of SimulationRun
	 protected function createSimulationRegionNodes($modelId)
	 {
		if (file_exists(DATAPATH.'rank.json')) 
			$cmpArr = json_decode(file_get_contents(DATAPATH.'rank.json'), true);
		else 
			$cmpArr = null;
			
		$simRegions =  array();
		$simulationRegionNodes =  array();
		
		foreach($this->tree->SimulationRun as $sr)
		{
			if (trim($sr->Model->ModelID) == $modelId)
			{
				$simReg = trim($sr->SimulatedRegion);
				if (! in_array($simReg, $simRegions))
				{
					$simRegions[] = $simReg;
					// add SimReg to TargetsSimu.xml
					$this->addSimulatedRegionToTargetsFile($simReg, 
							$sr->SimulationDomain->CoordinateSystem->CoordinateSystemName);
					
					echo '$simRegions =>'.$sr->SimulatedRegion.PHP_EOL;
					$simuRegion=$this->domAmda->createElement('simulationRegion');
					$simuRegion->setAttribute('xml:id', $this->baseID.'_'.$simReg);
					$simuRegion->setAttribute('name', $simReg);
					if (is_array($cmpArr)) 
					{
						$target = explode('.',$simReg);
						$index = $cmpArr[$target[0]];
						if ($index)  
							$simuRegion->setAttribute('rank',$index);
						else 
							$simuRegion->setAttribute('rank', 999);
					}					
					$this->setHelpAttribute($simuRegion, "simu/simu$simReg");										
					$simulationRegionNodes[] = $simuRegion;
				}
			
				$runNode = $this->createSimulationRunNode($sr);
				$this->setSimulationRunNodeDescription($runNode,$sr);
				
				foreach ($simulationRegionNodes as $node) 
				{
					if ($node->getAttribute('xml:id') == $this->baseID.'_'.$simReg) 
					{						
						$node->appendChild($runNode);	
					}
				}	 
			} 
		}			
		return $simulationRegionNodes;
	 }
	 
	 // 3-rd level :  SimulationRun
	protected function createSimulationRunNode($sr)
	{
		//$idSimulationRun =  $sr->ResourceID;
		$runNode = $this->domAmda->createElement('runID');
		$runNode->setAttribute('xml:id', $sr->ResourceID);
		$runNode->setAttribute('name', $sr->ResourceHeader->ResourceName);
		 
		foreach ($this->tree->NumericalOutput as $no)
		{  
		   if (((trim($no->InputResourceID) == $sr->ResourceID) || (trim($no->SimulationRunID) == $sr->ResourceID))
				&& ((trim($no->SimulationProduct) == "3DCubes") || (trim($no->SimulationProduct) == "Spectra")))
				{		
					if (trim($no->SimulationProduct) == "Spectra")
						$isSpectra = true;
					else 
						$isSpectra = false;
					 
					$datasetNode = $this->createDatasetNode($no, $isSpectra);
					$runNode->appendChild($datasetNode);
				}				 
	   }
	   return $runNode;
	 }		 
	
	 // 4-th level :  NumericalOutput (dataset) 
	protected function createDatasetNode($no, $isSpectra = false)
	{
		$dsNode = $this->domAmda->createElement('dataset');
		$dsNode->setAttribute('xml:id', trim($no->ResourceID));
		$dsName = $this->getDatasetName($no);
		$dsNode->setAttribute('name', $dsName);		
	 
		$paramNodes = $this->createParameterNodes($no->Parameter, trim($no->ResourceID), $isSpectra);
		
		foreach ($paramNodes as $node)
		{
			$dsNode->appendChild($node);
		}
		
		// Special case of IPIM
		if ($this->hasAccessUrl)
		{
			$dsNode->setAttribute('accessUrl', $this->getAccessUrl($no));		
			$dsNode->setAttribute('globalStart', $this->getStartTime($no));
			$dsNode->setAttribute('globalStop', $this->getStopTime($no));
			$dsNode->setAttribute('desc', 'TimeRange : '.$this->getStartTime($no)."-".$this->getStopTime($no));
			
		}
		else 
		{
			$dsNode->setAttribute('globalStart', 'depending on mission');
		}
			
		return $dsNode;
	}
    
	protected function getDatasetName($no) 
	{
		if (trim($no->ResourceHeader->ResourceName) != '')
			return trim($no->ResourceHeader->ResourceName);
		else
			return trim($no->ResourceID);     
	}
	
	protected function hasComponents($param)
	{
		if ($param->Particle->Qualifier) 
		{
			return  $param->Particle->Qualifier != "Scalar" && $param->Particle->Qualifier != "Total";
			
		}
		if ($param->Field->Qualifier) 
		{
			return  $param->Field->Qualifier != "Scalar" && $param->Field->Qualifier != "Total";
		}
		
		if (strpos(trim($param->ParameterKey), ',') === false)
			$comps = explode(' ',trim($param->ParameterKey)); 
		else
			$comps = explode(',',trim($param->ParameterKey));		
		 
		return count($comps) > 1;
	}
	
    // 5-th level : Parameters & Components
	protected function createParameterNodes($params, $dsid, $isSpectra = false)
	{
		$paramNodes = array();		
		foreach ($params as $param)
		{
			$paramNode = $this->domAmda->createElement('parameter');
			//$p = trim($sm->ResourceID).'/'.$argumentsParameterKey;
			$id = $this->param2dd($dsid."/".$param->ParameterKey);			  
			$paramNode->setAttribute('xml:id',$id);	
			$paramNode->setAttribute('name', $param->Name);
			$paramNode->setAttribute('desc', 'Units: '.$param->Units);			 
			$paramNode->setAttribute('needsArgs', $this->needsArgs);
			$paramNode->setAttribute('units', $param->Units);	
			
			if (!$isSpectra)
			{
				if ($this->hasComponents($param))
				{
					if (strpos(trim($param->ParameterKey), ',') === false)
						$comps = explode(' ',trim($param->ParameterKey)); 
					else
						$comps = explode(',',trim($param->ParameterKey));
						
					$paramNode->setAttribute('size', count($comps));
					
					foreach ($comps as $comp)
					{
						$compNode = $this->domAmda->createElement('component');
				//		$compNode->setAttribute('xml:id', $id."_".$comp);
						$compNode->setAttribute('xml:id', $this->param2dd($dsid."_".$comp));
						$compNode->setAttribute('name', $comp);
						$compNode->setAttribute('shortName',$comp); 
						$compNode->setAttribute('needsArgs', $this->needsArgs);
						
						$paramNode->appendChild($compNode);
					}
				}
				$paramNode->setAttribute('shortName',$param->ParameterKey);
			}
			else 
			{
				$paramNode->setAttribute('size', $this->getEnergyBinsNumber($param));
				$paramNode->setAttribute('display_type', 'spectrogram');
				$paramNode->setAttribute('isSpectra', true);
				$paramNode->setAttribute('energyRange', 'EnergyRange'); // check if it allways so - should be ! SPASE
				$paramNode->setAttribute('shortName','ParticleFlux');
				$paramNode->setAttribute('energyUnits',$param->Particle->EnergyRange->Units);
			}
			
			$paramNodes[] = $paramNode;
		}
		
		return $paramNodes;
	}
	
	// EnergyBinsNumber
	protected function getEnergyBinsNumber($param)
	{
	  return count($param->Particle->EnergyRange->Bin);	
	}
	
	// Run Description
	protected function getCoordinateSystem($coordSystem)
	{
	   return "<b>Reference Frame :</b><br/>".$coordSystem->CoordinateSystemName.",".$coordSystem->CoordinateRepresentation;	
	} 
	//  
	protected function getRegionBoundaries($domain, $region)
	{	
	   $simReg = explode(".", $region->SimulatedRegion);
	   $desc = "<b><br/>Domain: </b>Units: radius of ".$simReg[0]."<br/>";
		// Recalcul domain from km or m to rad
		$unitsDomain = $domain->Units;

		$spatialDimension = $domain->SpatialDimension;
		$radius = $region->Radius;

		$regionParameterRadius = trim($region->Radius['Units']);	  
		$radiusUnits = trim($domain->Units);	  

		$ValidMinsDom = preg_split ("/\s+/", $domain->ValidMin);
		$ValidMaxsDom = preg_split ("/\s+/",  $domain->ValidMax);
		$coordLabel =  preg_split ("/\s+/",$domain->CoordinatesLabel);
		// Transform Simulation Domain to Martian radius from km & m
		for($j=0; $j< $spatialDimension; $j++)
		{
			if ((strtolower($radiusUnits) == 'km') || (strtolower($radiusUnits)== 'm'))
			{
				if ($regionParameterRadius != $radiusUnits)
				{
					if (strtolower($radiusUnits) == 'km') $radius = ($region->Radius)/1000;
					else $radius = ($region->Radius) * 1000;
				}
				
				$ValidMinsDom[$j] = number_format($ValidMinsDom[$j]/$radius,2);
				$ValidMaxsDom[$j] = number_format($ValidMaxsDom[$j]/$radius,2);
			}
			
			$desc .= $coordLabel[$j]."=[".$ValidMinsDom[$j].', '.$ValidMaxsDom[$j]."]<br/>";

		}		
		return $desc;
	} 
	
	protected function setSimulationRunNodeDescription($runNode,$sr)
	{
	}
	
	protected function getProperties($sr)
	{
	}
	
	protected function addSimulatedRegionToTargetsFile($simReg, $coordName)
	{
	   $TargetsXml = new DomDocument("1.0");
	   $TargetsXml->formatOutput = TRUE;
		$TargetsXml->preserveWhiteSpace = FALSE;
		
		if (file_exists(SimuTargetsXml))
		{
			$TargetsXml->load(SimuTargetsXml);
			$rootElement = $TargetsXml->documentElement;			
		}
		else 
		{
			$rootElement = $TargetsXml->createElement('Targets');
			$TargetsXml->appendChild($rootElement);			
		}
		
		$targetNode = $TargetsXml->getElementById($simReg);
		
		if ($targetNode == null)
		{
		   $simRegMain = explode(".",$simReg);
			$targetNode  = $TargetsXml->createElement("Target", $simReg);	
			$targetNode->setAttribute('CoordName',$coordName);
			$targetNode->setAttribute('TargetMain',$simRegMain[0]);
			$targetNode->setAttribute('xml:id',$simReg);
			$targetNode->setAttribute($this->baseID,true);
			$rootElement->appendChild($targetNode);
		}
		// add Simulation Data Center to existing target
		else 
		{
		  $targetNode = $targetNode->setAttribute($this->baseID,true);		
		}
		
		$TargetsXml->save(SimuTargetsXml);				
	}
	
	public function getFileName($resourceID, $templateArgs, $start)
	{		 				 
			$fileName = strtr($resourceID, $this->impex_pairs); 
			foreach ($templateArgs as $key => $value) 
				$fileName .= "_".$value; 
			
			
			$fileName .= "_".$start.'.xml';
	 	 
		return $fileName;
	}
	
	public function getMask($resourceID, $templateArgs)
	{			
		$fileMask = strtr($resourceID, $this->impex_pairs);
		foreach ($templateArgs as $key => $value) 
			$fileMask .= "_".$value; 
			
			$fileMask .= '*.xml';
			
			return $fileMask;         
	}
	
	public function makeArgumentsList()
	{		
		if (!file_exists(SimuTargetsXml))
			exit('NOT YET!'.PHP_EOL);
			
		if (file_exists($this->templateFile))
			unlink($this->templateFile);	
		
		$TemplatesXml = new DomDocument("1.0");
		$TemplatesXml->formatOutput = TRUE;
		$TemplatesXml->preserveWhiteSpace = FALSE;

		$rootNode = $TemplatesXml->createElement('paramTemplateList');
		$TemplatesXml->appendChild($rootNode);
				
		$TargetsXml = new DomDocument("1.0");
		$TargetsXml->load(SimuTargetsXml);
		$targets = $TargetsXml->getElementsByTagName('Target'); 
		foreach ($targets as $target)
		{		   
			if ($target->hasAttribute($this->baseID))
			{
				echo $target->getAttribute('xml:id').PHP_EOL;
				$paramNode = $TemplatesXml->createElement('paramTemplate');
				$paramNode->setAttribute('paramId',$this->baseID."_".$this->param2dd($target->getAttribute('xml:id')));
				$paramNode->setAttribute('fileName','##orbit##');
				$argsNode = $TemplatesXml->createElement('arguments');
				$paramNode->appendChild($argsNode);
				$specialNodes = $this->createSpecialArgs($TemplatesXml);
				
				foreach ($specialNodes as $specialNode)
						$argsNode->appendChild($specialNode);
				
			   $missionGrps = json_decode(file_get_contents(RemoteData.$target->nodeValue.".json"), true);
			   $node = $TemplatesXml->createElement('argument');
				$node->setAttribute('key', 'url_XYZ');
				$node->setAttribute('name', 'Mission Name');
				$node->setAttribute('type', 'list');
			   foreach ($missionGrps as $grp => $missions)
			   {
					foreach ( $missions as $mission => $datasets)
					{	
						echo 'MISSION: '.$mission.PHP_EOL;
						foreach ($datasets as $dataset => $parameters)
						{
							echo "       ".$dataset.PHP_EOL;
							foreach ($parameters as $param => $value) 							
							{
								$item = $TemplatesXml->createElement('item');
								$item->setAttribute('name', $mission);
								$item->setAttribute('key', $value);
									
								$node->appendChild($item);
							}
						}
					}					
			   }
			  //TODO select default s/c for each target 
			  $node->setAttribute('default', $value);
			  $argsNode->appendChild($node);
			  $rootNode->appendChild($paramNode); 
			}
		}
		$TemplatesXml->save(RemoteData.$this->baseID.'/'.$this->templateFile);
	}
	
	protected function createSpecialArgs($dom = null)
	{					
		return array();
	}	
	
	public function getTableDefinition()
	{
		$res = array();
		$res["tableDefType"] = "SELECT"; 
		$res["channelsDefType"] = "BOUND";
		$res["data"] = array();
		$res["data"]["bound"] = $this->energyTableName;
			
		return $res;	
	}
	
	public function getData($params, $isSpectra = false)
	{
// 	$r = print_r($params,true);
// 	error_log($r,3,'/home/budnik/LOG');
	
		try 
		{
			$client = new SoapClient($this->url."/".$this->WSDL,
			array(
				'wsdl_cache' => 0,
				'trace' => 1,
				'soap_version'=>SOAP_1_2
			));
		}
		catch  (SoapFault $exception) 
		{
			throw new Exception($exception->getMessage()." ".$exception->getTraceAsString());
		}
		
		if ($isSpectra)
			$soapMethod = $this->soapMethodSpectra;
		else
			$soapMethod = $this->soapMethod;
			
		try 
		{
			$file = $client->__soapCall($soapMethod, array($params)); 
		}
		catch  (SoapFault $exception) 
		{
			throw new Exception($exception->getMessage()." ".$exception->getTraceAsString()); 
		} 
		
		return $file;
	}
	
	public function validateStartStop($fileName, $startTime, $stopTime)
	{    
			return array("success" => true, "start" => $startTime, "stop" => $stopTime);
	}
}
?>