<?php
/**
 * @class RemoteParamManager 
 * @brief Manage Remote Data Centers via DDServer  
 */

class RemoteParamManager
{ 
	public $Bases, $basesDom;	 	
	protected $baseDom;
	
	protected $center;
	
	public $xmlDom, $xmlName;
	public $baseId, $paramId, $remoteViId, $localInfo, $paramDom, $paramXML;
 
	function __construct() 
	{
		$this->basesDom = new DomDocument("1.0");

		if (!is_dir(RemoteData."/PARAMS"))
				mkdir(RemoteData."/PARAMS", 0775, true);
		chmod(RemoteData."/PARAMS",0775);
				
		if (!is_dir(RemoteData."/PARAMS_INFO"))
				mkdir(RemoteData."/PARAMS_INFO", 0775, true);
		chmod(RemoteData."/PARAMS_INFO",0775);
		
		$this->xmlName = USERWSDIR."RemoteParams.xml";
		$this->xmlDom = new DomDocument("1.0");
		
	}

	public function init() {
	
		if (!file_exists(RemoteData."Bases.xml"))
				return array("err" => "No Remote Data Bases");
				
		if (!$this->basesDom->load(RemoteData."Bases.xml"))
				return array("err" => "Can not load Remote Data Bases definitions");
		
		$bases = $this->basesDom->getElementsByTagName('dataCenter');
		
		foreach ($bases as $base) 
			$this->Bases[] = $base->getAttribute('xml:id');
			
		if (!file_exists(USERWSDIR."RemoteParams.xml"))
				return array("err" => "RemoteParams file error");
				
		if (!$this->xmlDom->load($this->xmlName))
			return array("err" => "RemoteParams file error");
		
		return array("success" => true);
	}
	
	/*
	*  get baseId from parameter descriptor
	*/
	protected function setBaseId($id) 
	{ 
		foreach ($this->Bases as $base) {
			// Special Themis case
			if (substr($id,0,2) == "th") {
				$baseId = "THEMIS";
				break;
			}
			if (strncmp($id, $base, strlen($base)) === 0) 
			{
				$baseId = $base;
				break;
			}
		}
		
		$this->center = new $baseId(); 	
	}
	
// <param xml:id="imf">
//   <info>
//     <name>imf</name>
//     <short_name>b_gse</short_name>
//     <components>bx,by,bz</components>
//     <units>nT</units>
//     <coordinates_system>GSE</coordinates_system>
//     <tensor_order/>
//     <si_conversion>1e-9&gt;T</si_conversion>
//     <fill_value>-1.0E31</fill_value>
//     <ucd>phys.magField</ucd>
//     <dataset_id>ace-imf-all</dataset_id>
//     <instrument_id>ACE_MAG</instrument_id>
//   </info>
//   <get>
//      <vi name="ace:imf:all">
//         <baseParam name="IMF"/>
//     </vi>
//   </get>
//   <process/>
//   <output/>
// </param>

	public function makeInternalParamXml($isSpectra)
	{
		if (!$this->center->ViId) return false;
		if (!$this->center->ParamId) return false;
		
	//	$this->paramId = strtolower($this->center->baseID."_".$this->center->ViId."_".$this->center->ParamId);

		$xmlNameRemote = RemoteData."/PARAMS/".$this->paramId.".xml";
		$xmlNameTemp = PARAMS_LOCALDB_DIR."/".$this->paramId.".xml";
		
		if (file_exists($xmlNameTemp)) {
			return true;
		}
			
		if (file_exists($xmlNameRemote)) {
			return copy($xmlNameRemote, $xmlNameTemp);
		}
		if (!$this->center->checkParamIsReal())
            return false;
         
		$xml = new DomDocument("1.0");
		$paramNode = $xml->createElement("param");
		$xml->appendChild($paramNode);
    
		$paramNode->setAttribute("xml:id", $this->paramId);
		
		$infoNode = $xml->createElement("info");
		$infoNode->appendChild($xml->createElement("name",strtolower($this->center->ParamId)));
		$infoNode->appendChild($xml->createElement("short_name",strtolower($this->center->ParamId)));
		
		$size = $this->center->getParamSize();
		//TODO spectra components 

		if ($size > 1 && !$isSpectra) 
		{	
			$components = strtolower($this->center->getParamComponents());	
		}
		else {
			$components = null;
		}
		
		$fillValue = $this->center->getParamFillValue();
		
		if (!$fillValue) 
				$fillValue = null;
				
		if ($components)
            $infoNode->appendChild($xml->createElement("components",$components));
            
		$infoNode->appendChild($xml->createElement("units",$this->center->getParamUnits()));
		$infoNode->appendChild($xml->createElement("coordinates_system"));
		$infoNode->appendChild($xml->createElement("tensor_order"));
		$infoNode->appendChild($xml->createElement("si_conversion"));
		$infoNode->appendChild($xml->createElement("fill_value", $fillValue));
		$infoNode->appendChild($xml->createElement("ucd"));
		$infoNode->appendChild($xml->createElement("dataset_id",strtolower($this->center->ViId)));
		$infoNode->appendChild($xml->createElement("instrument_id",strtolower($this->center->baseID." ".$this->center->ViId)));
		
		$getNode = $xml->createElement("get");
		$viNode = $xml->createElement("vi");
		$baseParamNode = $xml->createElement("baseParam");
		$baseParamNode->setAttribute("name", $this->center->ParamId);
		$viNode->setAttribute("name", strtolower(strtr($this->center->ViId,"_", ":")));
		$viNode->appendChild($baseParamNode);
		$getNode->appendChild($viNode);
		
		$paramNode->appendChild($infoNode);
		$paramNode->appendChild($getNode);
		$paramNode->appendChild($xml->createElement("process"));
		$output = $xml->createElement("output");
	
		if ($isSpectra) {
            $output->appendChild($this->makeSpectraNode($xml));                        
        }  
     	
		$paramNode->appendChild($output);
		 
		$res = $xml->save($xmlNameRemote);

		if ($res) 
				return copy($xmlNameRemote, $xmlNameTemp);
		
		return $res;
	}
	
	protected function makeSpectraNode($xml)
 	{
        $yAxis = $xml->createElement("yAxis"); 
        $digitalAxis = $xml->createElement("digitalAxis");
        $digitalAxis->setAttribute('id',"y-left");
//     $digitalAxis->setAttribute('scale',"logarithmic");
        $yAxis->appendChild($digitalAxis);
        
        $zAxis = $xml->createElement("zAxis"); 
        $colorAxis = $xml->createElement("colorAxis");
        $colorAxis->setAttribute('colorMapIndex',"1");
        $colorAxis->setAttribute('scale',"logarithmic");
        $zAxis->appendChild($colorAxis);
        
        $axes = $xml->createElement("axes");
        $axes->appendChild($yAxis);
        $axes->appendChild($zAxis);
        
        $spectro = $xml->createElement("spectro");
        $spectro->setAttribute('yAxis',"y-left");
        $param = $xml->createElement("param");
        $param->setAttribute('id',$this->paramId);
        $param->appendChild($spectro);
        
        $params = $xml->createElement("params");
        $params->appendChild($param);
        
        $timePlot = $xml->createElement("timePlot");
        $timePlot->appendChild($params);
        $timePlot->appendChild($axes);
        
        $plot = $xml->createElement("plot");
        $plot->appendChild($timePlot);
        
        return $plot;
 	}
 	
	protected function makeOurComponents($node, $size)
 	{
		for ($i = 0; $i < $size; $i++)
		{
			$compNode = $this->xmlDom->createElement("component");			
			$compNode->setAttribute('xml:id',$this->paramId."($i)");		
			$compNode->setAttribute('name',"comp_$i"); // LABEL

			$node->appendChild($compNode);
		}
 	}
 	
	protected function makeComponents($node, $size, $components)
 	{
		$compArray = explode(",",$components);
		
		for ($i = 0; $i < $size; $i++)
		{
			$compNode = $this->xmlDom->createElement("component");			
			$compNode->setAttribute('xml:id',$this->paramId."($i)");		
			$compNode->setAttribute('name',strtolower($compArray[$i])); // LABEL

			$node->appendChild($compNode);
		}
 	}
 	
	protected function addNode($id)
	{
		// Node exists already 
		$this->paramId = strtr(strtolower($id),":","_");
		
		if ($this->xmlDom->getElementById($this->paramId)) return true;

		// Node to be added
		$nodeRemote = $this->center->baseDom->getElementById($id);
		// No such node in base.xml
		 
		if (!$nodeRemote) return false;

		if ($nodeRemote->tagName == 'dataset') 
		{

			$this->center->setViId($nodeRemote->getAttribute('name'));
			$status = $this->center->addViToDD();
			
			if (!$status) return false;
			
			$remoteDatasetInfo = DDSERVICE."/BASE/INFO/bases/".$this->center->baseID."/".$this->center->infoFile; 
			$localDatasetInfo = RemoteData.$this->center->baseID."/".$this->center->infoFile;

			if (!copy($remoteDatasetInfo,$localDatasetInfo)) return false;	
		}			 	

		$node = $this->xmlDom->importNode($nodeRemote);

		if ($nodeRemote->tagName == 'parameter') 
		{
			$this->center->setParamId($nodeRemote->getAttribute('name'));
			$this->center->setViId($nodeRemote->parentNode->getAttribute('name'));
			$this->center->setInfoFile();
            $isSpectra = $this->center->checkIsSpectra();		          
			if (!$this->makeInternalParamXml($isSpectra)) return false;

			if ( (($size = $this->center->getParamSize()) > 1) && !$isSpectra )
			{
                // make components and args
                $components = $this->center->getParamComponents();	
                if ($components == -1) {
                    $this->makeOurComponents($node, $size);
                }
                else {
                    $this->makeComponents($node, $size, $components); // return false;
                }
			}
			
			// convert remote paramID into AMDA paramID			
			$node->setAttribute("xml:id", strtr(strtolower($node->getAttribute("xml:id")), ":","_"));
			if ($isSpectra)
                $node->setAttribute("display_type","spectrogram");
		}
	
		$parentRemote= $nodeRemote->parentNode;		  
		$parentRemoteId = $parentRemote->getAttribute('xml:id');

		$parent = $this->xmlDom->getElementById($parentRemoteId);
		
		if (!$parent) 
		{
			$parent = $this->xmlDom->importNode($parentRemote); 		      
		}
		
		$parent->appendChild($node); 
                 
		$toAddDataCentertToDoc = false;

		while ($parent->tagName != 'dataCenter') 
		{
			$node = $parent;	
			$parentRemote = $parentRemote->parentNode;        
			$parentRemoteId = $parentRemote->getAttribute('xml:id');
			$parent = $this->xmlDom->getElementById($parentRemoteId);

			if (!$parent) 
			{
				if ($parentRemote->tagName == 'dataCenter') 
					$toAddDataCenterToDoc = true;
				$parent = $this->xmlDom->importNode($parentRemote);			   
				$parent->appendChild($node); 		      
			}          		        		     
		}	

		if ($toAddDataCenterToDoc) 
		{
			//TODO if this is necessary ???
			// special bases 'hand-made' descriptions
			$basesDom = new DomDocument("1.0");
			$basesDom -> load(RemoteData.'Bases.xml');
			$theBase = $basesDom->getElementById($parent->getAttribute('xml:id'));

			if ($theBase) $parent -> setAttribute('name', $theBase->getAttribute('name'));
			$this->xmlDom->documentElement->appendChild($parent);
		}
		
		return true;
	}
	
/*
*         PUBLIC FUNCTIONS
*/
	public function saveTree($obj) 
	{	   
		if (count($obj) == 1) 
		{	    
			$id = $obj->id;
			
			if ($id == 'root') return array('res' => 'ok');

			$this->setBaseId($id);
						
			$res = $this->addNode($id);	
			
			if ($res === false) return array("err" => "Cannot add node : $id");
		}
		else 
		{ 
			foreach ($obj as $o) 
			{
				$id = $o->id;	
				
				if ($id == 'root') continue;
				
				if (!$this->baseId) $this->setBaseId($id);				
				
				$res = $this->addNode($id);
				
				if ($res === false) return array("err" => "Cannot add node : $id");

			}
		}

		if (!$this->xmlDom->save($this->xmlName))
			return array("err" => "Cannot save RemoteParams.xml");
			
		return array('res' => 'ok');
	}
	
	public function deleteFromTree($obj) 
	{
		$id = $obj->id;
		$nodeToDelete = $this->xmlDom->getElementById($id);
		
		if (!$nodeToDelete) 
			return array("err" => "No such id : $id");
		
		$tagName = $nodeToDelete->tagName;
		$topTag = "dataCenter"; //"dataRoot";
		
		if ($obj->nodeType && $obj->nodeType == "remoteSimuParam")  // FMI_GUMICS case
				$topTag = "simulationRegion";
		 
		while ( $tagName != $topTag ) // "dataCenter" ?
		{
			$parentNode = $nodeToDelete->parentNode;
			$parentNode->removeChild($nodeToDelete);
			$otherChildren = $parentNode->getElementsByTagName($tagName);
			
			if ( $otherChildren->length > 0 ) 
					break;
					
			 $nodeToDelete = $parentNode;
			 $tagName = $nodeToDelete->tagName;
		}
		$this->xmlDom->save($this->xmlName);

		return array('res'=> $obj->id);
	}
	
	public function getInfoName($datasetId) {
	  
// 	      if ($this->baseId == 'CDAWEB')
// 				return  strtolower($datasetId)."_00000000_v01.cdf";
		return  $datasetId.'.xml';

	}
}
?>