<?php defined('SYSPATH') or die('No direct access allowed.');

/**
 * This class provides Host Server functions
 *
 * @package    Host
 * @category   Controllers/Task
 * @author     Deon George
 * @copyright  (c) 2009-2013 Open Source Billing
 * @license    http://dev.osbill.net/license.html
 */
class Controller_Task_Host extends Controller_Task {
	private $so; // Service Object
	private $hpo; //Host Server Object

	public function __construct(Request $request, Response $response) {
		parent::__construct($request,$response);

		// To make it easy for some methods, we'll load our service here
		switch (Request::current()->action()) {
			case 'getclient':
			case 'getdomain':
			case 'getdns':
			case 'getmail':
			case 'getreseller':
			case 'gettraffic':
			case 'migrate':
			case 'provision':
			case 'setdisablemail':
			case 'setexpire':
			case 'setpasswd':
				$this->so = ORM::factory('Service',$this->request->param('id'));

				if (! $this->so->loaded())
					throw new Kohana_Exception('Unknown service :sid',array(':sid'=>$this->request->param('id')));

				$this->hpo = $this->so->plugin()->host_server->plugin();

				break;
		}
	}

	public function save($index,$result) {
		$p = $this->so->plugin();

		// We need to use a new var to avoid Indirect modification of overloaded property errors.
		$x = is_null($p->server_data) ? array() : $p->server_data;
		$x[$p->host_server_id][$index] = serialize($result);
		$p->server_data = $x;

		$x = is_null($p->server_data_date) ? array() : $p->server_data_date;
		$x[$p->host_server_id][$index] = time();
		$p->server_data_date = $x;

		return $p->save();
	}

	private function verify($index,$result,$save=TRUE) {
		$p = $this->so->plugin();

		if (! isset($p->server_data[$p->host_server_id][$index]) OR (md5($p->server_data[$p->host_server_id][$index]) != md5(serialize($result)))) {
			if ($save)
				$this->save('c',$result);

			return FALSE;
		} else
			return TRUE;
	}

	/**
	 * Get Client Details from Host Server
	 */
	public function action_getclient() {
		$result = $this->hpo->cmd_getclient($this->so);

		if ($result->loaded())
			$this->verify('c',$result);

		echo (string)$result->_object;
	}

	/**
	 * Get Client Details from Host Server
	 */
	public function action_getdomain() {
		$result = $this->hpo->cmd_getdomain($this->so);

		if ($result->loaded())
			$this->verify('d',$result);

		echo (string)$result->_object;
	}

	/**
	 * Get DNS Details from Host Server
	 */
	public function action_getdns() {
		$result = $this->hpo->cmd_getdns($this->so,'/tmp/z');

		#if ($result->loaded())
		#	$this->verify('d',$result);

		echo (string)$result->_object;
	}

	/**
	 * Get Mail Details from Host Server
	 */
	public function action_getmail() {
		$result = $this->hpo->cmd_getmail($this->so);

		echo (string)$result->_xml;
		echo (string)$result->_object;
	}

	/**
	 * Get Reseller
	 */
	public function action_getreseller() {
		$result = $this->hpo->cmd_getreseller($this->so);

		echo (string)$result->_object;
	}

	/**
	 * Get Domain Traffic
	 */
	public function action_gettraffic() {
		$result = $this->hpo->cmd_gettraffic($this->so);

		echo (string)$result->_object;
	}

	public function action_migrate() {
		if (! preg_match('/^[0-9]+:[0-9]+-[0-9]+$/',$ids=$this->request->param('id')))
			throw new Kohana_Exception('Need to specify 2 site for a service to migrate, ie: svc:a-b');

		list($sid,$svrs) = preg_split('/:/',$ids,2);
		list($fsid,$tsid) = preg_split('/-/',$svrs,2);

		$so = ORM::factory('Service',$sid);
		if (! $so->loaded())
			throw new Kohana_Exception('Service :sid doesnt exist?',array(':sid'=>$sid));

		printf("Migrate: %s\n",$so->plugin()->name());

		// Validation, make sure the target is as configured
		if ($so->plugin()->host_server_id != $tsid)
			throw new Kohana_Exception('Service :sid is defined to server :tsid?',array(':sid'=>$sid,':tsid'=>$tsid));

		// Validation, make sure the target is defined
		$domain = clone $this->hpo->cmd_getdomain($this->so);
		if (! $domain->loaded())
			throw new Kohana_Exception('Service :sid is not on server :tsid?',array(':sid'=>$sid,':tsid'=>$tsid));

		// Temporarily set our host_server_id to $fsid
		$hpo = ORM::factory('Host_Server',$fsid);
		if (! $hpo->loaded())
			throw new Kohana_Exception('Host server :fsid not defined?',array(':fsid'=>$fsid));

		$result = $hpo->plugin()->cmd_getdns($this->so);

		// During migration we are only interested in the data.
		$k = array(
			'host_plugin_plesk_10'=>array('type','host','value','opt'),  // From PLESK 9.
		);

		$t = array(
			'host_plugin_plesk_10'=>array('domain_id'=>array('site-id'=>'id')),  // From PLESK 9.
		);

		$f = array(
			'host_plugin_plesk_10'=>array('host'=>'NODOMAIN','value'=>'NOTRAILDOT'),
		);

		$dns = $this->hpo->newitem($this->so,'dns');

		foreach ($result->_object->get('result',FALSE) as $key => $o) {
			$rec = $o->data->collapse();

			$add = $dns->add_node('add_rec');

			// Translate old values to new ones.
			foreach ($t[strtolower(get_class($this->hpo))] as $a=>$b) {
				if (isset($rec[$a])) {
					unset($rec[$a]);

					foreach ($b as $c=>$d) {
						$add->add_node($c,$domain->$d->value());
					}
				}
			}


			// Import the values we are interested in
			foreach ($k[strtolower(get_class($this->hpo))] as $a=>$b)
				if (isset($rec[$b])) {
					if (isset($f[strtolower(get_class($this->hpo))][$b])) {
						switch ($f[strtolower(get_class($this->hpo))][$b]) {
							case 'NODOMAIN':
								$rec[$b] = preg_replace('/\.?'.$so->plugin()->name().'\.$/i','',$rec[$b]);
								break;

							case 'NOTRAILDOT':
								$rec[$b] = preg_replace('/\.$/','',$rec[$b]);
								break;

							default:
								throw new Kohana_Exception('Unknown filter action :filter',array(':filter'=>$f[strtolower(get_class($this->hpo))][$b]));
						}
					}

					$add->add_node($b,$rec[$b]);
				}
		}

		printf("DNS: %s\n",(string)$dns);

		$result = $this->hpo->add_dnsdata($this->so,$dns);

		echo (string)$result->_object;
	}

	/**
	 * List services that need to be provisioned
	 * @todo This needs to be reviewed for functionality
	 */
	public function action_provisionlist() {
		$mode = $this->request->param('id');
		$cats = array();

		if ($mode)
			$cats = ORM::factory('Product_Category')->list_bylistgroup($mode);

		foreach (ORM::Factory('service')->list_provision()->find_all() as $so) {
			$pc = array();

			// Limit to show only those by the requested category.
			if ($cats) {
				if (! $so->product->avail_category OR ! preg_match('/^a:/',$so->product->avail_category))
					continue;

				$pc = unserialize($so->product->avail_category);

				if (! array_intersect($pc,array_keys($cats)))
					continue;
			}

			echo $so->id();

			switch ($mode) {
				case 'host':
					printf(' %s %s %s',$so->plugin(),$so->plugin()->host_server->name,$so->service_name());
					break;

				default:
			}
			echo "\n";
		}
	}

	/**
	 * Provision a Hosting Service
	 */
	public function action_provision() {
		$result = $this->hpo->provision($this->so);
		$this->action_setexpire();

		print_r((string)$result);
	}

	/**
	 * Provision a Hosting Service
	 */
	public function action_setdisablemail() {
		$result = $this->hpo->cmd_disablemail($this->so);

		echo (string)$result->_object;
	}

	public function action_setexpire() {
		if (! ($result = $this->hpo->setexpire($this->so)) OR ! $result->loaded()) {
			echo ('Unable to set expire date.');
			echo (string)$result->_xml;
			echo (string)$result->_object;
		} else
			echo (string)$result->_object;
	}

	public function action_setpasswd() {
		$pw = PWGen::get(TRUE);

		$spho = $this->so->plugin();
		$spho->host_password = $pw;

		if (! ($result = $this->hpo->setpasswd($this->so,$pw)) OR ! $result->loaded() OR ! $spho->save())
			throw new Kohana_Exception('Unable to set password.');

		echo _('Password Reset Success');
	}
}
?>
