<?php
/**
 * @class VOTableMgr
 * @version $Id: VOTableMgr.php 2916 2015-05-19 13:08:33Z elena $ 
 */


//set DEBUG_MODE to TRUE to have some log information in user data dir
define("DEBUG_MODE",FALSE);


class VOTableMgr {
  private  $xml, $xp;
  private $log;
  
  function __construct() 
  {
  	 if (DEBUG_MODE)
  	   $this->log = fopen(USERDATADIR."logVOTable","w");
  }
  
  function addLog($msg)
  {
  	 if (DEBUG_MODE)
  	   fprintf($this->log,$msg);
  }
  
  function load($fileName)
  {
  	 $this->xml =  new DomDocument("1.0");
    if (!$this->xml->load($fileName))
    {
      $this->addLog("Cannot load file ".$fileName."\n");
      return FALSE;
    }

    $this->checkIDAttribute();
    /*if ($this->xml->namespaceURI == '')
    {
    	 $this->addLog("File don't have a namespace defined\n");
      if (!$this->xml->createAttributeNS('http://www.ivoa.net/xml/VOTable/v1.1','xmlns'))
        $this->addLog("Cannot create namespace attribute\n");
    }
      
    $this->addLog($this->xml->namespaceURI."\n");*/
      
    $rootNamespace = $this->xml->lookupNamespaceUri($this->xml->namespaceURI);
    
    $this->xp = new domxpath($this->xml);
    
    $this->xp->registerNameSpace('x', $rootNamespace);
    
    return TRUE;
  }
  
  function isValidSchema()
  {
  	 if (!$this->xml)
  	   return FALSE;
  	   
  	   
  	 //ToDo - BRE - add validation!!
  	 return TRUE;
  	   
  	 if (DEBUG_MODE)
  	   libxml_use_internal_errors(true);
  	   
  	 $vers = $this->getVersion();
  	   
  	 $this->addLog("VOTable version : ".$vers."\n");
  	   
  	 $result = FALSE;
  	 
  	 switch ($vers)
  	 {
  	 	 case '1.2' :
  	 	 	 $result = $this->xml->schemaValidate(XMLPATH.'VOTable-1.2.xsd');
  	 	 case '1.0' :
  	 	 	 $result = $this->xml->schemaValidate(XMLPATH.'VOTable-1.0.xsd');
  	 	 default :
  	 	   $result = $this->xml->schemaValidate(XMLPATH.'VOTable-1.1.xsd');
  	 }
  	 
  	 if (DEBUG_MODE)
  	 {
  	   $errors = libxml_get_errors();
  	   
  	   foreach ($errors as $error) 
  	   {
  	   	 $msg = ''; 
  	   
        switch ($error->level)
        {
          case LIBXML_ERR_WARNING:
            $msg .= ("WARNING ".$error->code.": ");
            break;
          case LIBXML_ERR_ERROR:
            $msg .= ("ERROR ".$error->code.": ");
            break;
          case LIBXML_ERR_FATAL:
            $msg .= ("FATAL ".$error->code.": ");
            break;
        }
        $msg .= ($error->message." - In line : ".$error->line." - Of file : ".$error->file."\n");
        
        $this->addLog($msg);
  	   }
  	   
  	   libxml_use_internal_errors(false);
  	 }
  	 
    return $result;
  }
  
  protected function queryResource()
  {
  	 return "//x:RESOURCE";
  }
  
  protected function queryTable()
  {
  	 return $this->queryResource()."/x:TABLE";
  }
  
  protected function queryDescription()
  {
  	 return $this->queryTable()."/x:DESCRIPTION";
  }
  
  protected function queryFields()
  {
  	 return $this->queryTable()."/x:FIELD";
  }
  
  protected function queryField($field_id)
  {
  	 return $this->queryFields()."[@ID='".$field_id."']";
  }

  protected function queryFieldByName($field_id)
  {
  	 return $this->queryFields()."[@name='".$field_id."']";
  }
  protected function queryFieldDescription($field_id)
  {
  	 return $this->queryField($field_id)."/x:DESCRIPTION";
  }
  
  protected function queryData()
  {
  	 return $this->queryTable()."/x:DATA";
  }
  
  protected function queryTableData()
  {
  	 return $this->queryData()."/x:TABLEDATA";
  }
  
  protected function queryTR()
  {
  	 return $this->queryTableData()."/x:TR";
  }
  
  //
  
  public function getVersion()
  {
  	 if (!$this->xml)
  	 		return '';
  	 $root = $this->xml->documentElement;
  	 
  	 return $root->getAttribute('version');
  }
  
  public function getDescription()
  {
  	 if (!$this->xp)
  	   return '';
  	
  	 $desc = $this->xp->query($this->queryDescription());
  	 
  	 if ($desc->length < 1)
  	   return '';
  	   
  	 return $desc->item(0)->nodeValue;
  }
  
  public function getFirstTR()
  {
  	 if (!$this->xp)
  	   return NULL;
  	
  	 /*$trs = $this->xp->query($this->queryTR()); 
  	 
  	 if ($trs->length < 1)
  	   return NULL;
  	   
  	 return $trs->item(0);*/
  	
  	 $tabledatas = $this->xp->query($this->queryTableData());
  	 
  	 if ($tabledatas->length < 1)
  	   return NULL;
  	   
  	 $tabledata = $tabledatas->item(0);
  	 
  	 $node = $tabledata->firstChild;
  	 
  	 while($node && ($node->nodeType != 1) && ($node->nodeName != "TR"))
      $node = $node->nextSibling;
      
    return $node;
  }
  
  public function getNextTR($tr)
  {
  	 if (!$this->xp)
  	   return NULL;
  	
    while($tr->nextSibling && ($tr->nextSibling->nodeType != 1) && ($node->nodeName != "TR"))
      $tr = $tr->nextSibling;
				return $tr->nextSibling;
  }
  
  public function getTDValueByFieldIndex($tr,$field_index)
  {
  	 if (!$this->xp)
  	   return NULL;
  	
  	 $tds = $tr->getElementsByTagName("TD");
  	 
  	 if (($tds->length < 1) || ($field_index >= $tds->length))
  	   return NULL;
  	   
  	 return $tds->item($field_index)->nodeValue;
  }
  
  protected function isTimeField($field)
  {
    if (!$this->xp)
  	   return FALSE;
  	
  	 return (($field->getAttribute("ucd") == "time.epoch") && ($field->getAttribute("xtype") == "dateTime"));
  }
  
  public function getTimeFieldIndex()
  {
  	 if (!$this->xp)
  	   return -1;
  	
  	 $fields = $this->xp->query($this->queryFields());
  	 
  	 if ($fields->length < 1)
  	   return -1;
  	   
  	 for ($i = 0; $i < $fields->length; $i++)
  	   if ($this->isTimeField($fields->item($i)))
  	     return $i;
  	     
  	 return -1;
  }
  
  protected function getFieldByID($field_id)
  {
  	 if (!$this->xp)
  	   return NULL;
  	
  	 $fields = $this->xp->query($this->queryFields());
  	 
  	 if ($fields->length < 1)
  	   return NULL;
  	  	   
  	 foreach ($fields as $field)
  	   if ($field->getAttribute("ID") == $field_id)
  	     return $field;
  	    
  	 return NULL;
  }

    protected function getFieldByName($field_id)
  {
  	 if (!$this->xp)
  	   return NULL;
  	
  	 $fields = $this->xp->query($this->queryFieldByName($field_id));
  	 
  	 if ($fields->length < 1)
  	   return NULL;
  	   
  	 foreach ($fields as $field)
  	   if ($field->getAttribute("name") == $field_id)
  	     return $field;
  	     
  	 return NULL;
  }

  protected function checkIDAttribute(){

      $fields = $this->xml->getElementsByTagName('FIELD');
      $i = 0;
      foreach ($fields as $field){
	$i++;
	if (!$field->hasAttribute("ID")){
	    $field->setAttribute("ID", "col".$i);
	}
      }
      $this->xml->saveXML();

  }

  public function getFieldIndexByID($field_id)
  {
  	 if (!$this->xp)
  	   return -1;
  	
  	 $fields = $this->xp->query($this->queryFields());
  	 
  	 if ($fields->length < 1)
  	   return -1;
  	   
  	 for ($i = 0; $i < $fields->length; $i++)
  	   if ($fields->item($i)->getAttribute("ID") == $field_id)
  	     return $i;
  	     
  	 return -1;
  }
  
  public function getStartStop() 
  {
  	 if (!$this->xp)
  	   return '0 0';
  	
    $timeIndex = $this->getTimeFieldIndex();
    if ($timeIndex < 0)
      return '0 0';
        		
    $tr = $this->getFirstTR();
        
    if (!$tr)
      return '0 0';
        
    $start = $this->getTDValueByFieldIndex($tr,$timeIndex);
        
    $stop = $start;
    while ($tr)
    {
      $stop = $this->getTDValueByFieldIndex($tr,$timeIndex);
      $tr = $this->getNextTR($tr);
    }
        
    if (!$start)
      $start = 0;
    else
      $start = strtotime($start);
          
    if (!$stop)
      $stop = 0;
    else
      $stop = strtotime($stop);
      
    return $start." ".$stop;  
  }
  
  public function getFieldInfoByID($field_id)
  {
   if (!$this->xp)
  	   return array("id"    => $field_id,
  	                "error" => "No file loaded");
    $field = $this->getFieldByID($field_id);
  	 
  	 if (!$field)
	    $field = $this->getFieldByName($field_id);

  	 if (!$field)
  	   return array("id"    => $field_id,
  	                "error" => "This field doesn't exist");
  	 return $this->getFieldInfo($field);
  }
  	   
  
  public function getFieldInfo($field)
  {
    if (!$this->xp)
      return array("id"    => $field_id,
		  "error" => "No file loaded");
    $description = '';
    $desc = $field->getElementsByTagName("DESCRIPTION");
    if ($desc->length >= 1)
      $description = $desc->item(0)->nodeValue;

    $size = $field->getAttribute("arraysize");
    if ($size == '')
      $size = 1;
    else
      $size = intval($size);

    switch ($field->getAttribute("datatype"))
    {
    	 case "short" :
    	 	 $type = "SHORT";
    	 	 break;
    	 case "int" :
    	 	 $type = "INTEGER";
    	 	 break;
    	 case "long"   :
    	 case "double" :
    	   $type = "DOUBLE";
    	   break;
    	 default :
    		  $type = "FLOAT"; 
    }
	if (!$field->getAttribute("ID"))
	  $id = "col".$n;
	else $id = $field->getAttribute("ID");
      
  	 return array("id"     => $field->getAttribute("ID"),
                 "type"        => $type,
                 "name"        => $field->getAttribute("name"),
                 "ucd"         => $field->getAttribute("ucd"),
                 "unit"        => $field->getAttribute("unit"),
                 "size"        => $size,
                 "description" => $description
                );
  }
  
  public function getFieldsInfo()
  {
   	 if (!$this->xp)
  	   return array("error" => "No file loaded");
  	
    $fields_info = array();
  	
  	 $fields = $this->xp->query($this->queryFields());
  	 
  	 if ($fields->length < 1)
  	   return $fields_info;
  	
    foreach ($fields as $field)
    {
     	if ($this->isTimeField($field))
        continue;
      
      array_push($fields_info,$this->getFieldInfo($field));
    }
        
    return $fields_info;
  }
  
  public function getSamplings() 
  {
  	 if (!$this->xp)
  	   return array("minSampling" => 0,
                   "maxSampling" => 0);
  	
  	 $timeIndex = $this->getTimeFieldIndex();
    if ($timeIndex < 0)
      return array("minSampling" => 0,
                   "maxSampling" => 0);
  	
    $tr = $this->getFirstTR();

    if (!$tr)
      return array("minSampling" => 0,
                   "maxSampling" => 0);

    $prevTime = 0;
    while ($tr)
    {
      $time = $this->getTDValueByFieldIndex($tr,$timeIndex);
        	  
      if ($time)
      {
        $time = strtotime($time);
        if (($prevTime > 0) && ($time-$prevTime > 0))
          $deltaT[$time-$prevTime]++;
        $prevTime = $time;
      }
        	  
      $tr = $this->getNextTR($tr);
    }
        
    $minSampling = +1.e31;
    $maxSampling = 0.0;
        
    foreach ($deltaT as $key => $value) 
    {
     
     if ($value/count($deltaT) < 0.10)
        continue;
       
      if ($key < $minSampling) $minSampling = $key;
      if ($key > $maxSampling) $maxSampling = $key;
    }
      
    return array("minSampling" => $minSampling,
                 "maxSampling" => $maxSampling);
  }
  
  public function args2vector($file, $paramID){

  $argsArr = explode('_', $paramID);

  $dom = new DOMDocument();
  $dom->load($file);
  $fields = $dom->getElementsByTagName('FIELD');
  $table = $dom->getElementsByTagName('TABLE')->item(0);
  $i=0;
  foreach ($fields as $field){
      if ($field->getAttribute('name') == $argsArr[0]){
	$unit = $field->getAttribute('unit');
	$ucd  = $field->getAttribute('ucd');
	$datatype  = $field->getAttribute('datatype');
	$firstTD = $i;
    }
    $i++;
  }
  if ($firstTD > 0){
    $table->removeChild($fields->item($firstTD + 2));
    $table->removeChild($fields->item($firstTD + 1));
    $table->removeChild($fields->item($firstTD));
    
    $i = 0;
    foreach ($fields as $field){
	$i++;
	if (strpos($field->getAttribute('ID'),'col') !== FALSE){ 
	    $field->setAttribute('ID', 'col'.$i);
	    $dom->saveXML();
	}
    }
    
    $group = $dom->createElement('GROUP');
    $group->appendChild(new DOMAttr('ID', 'info_'.$paramID));
    $table->appendChild($group);
    
    $param = $dom->createElement('PARAM');
    $param->appendChild(new DOMAttr('ID', 'components_'.$paramID));
    $param->appendChild(new DOMAttr('name', 'components_'.$paramID));
    $param->appendChild(new DOMAttr('datatype', 'char'));
    $param->appendChild(new DOMAttr('arraysize', '*'));
    $param->appendChild(new DOMAttr('value', $argsArr[0].' '.$argsArr[1].' '.$argsArr[2] ));
    $group->appendChild($param);
    
    $new_field = $dom->createElement('FIELD');
    $new_field->appendChild(new DOMAttr('ID', $paramID));
    $new_field->appendChild(new DOMAttr('name', $paramID));
    $new_field->appendChild(new DOMAttr('datatype', $datatype));
    $new_field->appendChild(new DOMAttr('arraysize', '3'));
    $new_field->appendChild(new DOMAttr('unit', $unit));
    $new_field->appendChild(new DOMAttr('ucd', $ucd));
    $new_field->appendChild(new DOMAttr('ref', 'info_'.$paramID));
    $table->appendChild($new_field);
    
    $trs = $dom->getElementsByTagName('TR');
    foreach($trs as $tr){
      $tds = $tr->getElementsByTagName('TD');
      $value = trim($tds->item($firstTD)->nodeValue).' '.trim($tds->item($firstTD + 1)->nodeValue).' '.trim($tds->item($firstTD + 2)->nodeValue);
      $toRemote  = $tds->item($firstTD);
      $tr->removeChild($toRemote);
       $toRemote = $tds->item($firstTD);
      $tr->removeChild($toRemote);
       $toRemote = $tds->item($firstTD);
      $tr->removeChild($toRemote);
     
      $td = $dom->createElement('TD', $value);
      $tr->appendChild($td);
    }
    
    $dom->save($file);
    }
  }
  
}



?>