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

/**
 * This class supports SSL
 *
 * @package    SSL
 * @category   Models
 * @author     Deon George
 * @copyright  (c) 2009-2013 Deon George
 * @license    http://dev.leenooks.net/license.html
 */
class Model_SSL_CA extends Model_SSL {
	// Relationships
	protected $_belongs_to = array(
		'account'=>array(),
		'parent'=>array('model'=>'ssl_ca','foreign_key'=>'ssl_ca_id'),
	);
	protected $_has_many = array(
		'child'=>array('model'=>'ssl_ca','far_key'=>'id','foreign_key'=>'ssl_ca_id'),
		'ssl'=>array('model'=>'ssl','far_key'=>'id','foreign_key'=>'ssl_ca_id'),
	);

	protected $_display_filters = array(
		'cert'=>array(
			array('Model_SSL::subject_cert',array(':value')),
		),
	);

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

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

	private function _bc() {
		return $this->_extensions('basicConstraints');
	}

	public function ca_path_len() {
		$m = array();
		$x = preg_match('/.*pathlen:\s*([0-9]+).*$/',$this->_bc(),$m);

		return isset($m[1]) ? (int)$m[1] : 0;
	}

	/**
	 * 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 $so)
			if ($so->ski() == $this->aki_keyid())
				return $so->id;

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

	public function isCA() {
		return preg_match('/CA:TRUE/',$this->_bc()) ? TRUE : FALSE;
	}

	public function isCert() {
		return $this->_cert_details ? TRUE : FALSE;
	}

	public function isRoot() {
		return $this->aki_keyid() == $this->ski();
	}

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

	/**
	 * 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->ssl_ca_id) AND $this->isRoot())
			return StaticList_YesNo::get(TRUE,$format);

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

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

		if ($children)
			foreach ($this->list_ca_child() as $cao)
				$result += $cao->count_ca_child($children);

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

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

		if ($children)
			foreach ($this->list_ssl_child() as $cao)
				$result += $cao->ca->count_ssl_child($children);

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

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

		foreach ($this->child->find_all() as $co) {
			// Ignore me if this is the root certificate
			if ($co->id == $this->id)
				continue;

			array_push($result,$co);
		}

		return $result;
	}

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

		foreach ($this->ssl->find_all() as $co)
			if ($co->validCA())
				array_push($result,$co);

		return $result;
	}
}
?>