<?php
/**
 * @class ParamMgr 
 * @version  $Id: ParamMgr.php 1947 2013-11-28 15:10:46Z elena $
 * 
 */

 class ParamMgr {
	  
	   
	  protected $Bases, $basesDom;	 	
	  protected $baseDom;
	  public $xmlDom, $xmlName;
	  public  $baseId, $paramId, $remoteViId, $localInfo, $paramDom, $paramXML;
 
	  function __construct() {
//TODO check if files exist....
	    $this->basesDom = new DomDocument("1.0");
	    $this->basesDom->load(RemoteData.'Bases.xml');
            $bases = $this->basesDom->getElementsByTagName('dataCenter');
	    foreach ($bases as $base) $this->Bases[] = $base->getAttribute('xml:id');
	    
	    $this->xmlName = USERWSDIR.'RemoteParams.xml';
	    $this->xmlDom = new DomDocument("1.0");
	    $this->xmlDom->load($this->xmlName);

	  }

/*
*       
*/
	protected function param2dd($paramID) {
	
	    $pairs = array("%" => "_","\\" => "_","$" => "_",":" => "_","+" =>"_","-" => "_","#" => "_","@" => "_","." => "_", ">" => "_", "<" => "_");    
	    return strtr($paramID,$pairs); 
	  }

/*
*       Make Aliases - Remote data set ID -> DD data set ID (xxxx_xxxx_xxxx)  
*/
	 public function dataset2dd($remVIID) {
            // TODO method of ????  class
      
                $ddVIID = $remVIID;
            return $ddVIID;
	  }

/*
*       get baseId from parameter descriptor
*/
	 protected function setBaseId($id) {
 
	    foreach ($this->Bases as $base) {
// Special Themis case
                if (substr($id,0,2) == "th") {
                      $this->baseId = "THEMIS";
                      break;
                    }
                 if (strncmp($id, $base, strlen($base)) === 0) {
		      $this->baseId = $base;
		      break;
		  }
	    }
 
	    $this->baseDom = new DomDocument("1.0");
	    $this->baseDom->load(RemoteData.$this->baseId.'/base.xml');             
	  }

/*
*       get Info File name
*/
//TODO  not to hardly code special stuff...
	 public function getInfoName($datasetId) {
	  
	      if ($this->baseId == 'CDAWEB')
				return  strtolower($datasetId)."_00000000_v01.cdf";
	      return  $datasetId.'.xml';

	  }

/*
*
*/
	  protected function getDatasetInfo() {

	      $infoFileName = $this->getInfoName($this->remoteViId);
	      $this->localInfo = RemoteData.$this->baseId.'/'.$infoFileName;
	      if (file_exists($this->localInfo)) return true;

// call to DD Server to create new VI
	      $command = OLD_CLASSPATH.'AddVI '.$this->dataset2dd($this->remoteViId).' '.$this->remoteViId.' '.$this->baseId;                
              system($command, $err);

	      $remoteInfo = INFOSITE.'INFO/'.$this->baseId.'/DATASETS/'.$infoFileName;
// Get dataset info from DD Server if it doesn't yet exists locally
//TODO may be not neccessary to copy file? load from URL?
	      $res = copy($remoteInfo, $this->localInfo);	     
              return $res;
	  }

/*
*
*/
	  public function getParamInfo() {
 	
	      if (!$this->localInfo) {
		$infoFileName = $this->getInfoName($this->remoteViId);
		$this->localInfo = RemoteData.$this->baseId.'/'.$infoFileName;
	      }
	      switch ($this->baseId) {
// CDAWEB specific function to parse master CDF - idl
		case 'CDAWEB' :
			  $command = OLD_CLASSPATH.'cdfInfo '.$this->localInfo.'  "'.$this->paramId.'"';
			  $info = exec($command);			                         
		      break;
		case 'VEXGRAZ' :
		case 'MAPSKP' :
			  $info = $this->getInfoSpase();
		      break;		
		default:
	
		}   
	      if ($info == "%-9999") return false;
	      return $info; 
	}

/*
*
*/ 
	  protected function getInfoSpase() {
 
	      $xmlinfo =  new DomDocument("1.0");
	      $xmlinfo->load($this->localInfo); 
	      $mission = $xmlinfo->getElementsByTagName("PARENT_MISSION");
	      $instrument = $xmlinfo->getElementsByTagName("PARENT_INSTRUMENT");
 
	      $xp = new domxpath($xmlinfo);          
	      $param = $xp->query("//PARAM_ID[.='".$this->paramId."']");
	      $paramNode = $param->item(0)->parentNode;
	      if (!$paramNode) return false;

	      $info = "paramID%" . $this->paramId . "&&";
	  // Data Type
	      $tag = $paramNode->getElementsByTagName("DATA_TYPE"); 
	      $value = $tag->item(0)->nodeValue;
		  switch ($value) {
			      case 'FLOAT' : $dataTypeS = '2'; break;
			      case 'DOUBLE': $dataTypeS = '3'; break;
			      case 'INT'   : $dataTypeS = '1'; break;
			      case 'CHAR'  : $dataTypeS = '0'; break;
			      default : $dataTypeS = '2' ;
		    }
	      $info = $info . "DATATYPE%" . $dataTypeS ."&&";
	      $tag = $paramNode->getElementsByTagName("SIZES"); 
	      $value = $tag->item(0)->nodeValue;
	      $info = $info . "DIMENSION%" . $value;
	      $tags=array("PARENT_MISSION", "PARENT_EXPERIMENT", "PARAMETER_SHORT_DESCRIPTION", "FILLVAL", "UNITS","DISPLAY_TYPE", "COORDINATE_SYSTEM", "TENSOR_ORDER_VALUE", "LABEL_I", "FIELDNAM");

	     foreach ($tags as $atag){
		    $tag = $paramNode->getElementsByTagName($atag);
		    $value = $tag->length > 0 ? $tag->item(0)->nodeValue : -9999;  
		    switch ($atag) {
			      case "LABEL_I" : $name = "LABLAXIS"; 
				$val_arr = array();
				for ($j = 0; $j < $tag->length; $j++)
				      $val_arr[$j] = $tag->item($j)->nodeValue;
				$value = implode($val_arr, '$').'$'; break;
			      case "COORDINATE_SYSTEM" : $name = "FRAME"; break;
			      case "TENSOR_ORDER_VALUE" : $name = "TENSOR"; break; 
			      case "PARAMETER_SHORT_DESCRIPTION" : $name = "DESCRIPTOR"; break; 
			      case "PARENT_MISSION" : $name = "SOURCE_NAME";
				  $value = $mission->item(0)->nodeValue;
				break; 
			      case "PARENT_EXPERIMENT" : $name = "DATA_TYPE";
				$value = $instrument->item(0)->nodeValue;
				break;
			      case "FILLVAL": 
				      $value =  $tag->length > 0 ? $tag->item(0)->nodeValue : -1.e31;
				      $name = "FILLVAL";
				break;
			      default: $name = $atag;
			}
		      $info = $info . "&&".$name."%". $value;                  
		    }
   
	  return $info;
      }
/*
* Create XML parameter descriptor in the generic_data/RemoteData/PARAMS dir
*/ 
	  public function createParamXml($infoTotal) {
 
		  $this->paramDom =  new DomDocument("1.0");  
		  $this->paramDom->preserveWhiteSpace = false;
		  $this->paramDom->formatOutput = true;
 		      
			    $param = $this->paramDom->createElement('PARAM');                       
			    $param->appendChild($this->paramDom->createElement("baseID",$this->baseId));
			    $param->appendChild($this->paramDom->createElement("viID",$this->remoteViId));
 				
			      $info = explode("&&",$infoTotal);
			      for ($i = 0; $i < count($info); $i++){
				$attr = explode("%",$info[$i]);
				try {     
				    $param->appendChild($this->paramDom->createElement($attr[0],$attr[1]));
				  }
				catch (Exception $e) {
				    return false;   
				}
			      } 
			      $this->paramDom->appendChild($param);
			      if (!$this->paramDom->save($this->paramXML)) return false;
  
		  return true; // NO ERROR

	  } 

/*
*  special themis case: componets from base.xml
*/
	  public function makeThemisComponents($param) {

	      $sizes = $param->getAttribute('size');
	      if (!$sizes) return true; // scalar


	      $labels = $param->getAttribute('labels');
	      $id = $param->getAttribute('xml:id');
	      $name = $param->getAttribute('name');

	      if (!$labels) {           		   			
		      $param->setAttribute('needsArgs', true);			   
		  return true;
		}

	      $labelArr = explode("$",$labels);                                     		
	      for ($i = 0; $i < count($labelArr); $i++)
		{
			$component = $this->xmlDom->createElement('component');
			$component->setAttribute('xml:id',$id.'('.$i.')');

			$component->setAttribute('name',$labelArr[$i]);
			$param->appendChild($component); 
		}        		    		  
		return true;  

	  }

/*
*
*/
	  public function makeComponents($param) {

		$sizes =  $this->paramDom->getElementsByTagName('DIMENSION')->item(0)->nodeValue;
		$display = strtolower($this->paramDom->getElementsByTagName('DISPLAY_TYPE')->item(0)->nodeValue);
		$units = $this->paramDom->getElementsByTagName('UNITS')->item(0)->nodeValue;
			
		if (!$units  || ($units == "-9999"))  $units = "no"; 
		$param->setAttribute("units", $units);

		if ($sizes == "1") return true; // Scalar - Nothing to do

		$id = $param->getAttribute('xml:id');
		$name = $param->getAttribute('name');
	// Not a Scalar - add components to user tree            
		$labels =  $this->paramDom->getElementsByTagName('LABLAXIS')->item(0)->nodeValue; 
		
	// No labels                        
	 	if (!$labels || ($labels == "$") || (substr($display,0,6) == "spectr")) {           
		    if (!$param->getAttribute('needsArgs')) {			     
		      $param->setAttribute('needsArgs', true);	
                      if (substr($display,0,6) == "spectr")  
                                    $param->setAttribute('display_type', 'spectrogram');   
		    }
		  return true;
		}
        
		$labelArr = explode("$",$labels);                                     		
		    for ($i = 0; $i < count($labelArr)-1; $i++)
		      {
 			      $component = $this->xmlDom->createElement('component');
			      $component->setAttribute('xml:id',$id.'('.$i.')');
			      $component->setAttribute('name',$labelArr[$i]);
			      $param->appendChild($component); 
		      }        		    		  
		return true;  
	      }
/*
*
*/ 
	  protected function addNode($id){

// NODE EXISTS
 
		if ($this->xmlDom->getElementById($id)) return true;
  
// NODE TO BE ADD
		$nodeRemote = $this->baseDom->getElementById($id);
 
		if (!$nodeRemote) return false;

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

				    $this->remoteViId = $nodeRemote->getAttribute('name');
				    $datasetExists = $this->baseId != 'THEMIS' ? $this->getDatasetInfo() : true;
				    if (!$datasetExists) return false;
		  }

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

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

				    $this->paramId = $nodeRemote->getAttribute('name');
				    $this->remoteViId = $nodeRemote->parentNode->getAttribute('name');
 
			 	    $info = $this->baseId != 'THEMIS' ? $this->getParamInfo() : true;
				    if (!$info) return false;
				      				  
				     
 // XML descriptor of the parameter; themis excluded
				    if ($this->baseId == 'THEMIS') {

					if (!$this->makeThemisComponents($node)) return false;
				    }
				    else {

					$paramGlobalId = $this->baseId.":".$this->dataset2dd($this->remoteViId).":".$this->param2dd($this->paramId);  
					$node->setAttribute('xml:id', $paramGlobalId);
					$this->paramXML = RemoteData.'PARAMS/'.$paramGlobalId.'.xml';

					if (!file_exists($this->paramXML) && !$this->createParamXml($info)) return false;
					if (!$this->paramDom) {
					      $this->paramDom = new DomDocument("1.0");
					}
					      $this->paramDom->load($this->paramXML);
					
					if (!$this->makeComponents($node)) return false;
				    }
		   }
 		 
		  $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 neccessary ???
// 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;
		     $this->setBaseId($id);
		     $res = $this->addNode($id);		  
		}
		else { 
		  foreach ($obj as $o) {
		    $id = $o->id;		 
		    if ($id == 'root') continue;
		    if (!$this->baseId) $this->setBaseId($id);	
		    $res = $this->addNode($id);		   		   
		   }
		  }

		$this->xmlDom->save($this->xmlName);
		return array('res' => 'ok');
	  }
	
	  public function deleteFromTree($obj) {
             	    
	     $id = $obj->id;
             $nodeToDelete = $this->xmlDom->getElementById($id);
	     if (!$nodeToDelete) return array('err' => 'NO SUCH ID');
	     $nodeToDelete->parentNode->removeChild($nodeToDelete);
	     
	     $this->xmlDom->save($this->xmlName);
 
	     return array('res'=> $obj->id);
	  }
	
}

?>