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

/**
 * This class supports OSB listing products
 *
 * @package    Product
 * @category   Models
 * @author     Deon George
 * @copyright  (c) 2009-2013 Open Source Billing
 * @license    http://dev.osbill.net/license.html
 *
 * Column Definitions:
 * + price_type: 0=One Time, 1=Recurring, 2=Trial
 */
class Model_Product extends ORM_OSB implements Invoicable {
	protected $_has_many = array(
		'invoice'=>array('through'=>'invoice_item'),
		'service'=>array('far_key'=>'id'),
		'translate'=>array('model'=>'Product_Translate','far_key'=>'id'),
	);

	protected $_sorting = array(
		'position'=>'asc',
	);

	protected $_display_filters = array(
		'price_type'=>array(
			array('StaticList_PriceType::get',array(':value')),
		),
		'status'=>array(
			array('StaticList_YesNo::get',array(':value',TRUE)),
		),
		'taxable'=>array(
			array('StaticList_YesNo::get',array(':value',TRUE)),
		),
	);

	protected $_form = array('id'=>'id','value'=>'description()');

	protected $_nullifempty = array(
		'price_group',
	);

	// Our attributes that are arrays, we'll convert/unconvert them
	protected $_serialize_column = array(
		'price_group',
	);

	protected $_save_message = TRUE;

	// Our required Interface Methods

	public function invoice_item($item_type) {
		switch ($item_type) {
			case 0:
			case 7:
				return 'Service';
			default:
				return 'Product Charge';
		}
	}

	public function invoice_title() {
		return $this->title();
	}

	// Our local methods

	// Our database index for pricing values
	private $_price_options = array(
		'base'=>'price_base',
		'setup'=>'price_setup',
	);

	public function cost($annual=FALSE) {
		return $this->plugin() ? $this->plugin()->cost($annual) : 0;
	}

	/**
	 * Return the translated description for a category.
	 */
	public function description($full=FALSE) {
		$x = $this->translate();

		return $x->loaded() ? $x->display($full ? 'description_full' : 'description_short') : 'No Description';
	}

	/**
	 * This will render the product feature summary information
	 */
	public function feature_summary() {
		return (is_null($x=$this->plugin())) ? HTML::nbsp('') : $x->render_view();
	}

	/**
	 * Is price shown for a specific period
	 *
	 * @param $p int recurring schedule period
	 */
	public function is_price_shown($p) {
		$x = $this->keyget('price_group',$p);

		return (isset($x['show']) AND $x['show']) ? TRUE : FALSE;
	}

	/**
	 * Test if the product is a TRIAL product
	 * (price_type == 2)
	 *
	 * @return boolean
	 */
	public function is_trial() {
		return ($this->price_type == 2) ? TRUE : FALSE;
	}

	/**
	 * Return the object of the product plugin
	 */
	public function plugin() {
		if (! $this->prod_plugin_file)
			return NULL;

		if (! is_numeric($this->prod_plugin_data))
			throw new Kohana_Exception('Missing plugin_id for :product (:type)',array(':product'=>$this->id,':type'=>$this->prod_plugin_file));

		return ORM::factory(Kohana::classname(sprintf('Product_Plugin_%s',$this->prod_plugin_file)),$this->prod_plugin_data);
	}

	/**
	 * Enable the plugin to store data during an update
	 */
	public function plugin_edit() {
		return (is_null($x = $this->plugin())) ? NULL : $x->render_edit();
	}

	/**
	 * Return the price for the particular group and price option for the period
	 */
	public function price($grp,$period,$price_option,$taxed=FALSE) {
		if (is_null($option=$this->price_option($price_option)) OR is_null($x=$this->keyget('price_group',$period)))
			return NULL;

		if (isset($x[$grp][$option]))
			return $taxed ? Tax::add($x[$grp][$option]) : $x[$grp][$option];
		else
			return NULL;
	}

	/**
	 * For the specific user, get the best price
	 *
	 * @todo change this to be the overall contract price, if there is a contract
	 */
	public function price_best($period,$taxed=FALSE) {
		$result = NULL;

		$x = NULL;
		foreach (Auth::instance()->get_groups() as $go) {
			$price = $this->price($go->id,$period,'base',$taxed);

			if ($go->pricing AND ! is_null($price) AND (is_null($result) OR $x > $price)) {
				$result = $go;
				$x = $price;
			}
		}

		return is_null($result) ? ORM::factory('Group',0) : $result;
	}

	/**
	 * Get the database index for a price option
	 */
	public function price_option($option) {
		return isset($this->_price_options[$option]) ? $this->_price_options[$option] : NULL;
	}

	/**
	 * Return the available pricing options
	 */
	public function price_options() {
		return $this->_price_options;
	}

	public function save(Validation $validation=NULL) {
		parent::save($validation);

		// Save our Translated Message
		if ($x = array_diff_key($_POST,$this->_object) AND ! empty($_POST['language_id']) AND ! empty($_POST['translate']) AND is_array($_POST['translate'])) {
			$to = $this->translate->where('language_id','=',$_POST['language_id'])->find();

			// For a new entry, we need to set the product_id
			if (! $to->loaded()) {
				$to->product_id = $this->id;
				$to->language_id = $_POST['language_id'];
			}

			$to->values($x['translate'])->save();
		}

		return $this;
	}

	public function supplier() {
		return $this->plugin() ? $this->plugin()->supplier() : 'other';
	}

	private function translate() {
		return $this->translate->where('language_id','=',Config::language())->find();
	}

	/**
	 * Return the translated title for a category
	 */
	public function title() {
		$x = $this->translate();

		return $x->loaded() ? $x->display('name') : 'No Title';
	}
}
?>
