IHMInputOutputParamsPlotClass.php 12.4 KB
<?php

define ("PLOT_RESULT_FILE_KEY","plot");

/**
 * @class IHMInputOutputParamsPlotClass
 * @brief Implementation of IHMInputOutputParamsAbstractClass to treat plot request
 * @details
*/
class IHMInputOutputParamsPlotClass extends IHMInputOutputParamsAbstractClass
{
	private $currentTabId;
	private $isInterractive;
	private $startTime;
	private $stopTime;
	
	/*
	 * @brief method to unmarshall a plot request
	*/
	protected function unmarshallRequest($input)
	{
		if (isset($input->action))
		{
			//interactive action
			$realInput = $input;
			$input = $this->loadIHMRequest();
			
			if (!isset($input))
				throw new Exception('Cannot get original request data for interactive action.');
			
			//modify request
			date_default_timezone_set('UTC');
			$intervalMove = 0.;
			switch ($realInput->action->name)
			{
				case 'next' :
					$intervalMove = strtotime($input->stopDate) - strtotime($input->startDate);
					break;
				case 'halfnext' :
					$intervalMove = (strtotime($input->stopDate) - strtotime($input->startDate))/2;
					break;
				case 'back' :
					$intervalMove = strtotime($input->startDate) - strtotime($input->stopDate);
					break;
				case 'halfback' :
					$intervalMove = (strtotime($input->startDate) - strtotime($input->stopDate))/2;
					break;
			}
			//apply move
			$input->startDate = date("Y-m-d\TH:i:s",strtotime($input->startDate)+$intervalMove);
			$input->stopDate = date("Y-m-d\TH:i:s",strtotime($input->stopDate)+$intervalMove);	
		}
		
		//remove old result files
		foreach (glob($this->getWorkingPath()."plot_*.png") as $oldfile)
		{
			unlink($oldfile);
		}
		
		//Full plot request
		$this->startTime = $input->startDate;
		$this->stopTime  = $input->stopDate;
		
		//save request
		$this->saveIHMRequest($input);
		
		//TimePlot
		//{"id":"","name":"","tabId":"1","outputName":"","orientation":"LANDSCAPE","format":"PNG","title":"",
		//"description":"","charSize":1.3,"thickness":1,"ppp":3000,"forcedLayout":false,"forcedMulti":false,
		//"children":[{"name":"Panel 1","leaf":false,"text":"","width":1,"height":0.4,"xTitle":"",
		//"xRangeMin":0,"xRangeMax":0,"y1Title":"","y1RangeMin":0,"y1RangeMax":0,"y2Title":"",
		//"y2RangeMin":0,"y2RangeMax":0,"plotType":"TIME",
		//"children":[{"name":"imf","leaf":true,"text":"imf","paramArgs":"select...","isScatter":false,
		//"needsArgs":false,"plotOnly":false,"yaxe":false}]}],
		//"timesrc":"Interval","startDate":"2008-03-17T14:07:43","stopDate":"2008-03-17T15:26:18"
		//"durationDay":"0000","durationHour":"01","durationMin":"18","durationSec":"35","leaf":true,"nodeType":"request"}


		//XYPlot
		//{"id":"","name":"","tabId":"1","outputName":"","orientation":"LANDSCAPE","format":"PNG","title":"",
		//"description":"","charSize":1.3,"thickness":1,"ppp":3000,"forcedLayout":false,"forcedMulti":false,
		//"children":[{"name":"Panel 1","leaf":false,"text":"","width":0.4,"height":0.4,"xTitle":"",
		//"xRangeMin":0,"xRangeMax":0,"y1Title":"","y1RangeMin":0,"y1RangeMax":0,"y2Title":"",
		//"y2RangeMin":0,"y2RangeMax":0,"plotType":"SCATTER",
		//"scatterParam":{"phantom":true,"internalId":"ext-record-71","raw":{"name":"imf(1)"},
		//"data":{"id":"","name":"imf(1)"},"modified":{},"hasListeners":{},"events":{},"stores":[],
		//"dirty":false,"id":"amdaModel.AmdaObject-ext-record-71"},
		//"children":[{"name":"#xmfi","leaf":true,"text":"#xmfi","paramArgs":"select...","isScatter":true,
		//"needsArgs":false,"plotOnly":false,"yaxe":false}]}],
		//"timesrc":"Interval","startDate":"2008-03-17T14:07:43","stopDate":"2008-03-17T15:26:18",
		//"durationDay":"0000","durationHour":"01","durationMin":"18","durationSec":"35","leaf":true,"nodeType":"request"}

		$this->currentTabId = $input->tabId;
		
		$paramsNode = $this->paramsData->getRequestNode()->getParamsNode();

		//unmarshall time definition
		$this->unmarshallTimeDefinition($input);

		//unmarshall plot output definition
		$outputsNode = $this->paramsData->getRequestNode()->getOutputsNode();
		$plotOutputNode = $outputsNode->addNewOutput(RequestOutputTypeEnum::PLOT);

		$pageNode = $plotOutputNode->getPage();

		//title
		$pageNode->setTitle($input->description);
		
		//orientation = [['landscape','LANDSCAPE'], ['portrait', 'PORTRAIT']];
		$forceRotation = false;
		switch (strtolower($input->orientation))
		{
			case 'landscape' :
				$pageNode->setOrientation(RequestOutputPlotPageOrientationEnum::LANDSCAPE);
				break;
			case 'portrait' :
				$pageNode->setOrientation(RequestOutputPlotPageOrientationEnum::PORTRAIT);
				$forceRotation = true;
				break;
			default :
				$pageNode->setOrientation(RequestOutputPlotPageOrientationEnum::LANDSCAPE);
				break;
		}

		//format = [['PNG','PNG'], ['PDF', 'PDF'], ['PS', 'PostScript']];
		switch ($input->format)
		{
			case 'PNG' :
				$pageNode->setFormat(RequestOutputPlotPageFormatEnum::PNG);
				//interactive plot => disable batch mode
				$this->paramsData->setBatchEnable(false);
				$this->isInterractive = true;
				break;
			case 'PDF' :
				$pageNode->setFormat(RequestOutputPlotPageFormatEnum::PDF);
				$this->isInterractive = false;
				break;
			case 'PS' :
			case 'PostScript' :
				$pageNode->setFormat(RequestOutputPlotPageFormatEnum::PS);
				$this->isInterractive = false;
				break;
		}

		//auto layout
		if (count($input->children) > 1)
		{
			if ($input->forcedLayout)
				$pageNode->getLayout()->setType(RequestOutputPlotLayoutTypeEnum::AUTO);
			else
				$pageNode->getLayout()->setType(RequestOutputPlotLayoutTypeEnum::VERTICAL);
		}
			
		$pageNode->getLayout()->setExpand("true");
		
		//panels
		
		foreach ($input->children as $panel)
		{
			$panelNode = $pageNode->addPanel();
			$panelNode->setTitle($panel->name);
				
			//add plot element
			switch ($panel->plotType)
			{
				case "TIME" :
					//time plot definition
					$plotElementNode = $panelNode->addPlotElement(RequestOutputPlotElementTypeEnum::TIMEPLOT);
					//time axis definition
					$timeAxisNode = $plotElementNode->getTimeAxis();
					$isXYPlot = false;
					break;
				case "SCATTER" :
					//XY plot definition
					$plotElementNode = $panelNode->addPlotElement(RequestOutputPlotElementTypeEnum::XYPLOT);
					//x axis definition
					$xAxisNode = $plotElementNode->getXAxis();
					$xAxisNode->getLegend()->setText($panel->xTitle);
					if ((($panel->xRangeMin != 0) || ($panel->xRangeMax != 0)) && ($panel->xRangeMin < $panel->xRangeMax))
						$xAxisNode->getRange()->setMinMax($panel->xRangeMin, $panel->xRangeMax);
					$isXYPlot = true;
					break;
			}
				
			if (!isset($plotElementNode))
				//unknown plot type
				continue;

			//y1 axis definition
			$y1AxisNode = $plotElementNode->addYAxis("y1");
			$y1AxisNode->getLegend()->setText($panel->y1Title);
			if ((($panel->y1RangeMin != 0) || ($panel->y1RangeMax != 0)) && ($panel->y1RangeMin < $panel->y1RangeMax))
				$y1AxisNode->getRange()->setMinMax($panel->y1RangeMin, $panel->y1RangeMax);

			//y2 axis definition - it will drawn only if at least one param is associated to this axis
			$y2AxisNode = $plotElementNode->addYAxis("y2");
			$y2AxisNode->getLegend()->setText($panel->y2Title);
			if ((($panel->y2RangeMin != 0) || ($panel->y2RangeMax != 0)) && ($panel->y2RangeMin < $panel->y2RangeMax))
				$y2AxisNode->getRange()->setMinMax($panel->y2RangeMin, $panel->y2RangeMax);
				
			//add xserie if XYPlot
			if ($panel->plotType == "SCATTER")
			{
				//"scatterParam":{"phantom":true,"internalId":"ext-record-71","raw":{"name":"imf(1)"},
				//"data":{"id":"","name":"imf(1)"},"modified":{},"hasListeners":{},"events":{},"stores":[],
				//"dirty":false,"id":"amdaModel.AmdaObject-ext-record-71"}
				$paramInfo = $this->paramManager->addExistingParam($panel->scatterParam->data->name,$this->paramsData);
				$paramsNode->addParam($paramInfo['id']);
			
				$paramNode = $plotElementNode->getParams()->getParamById($paramInfo['id']);
				if (count($paramInfo['indexes']) == 0)
					$paramNode->addXSerie($xAxisNode->getId(), -1);
				else
				{
					$paramNode->addXSerie($xAxisNode->getId(), $paramInfo['indexes'][0]);
				}
			}
			
			//add yseries
			foreach ($panel->children as $yserie)
			{
				//{"name":"imf","leaf":true,"text":"imf","paramArgs":"select...","isScatter":false,
				//"needsArgs":false,"plotOnly":false,"yaxe":false}

				//{"name":"#xmfi","leaf":true,"text":"#xmfi","paramArgs":"select...","isScatter":true,
				//"needsArgs":false,"plotOnly":false,"yaxe":false}

				$xAxis = "";
				if ($isXYPlot)
					$xAxis = $xAxisNode->getId();
					
				$yAxis = $y1AxisNode->getId();
				if ($yserie->yaxe)
					$yAxis = $y2AxisNode->getId();

				$paramInfo = $this->paramManager->addExistingParam($yserie->name,$this->paramsData);
				$paramsNode->addParam($paramInfo['id']);

				$paramNode = $plotElementNode->getParams()->getParamById($paramInfo['id']);
				if (count($paramInfo['indexes']) == 0)
				{
					$isSpectro = ($paramInfo['plotType'] == 'Spectra');
					if ($isSpectro && $panel->plotType == "TIME")
						$paramNode->addSpectro($yAxis);
					else
						$paramNode->addYSerie($yAxis, -1,$xAxis);
				}
				else
				{
					foreach ($paramInfo['indexes'] as $index)
						$paramNode->addYSerie($yAxis, $index,$xAxis);
				}
			}
		}

		//determine extension and add post processing if needed
		$extension = "";
		switch (strtolower($pageNode->getFormat()))
		{
			case RequestOutputPlotPageFormatEnum::PNG :
				$extension = ".png";
				break;
			case RequestOutputPlotPageFormatEnum::PS :
				$extension = ".ps";
				break;
			case RequestOutputPlotPageFormatEnum::PDF :
				$extension = ".pdf";
				break;
		}

		$compression = "";
		if ($pageNode->getFormat() != RequestOutputPlotPageFormatEnum::PNG)
		{
			//one file per interval
			$plotOutputNode->setStructure(RequestOutputPlotStructureEnum::ONE_FILE_PER_INTERVAL);
			//auto compression if not PNG format
			$compression = ".tar.gz";
			$plotOutputNode->addPostProcessing(RequestOutputPostProcessingEnumClass::TAR);
			$plotOutputNode->addPostProcessing(RequestOutputPostProcessingEnumClass::GZIP);
		}

		//Set post command to retrieve request result file
		//Use a cache killer (ie - random string in file name)
		$resultFile = "plot_".CommonClass::generateRandomString(6);
		$this->paramsData->addWaitingResult(PLOT_RESULT_FILE_KEY, $resultFile);

		if ($pageNode->getFormat() != RequestOutputPlotPageFormatEnum::PNG)
		{
			$postProcessCmd  = "mv plot_*".$compression;
			$postProcessCmd .= " ".$resultFile.$extension.$compression;
		}
		else
		{
			$postProcessCmd  = "mv plot_*";
			$postProcessCmd .= $extension;
			$postProcessCmd .= " ".$resultFile.$extension;
			if ($forceRotation)
				$postProcessCmd .= " | convert ".$resultFile.$extension." -rotate -90 ".$resultFile.$extension;
		}

		$this->paramsData->setPostCmd($postProcessCmd);

		return $this->paramsData;
	}

	/*
	 * @brief method to marshall the result of a download request
	*/
	protected function marshallResult($data)
	{
		if (!$this->isInterractive)
		{
			//add to job
			$commonRes = $this->commonMarshallResult($data,PLOT_RESULT_FILE_KEY);
		
			return $commonRes;
		}
		
		if (!$data->getSuccess())
			return array(
					'success' => false,
					'message' => $data->getLastErrorMessage());
		
		switch ($data->getStatus())
		{
			case ProcessStatusEnumClass::DONE :
				return array(
					'success'     => true,
					'id'          => $data->getId(),
					'folder'      => $this->getWorkingDirName(),
					'result'      => $data->getWaitingResult(PLOT_RESULT_FILE_KEY),
					'format'      => 'PNG',
					'compression' => 'unknown',
					'status'      => 'done',
					'children'    => array(
							array(
									"xmin" => "0",
									"xmax" => "1",
									"ymin" => "0",
									"umax" => "1"
							)
					),
					'tabId'       => $this->currentTabId,
					'startDate'   => $this->startTime,
					'stopDate'    => $this->stopTime
				);
			default :
				return array(
				'success' => false,
				'message'   => 'Error to process the interractive request');
		}
	}
	
	private function saveIHMRequest($input)
	{
		$path = $this->getWorkingPath()."ihm.request";
		if (!is_dir($this->getWorkingPath()))
			mkdir($this->getWorkingPath(),0777);
		$file = fopen($path, 'w');
		fwrite($file, json_encode($input));
		fclose($file);
	}
	
	private function loadIHMRequest()
	{
		$path = $this->getWorkingPath()."ihm.request";
		if (!file_exists($path))
			return NULL;
		return json_decode(file_get_contents($path));
	}
}
?>