<?php

class SonyengineClient {

	const POST_METHOD = "POST";
	const GET_METHOD = "GET";
	
	private $base_url;
	
	public static function getInstance() {
		$host = sfConfig::get('iri_sonyengine_service_host', "localhost");
    	$port = sfConfig::get('iri_sonyengine_service_port', 8080);
    	$path = sfConfig::get('iri_sonyengine_service_path', "/sonyengine");
		
		return new  SonyengineClient($host, $port, $path);
	}
	
	public function __construct($host, $port, $path) {
		$path = trim($path,'/');
		$this->base_url = "http://$host:$port/$path";
	}
	
	private function send($path, $method, $fields) {
		
		$path = ltrim($path,"/");
		
		$ch = curl_init();
		$url = rtrim($this->base_url,'/')."/".$path;
		
		sfContext::getInstance()->getLogger()->info("SonyengineClient.send - url : ".$url);
		
		curl_setopt($ch,CURLOPT_URL,$url);
		curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
		
		if($method == self::POST_METHOD) {
			
			$fields_string = "";
			
			foreach($fields as $key=>$value) {
				$fields_string .= $key.'='.urlencode($value).'&';
			}
			$fields_string = rtrim($fields_string,'&');
			
			curl_setopt($ch,CURLOPT_POST,1);
			curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);
		}
		
		$buffer = curl_exec($ch);
		curl_close($ch);
		
		return $buffer;
	}
	
	
	public function engineTrain($movieId = null) {
		
		$path = "engine/train";
		if(! is_null($movieId)) {
			$path .= "/$movieId";
		}
		
		$res = $this->send($path, self::POST_METHOD, array());
		
		if($res != "ok") {
			throw new Exception('Can not train engine');
		}
		
	}
	
	public function engineFind($movieId, $tag, $distance = "0.05", $more = true ) {
		
		if($more) {
			$more = "true";
		}
		else {
			$more = "false";
		}
		
		$tag = urlencode($tag);
		
		$path = "engine/find/$movieId/$tag/$distance/$more";
		
		$res = $this->send($path,self::GET_METHOD, array());
		
		$result = array();
		
		$doc = new DOMDocument();
		$doc->loadXML($res);
		$xpath = new DOMXPath($doc);
		
		$nodes = $xpath->query("/sonyengine/neighbor");
		
		foreach($nodes as $node) {
			$result[] = array("id"=>$node->getAttribute("segment"),"distance"=>$node->getAttribute("distance") );	
		}
				
		return $result;
	}
	
	private function processXmlResponse($res, $node, $count) {
        
		$doc = new DOMDocument();
		$doc->loadXML($res);
        $xpath = new DOMXPath($doc);
        
        $nodes = $xpath->query("//*/".$node);
		
        return ($nodes->length == $count);
	}
	
	public function engineReset() {
		$path = "engine/reset";
		
		$res = $this->send($path,self::POST_METHOD,array());

		if($res != "ok") {
			throw new Exception('Can not reset engine : ' . $res);
		}
		
	}
	
	public function segmentCreate($movieId, $retrain) {
		
		$path = "";
		if($retrain)
			$retrain = "true";
		else
		    $retrain = "false";
			
		if(is_array($movieId)) {
			$path = "segment/createall";
			$doc = new DOMDocument();
			$root = $doc->createElement("sonyengine");
			$doc->appendChild($root);
			
			foreach($movieId as $id) {
				$elem = $doc->createElement("segment");
				$elem->setAttribute("id",$id);
				$root->appendChild($elem);
			}
			$fields = array("xml"=>$doc->saveXML(), "retrain"=>$retrain);
			$count = count($movieId);
		}
		else {
			$path = "segment/create";
			$fields = array("id"=>$movieId, "retrain"=>$retrain);
			$count = 1;
		}
		
		$res = $this->send($path, self::POST_METHOD, $fields);
		
		if(! $this->processXmlResponse($res, "movieFragment", $count)) {
			throw new Exception('Can not create segment ' . $res);
		}		
		
	}
	
	public function tagAdd($array, $retrain) {
		// test if this is an associative array
		// taken from http://www.php.net/manual/en/function.is-array.php#96724
		$tags = null;
		if($retrain)
			$retrain = "true";
		else
			$retrain = "false";
		
		if(is_array($array)) {
			$tags = $array;
		}
		else {
			$tags = array();
			$tags[] = $array;
		}
		
		$path = "tag/add";

		
		$doc = new DOMDocument();
		$root = $doc->createElement("sonyengine");
		$doc->appendChild($root);
		foreach($tags as $tag) {
			$elem = $doc->createElement("tag");
			$elem->setAttribute("name",$tag["name"]);
			$elem->setAttribute("segment",$tag["segment"]);
			$root->appendChild($elem);
		}
		$fields = array("xml"=>$doc->saveXML(), "retrain"=>$retrain);
		
		$res = $this->send($path, self::POST_METHOD, $fields);
		
		if(!$this->processXmlResponse($res,"tag",count($tags))) {
			throw new Exception('Can not add tags : '. print_r($fields,true)."\n==========\n". print_r($tags,true)."\n==========\n".$res);
		}		

	}

}