<?php
/**
* @version	$Id: shipping_quote_collector.php 16640 2020-12-11 09:22:49Z alex $
* @package	In-Commerce
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license	Commercial License
* This software is protected by copyright law and international treaties.
* Unauthorized reproduction or unlicensed usage of the code of this program,
* or any portion of it may result in severe civil and criminal penalties,
* and will be prosecuted to the maximum extent possible under the law
* See http://www.in-portal.org/commercial-license for copyright notices and details.
*/

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

class ShippingQuoteCollector extends ShippingQuoteEngine {

	function GetShippingQuotes($params)
	{
		/** @var kCountryStatesHelper $cs_helper */
		$cs_helper = $this->Application->recallObject('CountryStatesHelper');
		$has_states = $cs_helper->CountryHasStates($params['dest_country']);

		if (
			!$params['dest_city'] || !$params['dest_country'] ||
			($has_states && !$params['dest_state']) ||
			!$params['dest_postal'] || !$params['packages']
		) {
			return Array ();
		}

		$cached_var_name = 'ShippingQuotes' . crc32(serialize($params));

		$shipping_types = $this->Application->getDBCache($cached_var_name);

		if ($shipping_types) {
			return unserialize($shipping_types);
		}

		$quotes_valid = true;
		$shipping_types = Array();
		$classes = $this->getEngineClasses();

		foreach ($classes as $class) {
			/** @var ShippingQuoteEngine $object */
			$object = $this->Application->recallObject($class);

			$new_shipping_types = $object->GetShippingQuotes($params);

			if (is_array($new_shipping_types)) {
				$shipping_types = array_merge($shipping_types, $new_shipping_types);
			}
			else {
				$quotes_valid = false;
			}
		}

		uasort($shipping_types, Array(&$this, 'price_sort'));

		// exclude not available shipping quotes by products
		$limit_types = unserialize($params['limit_types']);

		if ( is_array($limit_types) && count($limit_types) && !in_array('ANY', $limit_types) ) {
			$shipping_types = $this->applyLimitations($shipping_types, $limit_types);
		}

		// exclude Selected Products Only shipping types, not matching products
		$available_types = Array();

		foreach ($shipping_types as $a_type) {
			if (getArrayValue($a_type, 'SelectedOnly')) {
				if (!is_array($limit_types) || !in_array($a_type['ShippingId'], $limit_types)) {
					continue;
				}
			}

			$available_types[ $a_type['ShippingId'] ] = $a_type;
		}

		$shipping_types = $available_types;

		if ($quotes_valid) {
			$this->Application->setDBCache($cached_var_name, serialize($shipping_types), 24 * 3600);
		}

		return $shipping_types;
	}

	/**
	 * Applies limitations to shipping types
	 *
	 * @param array $shipping_types Shipping types.
	 * @param array $limit_types    Limit types.
	 *
	 * @return array
	 */
	protected function applyLimitations(array $shipping_types, array $limit_types)
	{
		$available_types = array();

		foreach ( $shipping_types as $a_type ) {
			$include = false; // Exclude by default.

			foreach ( $limit_types as $limit ) {
				$include = $include || preg_match('/^' . $limit . '/', $a_type['ShippingId']);

				if ( $include ) {
					break;
				}
			}

			if ( !$include ) {
				continue;
			}

			$available_types[$a_type['ShippingId']] = $a_type;
		}

		return $available_types;
	}

	function GetAvailableShippingTypes()
	{
		$shipping_types = Array ();
		$classes = $this->getEngineClasses();

		foreach ($classes as $class) {
			/** @var ShippingQuoteEngine $object */
			$object = $this->Application->recallObject($class);

			$new_shipping_types = $object->GetAvailableTypes();
			$shipping_types = array_merge($shipping_types, $new_shipping_types);
		}

		uasort($shipping_types, Array(&$this, 'SortShippingTypes'));

		return $shipping_types;
	}

	/**
	 * Returns all enabled shipping quote engine classes
	 *
	 * @return Array
	 */
	function getEngineClasses()
	{
		$sql = 'SELECT Classname
				FROM ' . $this->Application->getUnitOption('sqe', 'TableName') . '
				WHERE Status = ' . STATUS_ACTIVE;
		$classes = $this->Conn->GetCol($sql);

		// always persists
		$classes[] = 'CustomShippingQuoteEngine';

		return $classes;
	}

	/**
	 * Returns shipping quote engine, that matches shipping type used in order
	 *
	 * @param Array $shipping_info
	 * @param int $package_num
	 * @return ShippingQuoteEngine
	 */
	function &GetClassByType($shipping_info, $package_num = 1)
	{
		if ( !$shipping_info || !array_key_exists($package_num, $shipping_info) ) {
			return false;
		}

		$classes = $this->getEngineClasses();
		$shipping_id = $shipping_info[$package_num]['ShippingId'];

		foreach ($classes as $class) {
			/** @var ShippingQuoteEngine $object */
			$object = $this->Application->recallObject($class);

			$shipping_types = $object->GetAvailableTypes();

			foreach ($shipping_types as $index => $shipping_type) {
				if ( preg_match('/^' . preg_quote($shipping_type['_Id'], '/') . '/', $shipping_id) ) {
					return $class;
				}
			}
		}

		return false;
	}

	function SortShippingTypes($elem1, $elem2)
	{
		if ($elem1['_Name'] == $elem2['_Name']) {
			return 0;
		}

		return $elem1['_Name'] < $elem2['_Name'] ? -1 : 1;
	}

	function price_sort($elem1, $elem2)
	{
		if ($elem1['TotalCost'] == $elem2['TotalCost']) {
			return 0;
		}

		return $elem1['TotalCost'] < $elem2['TotalCost'] ? -1 : 1;
	}
}