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

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

	// Relationships
	protected $_belongs_to = array(
		'parent'=>array('model'=>'ssl_ca','foreign_key'=>'parent_ssl_ca_id'),
	);
	protected $_has_many = array(
		'children'=>array('model'=>'ssl_ca','far_key'=>'id','foreign_key'=>'parent_ssl_ca_id'),
		'service'=>array('through'=>'service__ssl'),
	);

	protected $_display_filters = array(
		'sign_cert'=>array(
			array('SSL::subject',array(':value')),
		),
	);

	public function filters() {
		return array(
			'parent_ssl_ca_id'=>array(
				array(array($this,'filter_getParent')),
			)
		);
	}

	public function rules() {
		return Arr::merge(parent::rules(),array(
			'sign_cert'=>array(
				array('not_empty'),
				array(array($this,'isCert')),
				array(array($this,'isCA')),
			),
			'parent_ssl_ca_id'=>array(
				array(array($this,'rule_parentExist')),
			),
		));
	}

	private $_so = NULL;

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

		if (is_null($this->_so))
			return NULL;

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

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

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

		return $this;
	}

	/**
	 * List the child CA certs
	 */
	public function childca($children=FALSE) {
		$result = 0;

		if ($children)
			foreach ($this->list_childca() as $cao)
				$result += $cao->childca($children);

		return $result+$this->list_childca()->count();
	}

	public function childcrt($children=FALSE) {
		$result = 0;

		if ($children)
			foreach ($this->list_childca() as $cao)
				$result += $cao->childcrt($children);

		return $result+$this->list_childcrt()->count();
	}

	/**
	 * Make sure we have our parent in the DB too
	 */
	public function validParent($format=FALSE) {
		$result = NULL;

		// If we are a root cert, we are valid
		if (is_null($this->parent_ssl_ca_id) AND $this->isRoot())
			return StaticList_YesNo::get(TRUE,$format);

		return StaticList_YesNo::get($this->aki_keyid() == $this->parent->ski(),$format);
	}

	// 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('sign_cert',$values))
			$this->_so = SSL::instance($this->sign_cert);

		return $this;
	}

	/**
	 * Filter to find the parent SSL_CA
	 *
	 * @notes This filter only runs when the value passed is -1
	 */
	public function filter_getParent() {
		// This cannot be an array
		if (count(func_get_args()) != 1)
			return NULL;

		$x = func_get_args();
		$x = array_pop($x);

		// This filter only runs when our value is -1
		if ($x != -1)
			return $x;

		foreach (ORM::factory($this->_object_name)->find_all() as $sco) {
			if ($sco->ski() == $this->aki_keyid())
				return $sco->id;
		}

		// If we got here, we couldnt find it
		return $this->isRoot() ? NULL : $x;
	}

	public function list_childca() {
		return $this->children->find_all();
	}

	public function list_childcrt() {
		return $this->service->where_active()->find_all();
	}

	public function rule_parentExist() {
		// Our parent_ssl_ca_id should have been populated by filter_GetParent().
		return ($this->parent_ssl_ca_id > 0) OR $this->isRoot();
	}
}
?>
