<?php
/**
* @version	$Id: brackets_helper.php 15145 2012-03-04 09:04:08Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class kBracketsHelper extends kHelper {

		/**
		 * Field name holding minimal amount
		 *
		 * @var string
		 */
		var $min_field = '';

		/**
		 * Field name holding maximal amount
		 *
		 * @var string
		 */
		var $max_field = '';

		/**
		 * Default values to be set to automtically created price brackets
		 *
		 * @var Array
		 */
		var $default_values = Array();

		var $defaultStartValue = 1;

		/**
		 * Decimal separator
		 *
		 * @var string
		 */
		var $_decimalSeparator = '';

		/**
		 * Thousands separator
		 *
		 * @var string
		 */
		var $_thousandsSeparator = '';

		/**
		 * Current language
		 *
		 * @var LanguagesItem
		 */
		var $_language = null;

		public function __construct()
		{
			parent::__construct();

			$this->_language = $this->Application->recallObject('lang.current');
			/* @var $lang kDBItem */

			$this->_decimalSeparator = $this->_language->GetDBField('DecimalPoint');
			$this->_thousandsSeparator = $this->_language->GetDBField('ThousandSep');
		}

		function InitHelper($min_field, $max_field, $default_values, $default_start_value = null)
		{
			$this->min_field = $min_field;
			$this->max_field = $max_field;
			$this->default_values = $default_values;

			if (isset($default_start_value)) {
				$this->defaultStartValue = $default_start_value;
			}
		}

		/**
		 * Converts number to operatable form
		 *
		 * @param string $value
		 * @return float
		 */
		function _parseNumber($value)
		{
			$value = str_replace($this->_thousandsSeparator, '', $value);
			$value = str_replace($this->_decimalSeparator, '.', $value);

			return $value;
		}

		/**
		 * Returns brackets from form with all numbers parsed
		 *
		 * @param kEvent $event
		 * @return Array
		 */
		function getBrackets($event)
		{
			$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );

			return $this->parseBrackets($items_info);
		}

		function parseBrackets($brackets)
		{
			if (!$brackets) {
				return $brackets;
			}

			foreach ($brackets as $id => $field_values) {
				if (strlen($brackets[$id][$this->min_field])) {
					$brackets[$id][$this->min_field] = (float)$this->_parseNumber($brackets[$id][$this->min_field]);
				}

				if (strlen($brackets[$id][$this->max_field])) {
					$brackets[$id][$this->max_field] = (float)$this->_parseNumber($brackets[$id][$this->max_field]);
				}
			}

			return $brackets;
		}

		/**
		 * Formats given brackets and sets them back to request
		 *
		 * @param kEvent $event
		 * @param Array $brackets
		 */
		function setBrackets($event, $brackets)
		{
			$brackets = $this->formatBrackets($brackets);

			$this->Application->SetVar($event->getPrefixSpecial(true), $brackets);
		}

		function formatBrackets($brackets)
		{
			if (!$brackets) {
				return $brackets;
			}

			foreach ($brackets as $id => $field_values) {
				if (strlen($brackets[$id][$this->min_field])) {
					$brackets[$id][$this->min_field] = $this->_language->formatNumber($brackets[$id][$this->min_field]);
				}

				if (strlen($brackets[$id][$this->max_field])) {
					$brackets[$id][$this->max_field] = $this->_language->formatNumber($brackets[$id][$this->max_field]);
				}
			}

			return $brackets;
		}

		/**
		 * Adds 5 more empty brackets to brackets
		 *
		 * @param kEvent $event
		 */
		function OnMoreBrackets($event)
		{
			$field_values = $this->getBrackets($event);

			$object = $event->getObject();

			foreach($field_values as $id => $record)
			{
				if($record[$this->max_field] == '&#8734;') $field_values[$id][$this->max_field] = -1;
			}

			$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$object->IDField.') FROM '.$object->TableName);
			if($new_id > 0) $new_id = 0;
			do
			{
				$new_id--;
			}while( $this->arraySearch($field_values, $object->IDField, $new_id) );


			$last_max_qty = $this->Conn->GetOne('SELECT MAX('.$this->max_field.') FROM '.$object->TableName);
			$min_qty = $this->Conn->GetOne('SELECT MIN('.$this->max_field.') FROM '.$object->TableName);

			if($min_qty == -1) $last_max_qty = -1;
			if(!$last_max_qty) $last_max_qty = $this->defaultStartValue;


			for($i = $new_id; $i > $new_id - 5; $i--)
			{
				$field_values[$i][$object->IDField] = $i;
				$field_values[$i][$this->min_field] = ($i == $new_id-4 && $last_max_qty != -1) ? $last_max_qty : '';
				$field_values[$i][$this->max_field] = ($i == $new_id-4 && $last_max_qty != -1) ? -1 : '';
				$field_values[$i] = array_merge($field_values[$i], $this->default_values);
			}

			$event->CallSubEvent('OnPreSaveBrackets');

			$this->setBrackets($event, $field_values);
		}

		/**
		 * Adds infinity bracket
		 *
		 * @param kEvent $event
		 */
		function OnInfinity($event)
		{
			$object = $event->getObject();
			$infinite_exists = $this->Conn->GetOne('SELECT COUNT(*) FROM '.$object->TableName.' WHERE '.$this->max_field.' = -1');
			$field_values = $this->getBrackets($event);
			/*if(is_array($field_values))
			{
				foreach($field_values as $values)
				{
					$infinite_exists = $infinite_exists || ($values[$this->max_field] == -1);
				}
			}*/

			if ($infinite_exists == 0) {
				reset($field_values);
				$last_bracket = end($field_values);
				$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$object->IDField.') FROM '.$object->TableName);

				$brackets_exist = (int)$this->Conn->GetOne('SELECT COUNT(*) FROM '.$object->TableName);

				if($new_id > 0) $new_id = 0;
				do
				{
					$new_id--;
				}while( $this->arraySearch($field_values, $object->IDField, $new_id) );

				$infinite_bracket[$object->IDField] = $new_id;
				$infinite_bracket[$this->min_field] = ($brackets_exist > 0) ? $last_bracket[$this->max_field] : $this->defaultStartValue;
				$infinite_bracket[$this->max_field] = '-1';
				$infinite_bracket = array_merge($infinite_bracket, $this->default_values);

				$field_values[$new_id] = $infinite_bracket;
				reset($field_values);

				$this->setBrackets($event, $field_values);
			}
		}

		/**
		 * Saves brackets to database
		 *
		 * @param kEvent $event
		 */
		function OnPreSaveBrackets($event)
		{
			$items_info = $this->getBrackets($event);
			if ($items_info) {
				$object = $event->getObject();
				/* @var $object kDBItem */

				$linked_info = $object->getLinkedInfo();
				$stored_ids = $this->Conn->GetCol('SELECT '.$object->IDField.' FROM '.$object->TableName.' WHERE '.$linked_info['ForeignKey'].' = '.$linked_info['ParentId']);

				uasort($items_info, Array(&$this, 'compareBrackets') );

				foreach ($items_info as $item_id => $values) {

					if (in_array($item_id, $stored_ids)) { //if it's already exist
						$object->Load($item_id);
						$object->SetFieldsFromHash($values/*, $this->getRequestProtectedFields($values)*/);
						if (!$object->Validate()) {
							unset($stored_ids[array_search($item_id, $stored_ids)]);
							$event->redirect = false;
							continue;
						}
						if( $object->Update($item_id) )
						{
							$event->status = kEvent::erSUCCESS;
						}
						else
						{
							$event->status = kEvent::erFAIL;
							$event->redirect = false;
							break;
						}
						unset( $stored_ids[ array_search($item_id, $stored_ids) ] );
					}
					else {
						$object->Clear();
						$object->SetFieldsFromHash($values/*, $this->getRequestProtectedFields($values)*/);
						$object->SetDBField($linked_info['ForeignKey'], $linked_info['ParentId']);

						if ($object->Create()) {
							$event->status = kEvent::erSUCCESS;
						}
					}
				}

				// delete
				foreach ($stored_ids as $stored_id)
				{
					$this->Conn->Query('DELETE FROM '.$object->TableName.' WHERE '.$object->IDField.' = '.$stored_id);
				}

			}
		}

		/**
		 * Sorts brackets and returns sorted array
		 *
		 * @param kEvent $event
		 * @return Array
		 */
		function arrangeBrackets($event)
		{
			$object = $event->getObject();
			/* @var $object kDBItem */

			$temp = $this->getBrackets($event);

			foreach ($temp as $id => $record) {
				if ( $record[$this->max_field] == '&#8734;' ) {
					$temp[$id][$this->max_field] = -1;
				}
			}

			$temp_orig = $temp;
			reset($temp);
			if( is_array($temp) )
			{
				// array to store max values (2nd column)
				$end_values = Array();

				// get minimal value of Min
				$first_elem = current($temp);
				$start = $first_elem[$this->min_field];
				if (!strlen($start)) {
					$start = $this->defaultStartValue;
				}

				foreach($temp as $id => $record)
				{
					if(
					// MAX is less than start
					($record[$this->max_field] <= $start && $record[$this->max_field] != -1) ||
					// Max is empty
					!strlen($record[$this->max_field]) ||
					// Max already defined in $end_values
					(array_search($record[$this->max_field], $end_values) !== false)
					) {	// then delete from brackets list
						unset($temp[$id]);
					}
					else {	// this is when ok - add to end_values list
						$end_values[] = $record[$this->max_field];
					}
				}

				// sort brackets by 2nd column (Max values)
				uasort($temp, Array (&$this, 'compareBrackets'));
				reset($temp);
				$first_item = each($temp);
				$first_item_key = $first_item['key'];

				$linked_info = $object->getLinkedInfo();
				$sql = 'SELECT %s FROM %s WHERE %s = %s';
				$ids = $this->Conn->GetCol( sprintf($sql, $object->IDField, $object->TableName, $linked_info['ForeignKey'], $linked_info['ParentId']) );

				if ( is_array($ids) ) {
					usort($ids, Array (&$this, 'sortBracketIDs'));
				}

//				$min_id = min( min($ids) - 1, -1 );

				foreach ($temp as $key => $record) {
					$temp[$key][$this->min_field] = $start;
					$start = $temp[$key][$this->max_field];
				}
			}

			$this->setBrackets($event, $temp);

			return $temp;
		}

		function compareBrackets($bracket1, $bracket2) // ap_bracket_comp
		{
			$bracket1_min = $bracket1[$this->min_field];
			$bracket1_max = $bracket1[$this->max_field];

			$bracket2_min = $bracket2[$this->min_field];
			$bracket2_max = $bracket2[$this->max_field];

			// limits
			if( ($bracket1_min != '') && ($bracket1_max == '') && ($bracket2_min != '') && ($bracket2_max != '') ) return 1;
			if( ($bracket1_min != '') && ($bracket1_max == '') && ($bracket2_min == '') && ($bracket2_max == '') ) return -1;
			if( ($bracket1_max == '') && ($bracket2_max != '') ) return 1;
			if( ($bracket1_max != '') && ($bracket2_max == '') ) return -1;


			if( ( ($bracket1_max > $bracket2_max) && ($bracket2_max != -1) ) || ( ($bracket1_max == -1) && ($bracket2_max != -1) ) )
			{
				return 1;
			}
			elseif( ($bracket1_max < $bracket2_max) || ( ($bracket2_max == -1) && ($bracket1_max != -1) ) )
			{
				return -1;
			}
			else
			{
				return 0;
			}
		}

		function sortBracketIDs($first_id, $second_id) // pr_bracket_id_sort
		{
			$first_abs = abs($first_id);
			$second_abs = abs($second_id);

			$first_sign = ($first_id == 0) ? 0 : $first_id / $first_abs;
			$second_sign = ($second_id == 0) ? 0 : $second_id / $second_abs;

			if($first_sign != $second_sign)
			{
				if($first_id > $second_id)
				{
					$bigger =& $first_abs;
					$smaller =& $second_abs;
				}
				else
				{
					$bigger =& $second_abs;
					$smaller =& $first_abs;
				}
				$smaller = $bigger + $smaller;
			}

			return ($first_abs > $second_abs) ? 1 : ($first_abs < $second_abs ? -1 : 0);
		}

		/**
		 * Searches through submitted grid data to find record with specific value in specific field
		 *
		 * @param Array $records // grid data from REQUEST
		 * @param string $field
		 * @param string $value
		 * @return bool
		 */
		function arraySearch($records, $field, $value) // check_array
		{
			foreach ($records as $record)
			{
				if ($record[$field] == $value)
				{
					return true;
				}
			}
			return false;
		}

		/**
		 * Replace infinity mark with -1 before saving to db
		 *
		 * @param kEvent $event
		 */
		function replaceInfinity($event)
		{
			$object = $event->getObject();
			/* @var $object kDBItem */

			if ( $object->GetDBField($this->max_field) == '&#8734;' ) {
				$object->SetDBField($this->max_field, -1);
			}
		}

	}