<?php
/**
 * @class UserWsTransfer
 */

class UserWsTransfer {  

	private $oldWs, $newWs, $Mgr;
	private $oldWsDir, $newWsDir;
	private $ws_deleted, $wsd_deleted, $pairs, $specParams, $postPairs;
   
	function __construct($user) 
	{  
	   define('OLDUSERPATH', 'http://cdpp1.irap.omp.eu/AMDA-NG/data/');
	  // define('OLDUSERPATH', 'http://amda-dev.irap.omp.eu/~budnik/AMDA-NG4/trunk/data/');
		define('NEWUSERPATH', USERPATH);
		define('TRANSFERUSER', $user);
	   define('CONVERSIONDIR',  DATAPATH."migration/");
		
		$this->oldWs = new DomDocument("1.0");
		$this->newWs = new DomDocument("1.0");
		
		$this->oldWsDir = OLDUSERPATH.TRANSFERUSER.'/WS/';
		$this->newWsDir = NEWUSERPATH.TRANSFERUSER.'/WS/';
		
		if (!is_dir(NEWUSERPATH.TRANSFERUSER.'/WS'))
			mkdir(NEWUSERPATH.TRANSFERUSER.'/WS', 0775);
			
		$this->ws_deleted = array();
		$this->wsd_deleted = array();
		$this->getModified();
		$this->getReprocessed();
		$this->getSpectra();
	}
	
	private function getObsolete() {
	
		$deletedXML = new DomDocument("1.0");
		$deletedXML->load(CONVERSIONDIR."Deleted.xml"); 
		$deletedNodes = $deletedXML->getElementsByTagName('deleted');
		
		$deleted = array();
		foreach ($deletedNodes as $node) 
			$deleted[] = $node->getAttribute('xml:id');

		return $deleted;
	}
	
	private function getNotreadyFunctions() {
	
		$deletedXML = new DomDocument("1.0");
		$deletedXML->load(CONVERSIONDIR."Functions.xml"); 
		$deletedNodes = $deletedXML->getElementsByTagName('deleted');
		
		$notready = array();
		foreach ($deletedNodes as $node)
			$notready[] = $node->getAttribute('xml:id');
		
		return $notready;
	}
	
	private function getNotready() {
	
		$deletedXML = new DomDocument("1.0");
		$deletedXML->load(CONVERSIONDIR."NotReady.xml"); 
		$deletedNodes = $deletedXML->getElementsByTagName('deleted');
		
		$notready = array();
		foreach ($deletedNodes as $node)
			$notready[] = $node->getAttribute('xml:id');
		
		return $notready;
	}
	
	private function deleteParam($exp, $deleted) 
	{
		$toDelete = false;
		 
		if (count($deleted)  > 0)
			foreach ($deleted as $item) {
				if (strpos($exp, $item) !== false)  {
					$toDelete = true;
					break;
				}
			}

		return $toDelete;
	}
	
	private function getWs($exp) 
	{	
		$ws = array();
		
		if (strpos($exp, 'ws_') !== false)  {
			 $arr = $this->delimitIt($exp);
			 foreach ($arr as $item) {
				if (strpos($item, 'ws_') !== false)
						$ws[] = substr($item,3);
			 }
			 return $ws;
		}
		return false;
	}
	
	private function delimitIt($chain) {
       
       $delimiter = '[]+,/*()^<>&|=[-]+';    
       $array = split($delimiter,$chain);
       if (trim(end($array)) == "") array_pop($array);

       return $array;
   }
   
	private function getModified() 
	{
		$convertXML = new DomDocument("1.0");
		$modifiedFile = CONVERSIONDIR.'Modified.xml';
			
		if (!$convertXML->load($modifiedFile)) 
							error_log('ERROR loading '.$modifiedFile,1,email);
		$convertedNodes = $convertXML->getElementsByTagName('param_convert');

		foreach ($convertedNodes as $item) {   
			$pairs[$item->getAttribute('oldid')] = $item->getAttribute('xml:id');
		}    
		krsort($pairs, SORT_NATURAL);
		
		$this->pairs = $pairs;
	}
	
	private function getReprocessed() 
	{
		$convertXML = new DomDocument("1.0");
		$modifiedFile = CONVERSIONDIR.'PostProcess.xml';
			
		if (!$convertXML->load($modifiedFile)) 
							error_log('ERROR loading '.$modifiedFile,1,email);
		$convertedNodes = $convertXML->getElementsByTagName('param_convert');

		foreach ($convertedNodes as $item) {   
			$pairs[$item->getAttribute('oldid')] = $item->getAttribute('xml:id');
		}    
		krsort($pairs, SORT_NATURAL);
		
		$this->postPairs = $pairs;
	}
	
	private function getSpectra() 
	{
		$convertXML = new DomDocument("1.0");
		$modifiedFile = CONVERSIONDIR.'SpectraModifs.xml';
			
		if (!$convertXML->load($modifiedFile)) 
							error_log('ERROR loading '.$modifiedFile,1,email);
		$convertedNodes = $convertXML->getElementsByTagName('deleted');

		foreach ($convertedNodes as $item) {   
			$this->specParams[] = $item->getAttribute('xml:id');
		}    
	}
	
	private function updateParams($expression)
	{
		$newExp = strtr($expression, $this->pairs);
		if (!empty($this->postPairs))
			$expFinal = strtr($newExp, $this->postPairs);
		
		return $expFinal;
	}
	
	
	protected function createDom() 
	{
		$types = array('param' => 'derived', 'mydata' => 'myData');

		$rootElement = $this->newWs->createElement('ws');
		foreach ($types as $key => $value)
		{
			$contentId = $value.'Param-treeRootNode';
			$contentTag = $key.'List';
			$typeElement = $this->newWs->createElement($contentTag);
			$typeElement->setAttribute('xml:id', $contentId);
			$rootElement->appendChild($typeElement);
		}
		
		$this->newWs->appendChild($rootElement);
	   $this->newWs->save($this->newWsDir.'WsParams.xml');
	}
	
	public function urlExists($url) 
	{
		$handle = curl_init($url);
		curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);

		$response = curl_exec($handle);
		$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
		curl_close($handle);

		if($httpCode >= 200 && $httpCode <= 400 || $httpCode == 403) {
			return true;
		} else {
			return false;
		}
	}
		
	public function checkWS() 
	{
		// old ws   
		if (!$this->urlExists(OLDUSERPATH.TRANSFERUSER)) {
				error_log('no  '.TRANSFERUSER.' at old AMDA',1,email);
				return array('success' => false, 'error' => 'Sorry, it seems you have no account at old AMDA');
		}

		if (!$this->urlExists($this->oldWsDir)) {
			error_log('no ws.xml for '.TRANSFERUSER,1,email);
			return array('success' => false, 'error' => 'Sorry, we failed to find your workspace at old AMDA');
		}
		
		return array('success' => true);
	}
	
	public function transferDerived() 
	{
		$msg = '<hr><br/><b><i>Derived Params:</i></b><br/><br/>';
		$msg .= '<i>Note</i> : Parameters made from Remote Base parameters are not copied <br/><br/>';
		if (!$this->oldWs->load($this->oldWsDir.'WsParams.xml')) {
			error_log('cannot load WsParams.xml for '.TRANSFERUSER,1,email);
			return array('success' => false, 'error' => 'Sorry, we failed to get your Derived Params from old AMDA');
		}

		if (!file_exists($this->newWsDir.'WsParams.xml'))
						$this->createDom();
		else 
			$this->newWs->load($this->newWsDir.'WsParams.xml');
		
		$deleted = $this->getObsolete();
	
		$notready = $this->getNotready();
		$notreadyFunctions = $this->getNotreadyFunctions();
		
	   $wsParamNode = $this->newWs->getElementsByTagName('paramList')->item(0);
	   
		$wsParamsOld = $this->oldWs->getElementsByTagName('param');
		
		if ($wsParamsOld->length == 0) {
				return array('success' => true, 'msg' => 'No parameters');
		}
		
		$paramXml = new DomDocument("1.0");
	
		$msg .= 'Some expressions could have problems while being processed by new kernel <br/> - <b>Please send us feedback in this case.</b><br><br>Not copied derived parameters :<br/>';
		
		foreach ($wsParamsOld as $param) {        
			$id = $param->getAttribute('xml:id');
			$name = $param->getAttribute('name');
			
			$expression = $param->getAttribute('buildchain');

			if ($this->deleteParam($expression,$deleted)) {
						$msg .= '<li><i>'.$name.'</i> : uses obsolete param<br/> '.$expression.'<br/>';
					// error_log( 'For INFO : DELETED '.$expression,1,email);
						$this->ws_deleted[] = $name;
						continue;
			}
			 
			if ($this->deleteParam($expression,$notready)) {
						$msg .= '<li><i>'.$name.'</i> : uses param not ready yet <br/> '.$expression.'<br/>';
					// error_log( 'For INFO : DELETED '.$expression,1,email);
						$this->ws_deleted[] = $name;
						continue;
			}
			 
			if ($this->deleteParam($expression,$notreadyFunctions)) {
						$msg .= '<li><i>'.$name.'</i> : uses function not ready yet <br/> '.$expression.'<br/>';
					// error_log( 'For INFO : DELETED '.$expression,1,email);
						$this->ws_deleted[] = $name;
						continue;
			}
			 
			if (!empty($this->wsd_deleted))
					if ($this->deleteParam($expression,$this->wsd_deleted)) {
						$msg .= '<li><i>'.$name.'</i> : uses obsolete myData param<br/> '.$expression.'<br/>';
					// error_log( 'For INFO : DELETED '.$expression,1,email);
						$this->ws_deleted[] = $name;
						continue;
			}
			 
			if ($this->deleteParam($expression,array("CDAWEB","MAPSKP","VEXGRAZ","IMPEX"))) {
						$msg .= '<li><i>'.$name.'</i> : uses remote params <br/> '.$expression.'<br/>';
						$this->ws_deleted[] = $name;
						continue;
			}
			
			if ($this->deleteParam($expression,$this->specParams)) {
						$msg .= '<li><i>'.$name.'</i> : too much difference <br/> '.$expression.'<br/>';
						$this->ws_deleted[] = $name;
						continue;
			}
			 
			$expressionUpdated = $this->updateParams($expression);
  
			$wsParamNode->appendChild($this->newWs->importNode($param));
			
			$paramXml->load($this->oldWsDir.$id.'.xml');
			$expressionNode = $paramXml->getElementsByTagName('buildchain')->item(0);
			$expressionNode->nodeValue = $expressionUpdated;
			$paramXml->save($this->newWsDir.$id.'.xml');
			
			$nodeInWS = $this->newWs->getElementById($id);
			if ($nodeInWS) {
				$buildchain = $nodeInWS->getAttribute('buildchain');
				$buildchainUpdated = $this->updateParams($buildchain);
				
				$nodeInWS->setAttribute('buildchain',$buildchainUpdated);
			}
		}
		
		// check of 'ws bricks' were deleted
		$newParams = $this->newWs->getElementsByTagName('param');
		$xp = new domxpath($this->newWs); 
		$paramsToRemove = array();
		
		foreach ($newParams as $param) {
			$id = $param->getAttribute('xml:id');
			$name = $param->getAttribute('name');
			
			$expression = $param->getAttribute('buildchain');
			if ($wsParams = $this->getWs($expression)) {
				foreach ($wsParams as $wsParam) {
					$res = $xp->query("//param[@name='".trim($wsParam)."']");
					if ($res->length == 0) {
						if (file_exists($this->newWsDir.$id.'.xml')) { // Delete only once
							unlink($this->newWsDir.$id.'.xml');
							$paramsToRemove[] = $param; 
							$this->ws_deleted[] = $name;
							$msg .= '<li><i>'.$name.'</i> : uses obsolete / not ready ws param : <br/> '.$expression.'<br/>';
						}
					}
				}
			}
		}
		
		if (count($paramsToRemove) > 0)
			foreach ($paramsToRemove as $paramToRemove) {
				$paramToRemove->parentNode->removeChild($paramToRemove);
			}
		
		$this->newWs->save($this->newWsDir.'WsParams.xml');
		$copied = $newParams->length - count($paramsToRemove);
		
		$msg .= '<br/><i>Copied : </i>'.$copied.' derived parameters<br/><br/><hr>';
		return array('success' => true, 'msg' => $msg);
	}

	public function transferTimeTables() 
	{    
		$msg = '<b><i>Time Tables:</i></b><br/><br/>'; 
		
		// get old time tab list
		$this->newWs->load($this->oldWsDir.'Tt.xml');
		$timeTabs = $this->newWs->getElementsByTagName('timetab');
		if ($timeTabs->length == 0) {
			$msg .= 'No time tables';
			return array('success' => true, 'msg' => $msg);
		}
		
		$oldTtDir = OLDUSERPATH.TRANSFERUSER."/TT/";
		$newTtDir = NEWUSERPATH.TRANSFERUSER."/TT/";
		foreach ($timeTabs as $tab) {
			$id = $tab->getAttribute('xml:id');
			copy($oldTtDir.$id.'.xml', $newTtDir.$id.'.xml');
		}
		
		$this->newWs->save($this->newWsDir.'Tt.xml');
		$msg .= '<i>Copied : </i>'.$timeTabs->length.' time tables<br/><br/><hr>';
		return array('success' => true, 'msg' => $msg);
	}
 
	public function transferConditions() 
	{
		$msg = '<b><i>Requests</i></b><br/><br/>';
		$msg .= '<i>Note :</i> Plot requests are not copied : too much difference between new and old AMDA versions<br/<br/><br/>';
		$oldRequestXml = new DomDocument("1.0");
		$newRequestXml = new DomDocument("1.0");
		
		if (!@$oldRequestXml->load($this->oldWsDir.'Request.xml')){
			$msg .= ' No Requests File<br/>';
			return array('success' => true, 'msg' => $msg);
		}
		
		$condNodes = $oldRequestXml->getElementsByTagName('condition');
		if ($condNodes->length == 0) {
			$msg .= ' no DataMining requests to copy<br/>';
			return array('success' => true, 'msg' => $msg);
		}
		
		if (!file_exists($this->newWsDir.'Request.xml')) {
			$types = array('request', 'condition');

			$rootElement = $newRequestXml->createElement('ws');
			foreach ($types as $type)
			{
				$contentId = $type.'-treeRootNode';
				$contentTag = $type.'List';
				$typeElement = $newRequestXml->createElement($contentTag);
				$typeElement->setAttribute('xml:id', $contentId);
				$rootElement->appendChild($typeElement);
			}
			
			$newRequestXml->appendChild($rootElement);			 
		}				
		else 
			$newRequestXml->load($this->newWsDir.'Request.xml'); 
		
		$conditionRoot = $newRequestXml->getElementsByTagName('conditionList')->item(0);
		
		$condDir = OLDUSERPATH.TRANSFERUSER."/REQ/";
		
		$deleted = $this->getObsolete();
		$notready = $this->getNotready();
		$msg .= 'Some expressions could have problems while being processed by new kernel <br/> - <b>Please send us feedback in this case.</b><br/><br>
		 Not copied DataMining requests :<br/>';
		
		foreach ($condNodes as $condNode) {
			$id = $condNode->getAttribute('xml:id');
			$name = $condNode->getAttribute('name');
			$cond = file($condDir.$id, FILE_IGNORE_NEW_LINES);

			$condObj = json_decode($cond[0]);
			$expression = $condObj->expression;
			if ($this->deleteParam($expression, $deleted)) {
						$msg .= '<li><i>'.$name.'</i> : uses obsolete parameters<br/> '.$expression.'<br/>';
						$cond_deleted[] = $name;
 						continue;
 			}
 			
 			if ($this->deleteParam($expression,$notready)) {
						$msg .= '<li><i>'.$name.'</i> : uses param not ready yet<br/> '.$expression.'<br/>';
					// error_log( 'For INFO : DELETED '.$expression,1,email);
						$cond_deleted[] = $name;
						continue;
			}
			
			if (!empty($this->wsd_deleted))
					if ($this->deleteParam($expression,$this->wsd_deleted)) {
						$msg .= '<li><i>'.$name.'</i> : uses obsolete myData parameters<br/> '.$expression.'<br/>';
					// error_log( 'For INFO : DELETED '.$expression,1,email);
						$cond_deleted[] = $name;
						continue;
			}
			
			if (!empty($this->ws_deleted))
					if ($this->deleteParam($expression,$this->ws_deleted)) {
						$msg .= '<li><i>'.$name.'</i> : uses obsolete derived parameters<br/> '.$expression.'<br/>';
					// error_log( 'For INFO : DELETED '.$expression,1,email);
						$cond_deleted[] = $name;
						continue;
			}
			
			if ($this->deleteParam($expression,array("CDAWEB","MAPSKP","VEXGRAZ","IMPEX"))) {
						$msg .= '<li><i>'.$name.'</i> : uses remote params <br/> '.$expression.'<br/>';
						$cond_deleted[] = $name;
						continue;
			}
			
			if ($this->deleteParam($expression,$this->specParams)) {
						$msg .= '<li><i>'.$name.'</i> : too much difference <br/> '.$expression.'<br/>';
						$cond_deleted[] = $name;
						continue;
			}
			$expressionUpdated = $this->updateParams($expression);
			$condObj->expression = $expressionUpdated;
			file_put_contents(NEWUSERPATH.TRANSFERUSER."/REQ/".$id, json_encode($condObj));
			$conditionRoot->appendChild($newRequestXml->importNode($condNode));
		}
		
		$newRequestXml->save($this->newWsDir.'Request.xml');

		return array('success' => true, 'msg' => $msg);
	}
  
	public function transferMyData() 
	{
		$msg = '<hr><b><i>MyData Parameters / My Files:</i></b><br/><br/>';
		$msg.= '<i>Note :</i> CEF format is not implemented<br/><br/>';
		
		if (!$this->oldWs->load($this->oldWsDir.'WsParams.xml')) {
			error_log('cannot load WsParams.xml for '.TRANSFERUSER,1,email);
			return array('success' => false, 'error' => 'Sorry, we failed to get your MyData Params from old AMDA');
		}

		if (!file_exists($this->newWsDir.'WsParams.xml'))
						$this->createDom();
		else 
			$this->newWs->load($this->newWsDir.'WsParams.xml');
			
		$BaseXml =  new DomDocument("1.0");
		$FilesXml = new DomDocument("1.0");
		
		// get old params 
		$wsdParamsOld = $this->oldWs->getElementsByTagName('mydata');

		if ($wsdParamsOld->length == 0) {
				return array('success' => true, 'msg' => 'You have no MyData parameters');
		}
		
		if (!$BaseXml->load(OLDUSERPATH.TRANSFERUSER.'/DATA/base.xml')) {
			return array('success' => false, 'msg' => 'base description corrupted');
		}
		
		if (!$FilesXml->load($this->oldWsDir.'Files.xml')) {
			return array('success' => false, 'msg' => 'files description corrupted');
		}
		
		$this->newWs->load($this->newWsDir.'WsParams.xml');
		$paramDom = new DomDocument("1.0");
     
      $msg.= ' Not copied parameters : <br/>';
		foreach ($wsdParamsOld as $wsdParamOld) {
			$format = $wsdParamOld->getAttribute('format');
			$name = $wsdParamOld->getAttribute('name');
			$id = $wsdParamOld->getAttribute('xml:id');
			$mask = $wsdParamOld->getAttribute('mask');
			if ($format == 'cef') {
				$deletedVi[] = $mask;
				$msg .= '<li><i>'.$name.'</i><br/>';
				$this->wsd_deleted[] = 'wsd_'.$name;
			}
			else {
				$desc = $wsdParamOld->getAttribute('desc');
				$start = substr($desc,0,16).':00';
				$stop = substr($desc,17).':00';
				$wsdParamOld->setAttribute('desc', $start.'-'.$stop);
				
				$this->newWs->getElementsByTagName('mydataList')->item(0)->appendChild($this->newWs->importNode($wsdParamOld));
				
				$paramDom->load($this->oldWsDir.$id.'.xml');
				$descNode = $paramDom->getElementsByTagName('desc')->item(0);
				$descNode->nodeValue = $start.'-'.$stop;
				$paramDom->save($this->newWsDir.$id.'.xml'); 
				
				$fileFormat[$mask] = $format === 'txt' ? 'ASCII' : strtoupper($format);
			}
		}

		$this->newWs->save($this->newWsDir.'WsParams.xml');
		
		// First delete CEF files
		$xpBase = new domxpath($BaseXml);
		if (count($deletedVi) > 0)
			foreach ($deletedVi as $vi) {
				$maskNode = $xpBase->query("//mask[.='".$vi."']");
				if ( $maskNode->length == 0 )
					error_log('No '.$vi.' in '.TRANSFERUSER.'/DATA/base.xml',1,email);
				else {
					$viNode = $maskNode->item(0)->parentNode;
					$viNode->parentNode->removeChild($viNode);
				}
			}
		// Then modify base.xml : xml:id => id
		$viNodes = $BaseXml->getElementsByTagName('vi');
		foreach ($viNodes as $viNode) {
			$id = $viNode->getAttribute('xml:id');
			$viNode->removeAttribute('xml:id');
			$viNode->setAttribute('id',$id);
			$mask = $viNode->getElementsByTagName('mask')->item(0)->nodeValue;
			$viNode->setAttribute('format', $fileFormat[$mask]);
		}
		
		$BaseXml->save(NEWUSERPATH.TRANSFERUSER.'/DATA/base.xml');
		
		$msg .= 'Not copied files :<br/>';
		
		$filesNodes = $FilesXml->getElementsByTagName('file');
		foreach ($filesNodes as $file) {
			$fileName = $file->getAttribute('name');
			$format = $file->getAttribute('format');
			if ($format == 'cef') {
				$deletedFiles[] = $file->getAttribute('xml:id');
			}
			else {
				if (!@copy(OLDUSERPATH.TRANSFERUSER.'/DATA/'.$fileName,NEWUSERPATH.TRANSFERUSER.'/DATA/'.$fileName))
					$msg .= $fileName.'<br/>'; 
			}
		}
		
		if (count($deletedVi) > 0) 
			foreach ($deletedVi as $vi) {
				$node = $BaseXml->getElementById($vi);
				if ($node) {
					$node->parentNode->removeChild($node);
				}
			}
		 
      
		if (count($deletedFiles) > 0)
			foreach ($deletedFiles as $vi) {
				$node = $FilesXml->getElementById($vi);
				if ($node) {
					$msg .= '<li><i>'.$vi.'</i> <br/>';
					$node->parentNode->removeChild($node);
				}
			}

		$FilesXml->save($this->newWsDir.'Files.xml');

		return array('success' => true, 'msg' => $msg);
	} 
	
	public function transferFilters() 
	{
		$msg = '<hr><br/><br/><b><i>Filters:</i></b><br/><br/>'; 
		
		if (!curl_init($this->oldWsDir.'Filters.xml')) {
				return array('success' => true, 'msg' => 'No filters at old AMDA');
		}
		
		$filterXml = new DomDocument("1.0");
		if (!$filterXml->load($this->oldWsDir.'Filters.xml')) {
			return array('success' => false, 'error' => 'Cannot load filters from old AMDA');
		}
	    
	   $filterXml->save($this->newWsDir.'Filters.xml');
	   $msg .= 'Filters have been copied</br>';
		return array('success' => true, 'msg' => $msg);
	}
	
	function sendMail($email, $msg)
	{
		$subject = 'Your workspace has been copied to new AMDA';
		
		$headers = "From: amda@irap.omp.eu " . "\r\n".
						"Reply-To: amda@irap.omp.eu " . "\r\n".
						"Content-type: text/html\r\n";
	   $msg = "<html><b>Your Workspace has been copied to new AMDA</b><br/><br/>".$msg."</html>";
		mail($email, $subject, $msg, $headers);
	}
}
?>