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

/**
 * This class supports ADSL products
 *
 * @package    ADSL
 * @category   Models
 * @author     Deon George
 * @copyright  (c) 2009-2013 Open Source Billing
 * @license    http://dev.osbill.net/license.html
 */
class Model_Product_Plugin_Adsl extends Model_Product_Plugin {
	protected $_table_name = 'adsl_plan';

	// We dont use the update column
	protected $_updated_column = FALSE;

	// Relationships
	protected $_belongs_to = array(
		'supplier_plan'=>array('model'=>'ADSL_Supplier_Plan','foreign_key'=>'adsl_supplier_plan_id'),
	);

	/**
	 * Filters used to format the display of values into friendlier values
	 */
	protected $_display_filters = array(
		'extra_down_peak'=>array(
			array('Tax::add',array(':value')),
			array('Currency::display',array(':value')),
		),
		'extra_down_offpeak'=>array(
			array('Tax::add',array(':value')),
			array('Currency::display',array(':value')),
		),
		'extra_up_peak'=>array(
			array('Tax::add',array(':value')),
			array('Currency::display',array(':value')),
		),
		'extra_up_offpeak'=>array(
			array('Tax::add',array(':value')),
			array('Currency::display',array(':value')),
		),
		'extra_charged'=>array(
			array('StaticList_YesNo::get',array(':value',TRUE)),
		),
	);

	protected $_nullifempty = array(
		'base_down_peak',
		'base_down_offpeak',
		'base_up_peak',
		'base_up_offpeak',
		'extra_down_peak',
		'extra_down_offpeak',
		'extra_up_peak',
		'extra_up_offpeak',
	);

	// Our required abstract methods

	public function cost($annual=FALSE) {
		$x = $this->supplier_plan->display('base_cost');

		return $annual ? $x*12 : $x;
	}

	// @todo Select the ADSL Plan for this product.
	public function render_edit() {
		return '';
	}

	public function supplier() {
		return $this->supplier_plan->supplier_id;
	}

	// Local functions

	// Map the table fields
	private $_map = array(
		'base_up_offpeak'=>'extra_up_offpeak',
		'base_down_offpeak'=>'extra_down_offpeak',
		'base_up_peak'=>'extra_up_peak',
		'base_down_peak'=>'extra_down_peak',
	);

	/**
	 * Calculate the allowance array or traffic used array
	 *
	 * If:
	 *
	 *   + UPLOADS are charged and there are no PEAK/OFFPEAK periods (therefore all
	 *     traffic is charged), the allowance will be shown as 1 metric - TRAFFIC.
	 *   + UPLOADS are charged and there are PEAK/OFFPEAK periods the allowance
	 *     will be shown as 2 metrics - PEAK/OFFPEAK.
	 *   + UPLOADS are NOT charged and there are no PEAK/OFFPEAK periods the allowance
	 *     will be shown as 1 metrics - TRAFFIC.
	 *   + UPLOADS are NOT charged and there are PEAK/OFFPEAK periods the allowance
	 *     will be shown as 2 metrics - PEAK/OFFPEAK.
	 *
	 * Thus:
	 *
	 *   + If base_x_Y is NULL, all Y traffic is FREE (ignore respective extra_x_Y setting).
	 *   + If base_x_Y is a number, all Y traffic is FREE up to the number (evaluate extra_x_Y setting).
	 *   + If extra_x_Y is a number, charge this amount for traffic over base_x_Y.
	 *   + If extra_down_peak is NULL this is invalid, treat base_down_peak as NULL
	 *   + If extra_down_offpeak is NULL add traffic_down_offpeak to traffic_down_peak
	 *   + If extra_up_peak is NULL add traffic_up_peak to traffic_down_peak
	 *   + If extra_up_offpeak is NULL add traffic_up_offpeak to traffic_down_offpeak
	 *
	 * @param array Traffic Used in each metric.
	 * @param bool Whether the output should be a string
	 * @param bool Display the over allowance numbers
	 * @param int Divide the numbers
	 */
	public function allowance(array $data=array(),$format=FALSE,$over=FALSE,$ceil=FALSE) {
		$result = $x = array();

		// Do we invert the result - showing allowance
		$invert = $data ? FALSE : TRUE;

		// Map the NULL relationships
		$merge = array(
			'extra_up_offpeak'=>'base_down_offpeak',
			'extra_down_offpeak'=>'base_down_peak',
			'extra_up_peak'=>'base_down_peak',
			'extra_down_peak'=>'base_down_peak',
		);

		// Work out if we charge each period
		foreach ($this->_map as $k => $v) {
			// Anything NULL is not counted
			if (is_null($this->{$k}))
				continue;

			if (! isset($data[$k]))
				$data[$k] = 0;

			if ($over) {
				// @todo This is an ugly hack - if our data has been passed it, it is assumed it has been reduced by $this->metric
				$z = $this->metric ? round($this->{$k}/$this->metric,2) : $this->{$k};

				$data[$k] = $invert ? $z : $data[$k]-$z;

				// We need to return this back to base units as later, we'll return it back to metric
				$data[$k] = $this->metric ? $data[$k]*$this->metric : $data[$k];
			}

			// Do we charge for extra, or merge it to another field
			if (! is_null($this->{$v})) {
				if (isset($x[$k]))
					$x[$k] += $data[$k];
				else
					$x[$k] = $data[$k];

			} else {
				if (isset($x[$merge[$v]])) {
					$x[$merge[$v]] += $data[$k];

				} else {
					$x[$merge[$v]] = $data[$k];

					// If we had any data already in A for this merge, we'll need to add it too.
					if (isset($x[$k])) {
						$x[$merge[$v]] += $x[$k];

						unset($x[$k]);
					}
				}
			}
		}

		// Return the output sorted
		foreach (array_keys(Model_Service_Plugin_Adsl_Traffic::$metrics) as $k) {
			$k = 'base_'.$k;

			if (isset($x[$k])) {
				$result[$k] = $this->metric ? round($x[$k]/$this->metric,2) : $x[$k];

				if ($ceil)
					$result[$k] = ceil($result[$k]);
			}
		}

		return $format ? join('/',array_values($result)) : $result;
	}

	public function cost_extra(array $data=array(),$format=FALSE) {
		$result = array();

		foreach ($this->allowance($data) as $k => $v)
			$result[$k] = $format ? $this->display($this->_map[$k]) : $this->{$this->_map[$k]};

		return $format ? join('/',array_values($result)) : $result;
	}

	public function hasOffpeak() {
		if ((($this->base_down_offpeak || $this->base_down_offpeak == 0) AND (! is_null($this->extra_down_offpeak)))
			OR (($this->base_up_offpeak || $this->base_up_offpeak == 0) AND (! is_null($this->extra_up_offpeak))))

			return TRUE;
	}
}
?>
