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

/**
 * This class supports Services
 *
 * @package    SSL
 * @category   Models
 * @author     Deon George
 * @copyright  (c) 2009-2013 Open Source Billing
 * @license    http://dev.osbill.net/license.html
 */
class Model_Service_Plugin_Ssl extends Model_Service_Plugin {
	protected $_table_name = 'service__ssl';
	protected $_updated_column = FALSE;

	// Relationships
	protected $_belongs_to = array(
		'service'=>array(),
	);
	protected $_has_one = array(
		'SSL_CA'=>array('far_key'=>'ssl_ca_id','foreign_key'=>'id'),
	);

	protected $_display_filters = array(
		'csr'=>array(
			array('SSL::csrsubject',array(':value')),
		),
		'cert'=>array(
			array('SSL::subject',array(':value')),
		),
	);

	// Required abstract functions
	public function username_value() {} // Not used
	public function password_value() {} // Not used

	private $_so = NULL;

	/**
	 * Resolve any queries to certificate details
	 */
	public function __call($name,$args) {
		$m = 'get_'.$name;

		if (method_exists($this->_so,$m))
			return $this->_so->{$m}($args);
		else
			throw new Kohana_Exception('Unknown method :method',array(':method'=>$name));
	}

	// We want to inject the SSL object into this Model
	protected function _load_values(array $values) {
		parent::_load_values($values);

		if ($this->cert)
			$this->_so = SSL::instance($this->cert);

		return $this;
	}

	// If we change the SSL certificate, we need to reload our SSL object
	public function values(array $values, array $expected = NULL) {
		parent::values($values,$expected);

		if (array_key_exists('cert',$values))
			$this->_so = SSL::instance($this->cert);

		return $this;
	}

	public function expire() {
		return $this->_so->get_valid_to();
	}

	public function name() {
		return ($this->cert AND $this->SSL_CA->loaded()) ? sprintf('%s:%s',$this->SSL_CA->subject(),$this->display('cert')) : $this->display('csr');
	}

	public function service_view() {
		return View::factory('service/user/plugin/ssl/view')
			->set('so',$this);
	}

	/**
	 * Get specific service details for use in other modules
	 * For Example: Invoice
	 *
	 * @todo Make the rendered items configurable
	 * @todo Change this method name, now that it is public
	 */
	// @todo This needs to be validated for this model
	public function _details($type) {
		switch ($type) {
			case 'invoice_detail_items':
				return array();
				break;
			default:
				return parent::$_details($type);
		}
	}

	// @todo This needs to be validated for this model
	public function admin_update() {
		return View::factory('service/admin/plugin/ssl/update')
			->set('mediapath',Route::get('default/media'))
			->set('so',$this);
	}

	public function download_button() {
		if (! $this->service->status OR ! preg_match('/client/',$this->service->product->plugin()->extensions) OR $this->valid_to() < time())
			return '';

		// @todo Do some password validation
		$output = Form::open(URL::link('user','ssl/download'));
		$output .= Form::hidden('sid',$this->service->id);
		$output .= _('Choose a password').': '.Form::password('passwd','').'<br/><br/>';
		$output .= Form::submit('download','Download',array('class'=>'form_button'));
		return $output;
	}

	public function cacerts() {
		$result = array();

		$x = $this->ssl_ca_id;
		while ($x) {
			$sco = ORM::factory('SSL_CA',$x);
			array_push($result,$sco->sign_cert);
			$x = $sco->parent_ssl_ca_id;
		}

		return $result;
	}

	public function renew() {
		$d = SSL::instance($this->cert);
		$ssl_conf = Kohana::$config->load('ssl');
		// @todo change this so an admin can force this.
		$force = TRUE;

		// If our certificate is not old enough skip
		if ($d->get_valid_to() > time()+$ssl_conf['min_renew_days']*86400 AND ! $force)
			return FALSE;

		$res = openssl_csr_sign($this->csr,$this->SSL_CA->sign_cert,$this->SSL_CA->sign_pk,$this->service->product->plugin()->days,array(
			'config'=>$ssl_conf['config'],
			'x509_extensions'=>$this->service->product->plugin()->extensions,
			'digest_alg'=>'sha1',
		),time());

		if ($res AND openssl_x509_export($res,$cert)) {
			$this->cert = $cert;
			$this->save();

			return TRUE;
		} else {
			print_r(array(
				'csr'=>$this->csr,
				'ca'=>$this->SSL_CA->sign_cert,
				'capk'=>$this->SSL_CA->sign_pk,
				'days'=>$this->service->product->plugin()->days,
				'ssl'=>$ssl_conf,
				'x509e'=>$this->service->product->plugin()->extensions
			));

			throw new Kohana_Exception('Error Creating SSL Certificate :error',array(':error'=>openssl_error_string()));
		}
	}
}
?>