<?php
/**
* @version	$Id: intershipper.php 16516 2017-01-20 14:12:22Z 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 Intershipper extends ShippingQuoteEngine {

	var $state = Array();
	var $quote = Array();
	var $quotes = Array();
	var $package_id;
	var $box_id;
	var $shipment_id;

	var $FlatSurcharge = 0;
	var $PercentSurcharge = 0;

	function _stripTags($params)
	{
		foreach ($params as $param_name => $param_value) {
			if (is_array($param_value)) {
				$params[$param_name] = $this->_stripTags($param_value);
			}
			else {
				$params[$param_name] = strip_tags($param_value);
			}
		}

		return $params;
	}

	function BuildUrl($params = null)
	{
		$params = $this->_stripTags($params);

		$this->shipment_id = isset($params['shipment_id']) ? $params['shipment_id'] : $this->GenerateId();
		$url = 'www.intershipper.com/Interface/Intershipper/XML/v2.0/HTTP.jsp';
		$uri =	'Username='.			$params['AccountLogin'].
				'&Password='.			$params['AccountPassword'].
				'&Version='.			'2.0.0.0'.
				'&ShipmentID='.			$this->shipment_id.
				'&QueryID='.			$this->shipment_id.
				'&TotalCarriers='.		count($params['carriers']);

		$i = 0;
		foreach($params['carriers'] as $carrier)
		{
			$i++;
			$uri .= '&CarrierCode'.$i.'='.	kUtil::escape($carrier['name'], kUtil::ESCAPE_URL).
			'&CarrierAccount'.$i.'='.		kUtil::escape($carrier['account'], kUtil::ESCAPE_URL).
			'&CarrierInvoiced'.$i.'='.		$carrier['invoiced'];
		}

		$uri .= '&TotalClasses='.	count($params['classes']);
		$i = 0;
		foreach($params['classes'] as $class)
		{
			$i++;
			$uri .= '&ClassCode'.$i.'='.	$class;
		}
		$uri .= '&DeliveryType='.	'COM'.
			'&ShipMethod='.			$params['ShipMethod'].

			'&OriginationName='.	kUtil::escape( $params['orig_name'], kUtil::ESCAPE_URL ).
			'&OriginationAddress1='.kUtil::escape( $params['orig_addr1'], kUtil::ESCAPE_URL ).
			'&OriginationAddress2='.kUtil::escape( $params['orig_addr2'], kUtil::ESCAPE_URL ).
			'&OriginationCity='.	kUtil::escape( $params['orig_city'], kUtil::ESCAPE_URL ).
			'&OriginationState='.	kUtil::escape( $params['orig_state'], kUtil::ESCAPE_URL ).
			'&OriginationPostal='.	kUtil::escape( $params['orig_postal'], kUtil::ESCAPE_URL ).
			'&OriginationCountry='.	kUtil::escape( $params['orig_country'], kUtil::ESCAPE_URL ).

			'&DestinationName='.	kUtil::escape( $params['dest_name'], kUtil::ESCAPE_URL ).
			'&DestinationAddress1='.kUtil::escape( $params['dest_addr1'], kUtil::ESCAPE_URL ).
			'&DestinationAddress2='.kUtil::escape( $params['dest_addr2'], kUtil::ESCAPE_URL ).
			'&DestinationCity='.	kUtil::escape( $params['dest_city'], kUtil::ESCAPE_URL ).
			'&DestinationState='.	kUtil::escape( $params['dest_state'], kUtil::ESCAPE_URL ).
			'&DestinationPostal='.	kUtil::escape( $params['dest_postal'], kUtil::ESCAPE_URL ).
			'&DestinationCountry='.	kUtil::escape( $params['dest_country'], kUtil::ESCAPE_URL ).

			'&Currency='.			'USD'.
			'&TotalPackages='.		count($params['packages']);

		$i = 0;
		foreach($params['packages'] as $package)
		{
			$i++;
			$uri .=	'&BoxID'.$i.'='.	kUtil::escape( $package['package_key'] , kUtil::ESCAPE_URL ).
			'&Weight'.$i.'='.			$package['weight'].
			'&WeightUnit'.$i.'='.		$package['weight_unit'].
			'&Length'.$i.'='.			$package['length'].
			'&Width'.$i.'='.			$package['width'].
			'&Height'.$i.'='.			$package['height'].
			'&DimensionalUnit'.$i.'='.	$package['dim_unit'].
			'&Packaging'.$i.'='.		$package['packaging'].
			'&Contents'.$i.'='.			$package['contents'].
			'&Insurance'.$i.'='.		$package['insurance'];
		}

		return Array('url' => $url, 'uri' => $uri);
	}

	function MergeParams($custom_params)
	{
		$params = $this->LoadParams();

		$this->FlatSurcharge = $params['FlatSurcharge'];
		$this->PercentSurcharge = $params['PercentSurcharge'];

		if($custom_params['carriers'])
		{
			$params['carriers'] = $custom_params['carriers'];
		}
		else
		{
			$carrier_codes = Array('UPS', 'FDX', 'DHL', 'USP', 'ARB');
			$i = 0;
			foreach($carrier_codes as $carrier)
			{
				if(isset($params[$carrier.'Enabled']) && $params[$carrier.'Enabled'])
				{
					$i++;
					$params['carriers'][$i]['name'] = $carrier;
					$params['carriers'][$i]['account'] = $params[$carrier.'Account'];
					$params['carriers'][$i]['invoiced'] = (int) $params[$carrier.'Invoiced'];
				}
			}
		}

		if($custom_params['classes'])
		{
			$params['classes'] = $custom_params['classes'];
		}
		else
		{
			$classes = Array('1DY', '2DY', '3DY', 'GND');
			foreach($classes as $class)
			{
				if(isset($params[$class.'Enabled']) && $params[$class.'Enabled'])
				{
					$params['classes'][] = $class;
				}
			}
		}

		if (isset($custom_params['orig_addr1'])) {
			$params['orig_name']		=	$custom_params['orig_name'];
			$params['orig_addr1']		=	$custom_params['orig_addr1'];
			$params['orig_addr2']		=	$custom_params['orig_addr2'];
			$params['orig_city']		=	$custom_params['orig_city'];
			$params['orig_state']		=	$custom_params['orig_state'];
			$params['orig_postal']		=	$custom_params['orig_postal'];
			$params['orig_country']		=	$custom_params['orig_country'];
		}
		else {
			$params['orig_name']		=	$this->Application->ConfigValue('Comm_StoreName');
			$params['orig_addr1']		=	$this->Application->ConfigValue('Comm_Shipping_AddressLine1');
			$params['orig_addr2']		=	$this->Application->ConfigValue('Comm_Shipping_AddressLine2');
			$params['orig_city']		=	$this->Application->ConfigValue('Comm_Shipping_City');
			$params['orig_state']		=	$this->Application->ConfigValue('Comm_Shipping_State');
			$params['orig_postal']		=	$this->Application->ConfigValue('Comm_Shipping_ZIP');
			$params['orig_country']		=	$this->Application->ConfigValue('Comm_Shipping_Country');
		}

		/** @var kCountryStatesHelper $cs_helper */
		$cs_helper = $this->Application->recallObject('CountryStatesHelper');

		if (strlen($params['orig_country']) == 3) {
			// got 3symbol ISO code -> resolve to 2symbol ISO code
			$params['orig_country'] = $cs_helper->getCountryIso( $params['orig_country'] );
		}

		if (strlen($params['orig_state']) != 2) {
			// got state name instead of ISO code -> resolve it to ISO code
			$country_iso = $cs_helper->getCountryIso($params['orig_country'], true);
			$params['orig_state'] = $cs_helper->getStateIso($params['orig_state'], $country_iso);
		}

		if (isset($custom_params['ShipMethod'])) {
			$params['ShipMethod']	=	$custom_params['ShipMethod'];
		}

		$params['packages']			=	$custom_params['packages'];

		$params['dest_name']		=	$custom_params['dest_name'];
		$params['dest_addr1']		=	$custom_params['dest_addr1'];
		$params['dest_addr2']		=	$custom_params['dest_addr2'];
		$params['dest_city']		=	$custom_params['dest_city'];
		$params['dest_state']		=	$custom_params['dest_state'];
		$params['dest_postal']		=	$custom_params['dest_postal'];
		$params['dest_country']		=	$custom_params['dest_country'];

		if (strlen($params['dest_country']) == 3) {
			// got 3symbol ISO code -> resolve to 2symbol ISO code
			$params['dest_country'] = $cs_helper->getCountryIso( $params['dest_country'] );
		}

		if(!$params['dest_city'] || !$params['dest_country'] ||
				(($params['dest_country'] == 'US' || $params['dest_country'] == 'CA') && !$params['dest_state']) ||
				!$params['dest_postal'] || !$params['packages'])
		{
			$valid = false;
		}
		else
		{
			$valid = true;
		}

		return $valid ? $params : false;
	}

	function GenerateId()
	{
		static $id;
		if(!$id)
		{
			$id = rand(0, 1000000);
		}
		return $id;
	}

	function getShipmentId()
	{
		return $this->shipment_id;
	}

	function GetShippingQuotes($params = null)
	{
		if(!is_array($params)) $params = unserialize($params);
		$params = $this->MergeParams($params);

		if($params == false)
		{
			trigger_error('Incorrect params given to <em>intershipper</em> engine', E_USER_WARNING);
			return;
		}

		$target_url = $this->BuildUrl($params);
		// print_r($target_url);

		$depth = Array();

		$xml_parser = xml_parser_create();
		xml_set_element_handler( $xml_parser, Array(&$this, 'startElement'), Array(&$this, 'endElement') );
		xml_set_character_data_handler( $xml_parser, Array(&$this, 'characterData') );

		/** @var kCurlHelper $curl_helper */
		$curl_helper = $this->Application->recallObject('CurlHelper');

		$curl_helper->SetPostData($target_url['uri']);
		$newdata = $curl_helper->Send($target_url['url']);

 		$newdata = substr($newdata, strpos($newdata, '<'));

		if (!xml_parse($xml_parser, $newdata, 1)) {
    	    trigger_error(sprintf('XML error: %s at line %d'),
			xml_error_string(xml_get_error_code($xml_parser)),
			xml_get_current_line_number($xml_parser), E_USER_WARNING);
		}

		xml_parser_free($xml_parser);

		return array_shift($this->quotes);		// array_shift must be removed after!!!
	}

	function startElement(&$Parser, &$Elem, $Attr)
	{
		array_push($this->state, $Elem);
		$states = implode(' ',$this->state);
		//check what state we are in
		if($states == 'SHIPMENT PACKAGE') {
			$this->package_id = $Attr['ID'];
		}
		elseif($states == 'SHIPMENT PACKAGE QUOTE') {
			$quote = Array('package_id' => $this->package_id, 'id' => $Attr['ID']);
		}
	}

	function characterData($Parser, $Line)
	{
		$states = join (' ',$this->state);
		switch($states)
		{
			case 'SHIPMENT ERROR':
				trigger_error($error = $Line, E_USER_WARNING);
			break;
			case 'SHIPMENT SHIPMENTID':
				$this->shipment_id = $Line;
			break;
			case 'SHIPMENT PACKAGE BOXID':
				$this->box_id = $Line;
			break;
		  	case 'SHIPMENT PACKAGE QUOTE CARRIER NAME':
				$this->quote['carrier_name'] = $Line;
			break;
			case 'SHIPMENT PACKAGE QUOTE CARRIER CODE':
				$this->quote['carrier_code'] = $Line;
			break;
			case 'SHIPMENT PACKAGE QUOTE CLASS NAME':
				$this->quote['class_name'] = $Line;
			break;
			case 'SHIPMENT PACKAGE QUOTE CLASS CODE':
				$this->quote['class_code'] = $Line;
			break;
			case 'SHIPMENT PACKAGE QUOTE SERVICE NAME':
				$this->quote['service_name'] = $Line;
			break;
			case 'SHIPMENT PACKAGE QUOTE SERVICE CODE':
				$this->quote['service_code'] = $Line;
			break;
			case 'SHIPMENT PACKAGE QUOTE RATE AMOUNT':
				$this->quote['amount'] = $Line / 100;
			break;
			default:
		}
	}

	function endElement($Parser, $Elem)
	{
		$states = implode(' ',$this->state);
		if ($states == 'SHIPMENT PACKAGE QUOTE') {
			unset($this->quote['id']);
			unset($this->quote['package_id']);
			// the $key is a combo of the carrier_code and service_code
			// this is the logical way to key each quote returned

			$this->quote['amount'] = $this->quote['amount']*(1+$this->PercentSurcharge/100) + $this->FlatSurcharge;

			$amount_plain = $this->quote['amount'] * 100;
			$key = 'INTSH_'.$this->quote['carrier_code'].'_'.$this->quote['class_code'].'_'.$amount_plain;
			$this->quote['ShippingId'] = $key;
			$this->quote['ShippingName'] = $this->quote['carrier_code'].' - '.$this->quote['service_name'];
			$this->quote['TotalCost'] = $this->quote['amount'];
			$this->quotes[$this->box_id][$key] = $this->quote;

		}
		array_pop($this->state);
	}

	function LoadParams()
	{
		$sql = 'SELECT Properties, FlatSurcharge, PercentSurcharge FROM '.$this->Application->getUnitOption('sqe', 'TableName').'
				WHERE Name="Intershipper.com"';
		$data = $this->Conn->GetRow($sql);

		$params = unserialize(getArrayValue($data, 'Properties'));
		return array_merge($params, array('FlatSurcharge' => $data['FlatSurcharge'], 'PercentSurcharge' => $data['PercentSurcharge']));
	}

	function GetAvailableTypes()
	{
		$params = $this->LoadParams();

		$carrier_codes = Array('UPS', 'FDX', 'DHL', 'USP', 'ARB');
		$classes = Array('1DY', '2DY', '3DY', 'GND');
		$i = 0;
		foreach($carrier_codes as $carrier)
		{
			if(isset($params[$carrier.'Enabled']) && $params[$carrier.'Enabled'])
			{
				foreach($classes as $class)
				{
					if(isset($params[$class.'Enabled']) && $params[$class.'Enabled'])
					{
						$a_type['_ClassName'] = get_class($this);
						$a_type['_Id'] = 'INTSH_'.$carrier.'_'.$class;
						$a_type['_Name'] = '(Intershipper) '.$carrier.' '.$class;
						$ret[] = $a_type;
					}
				}
			}
		}
		return $ret;
	}

	/**
	 * Returns virtual field names, that will be saved as properties
	 *
	 * @return Array
	 */
	function GetEngineFields()
	{
		return Array (
			'AccountLogin',
			'UPSEnabled', 'UPSAccount', 'UPSInvoiced', 'FDXEnabled', 'FDXAccount', 'FDXInvoiced',
			'DHLEnabled', 'DHLAccount', 'DHLInvoiced', 'USPEnabled', 'USPAccount', 'USPInvoiced',
			'ARBEnabled', 'ARBAccount', 'ARBInvoiced', '1DYEnabled', '2DYEnabled', '3DYEnabled',
			'GNDEnabled', 'ShipMethod',
		);
	}
}

/*$params = Array(
	'AccountLogin'		=>	'login',
	'AccountPassword'	=>	'password',
	'carriers'	=>	Array(
						Array(
							'name'		=>	'UPS',
							'account'	=>	'',
							'invoiced'	=>	'0'
						),
						Array(
							'name'		=>	'DHL',
							'account'	=>	'',
							'invoiced'	=>	'0'
						),
						Array(
							'name'		=>	'FDX',
							'account'	=>	'',
							'invoiced'	=>	'0'
						),
						Array(
							'name'		=>	'USP',
							'account'	=>	'',
							'invoiced'	=>	'0'
						),
						Array(
							'name'		=>	'ARB',
							'account'	=>	'',
							'invoiced'	=>	'0'
						),
					),
	'classes'		=>	Array('1DY', '2DY', '3DY', 'GND'),

	'ShipMethod'	=>	'DRP',

	'orig_name'		=>	'John%20Smith',
	'orig_addr1'	=>	'2275%20Union%20Road',
	'orig_city'		=>	'Cheektowaga',
	'orig_state'	=>	'NY',
	'orig_postal'	=>	'14227',
	'orig_country'	=>	'US',

	// this section is required
	'dest_name'		=>	'Vasya%20Pupkin',
	'dest_addr1'	=>	'175%20E.Hawthorn%20pkwy.',
	'dest_city'		=>	'Vernon%20Hills',
	'dest_state'	=>	'IL',
	'dest_postal'	=>	'60061',
	'dest_country'	=>	'US',

	// this section is required
	'packages' 		=>	Array(
		Array(
			'package_key'	=>	'package1',
			'weight'		=>	'50',
			'weight_unit'	=>	'LB',
			'length'		=>	'25',
			'width'			=>	'15',
			'height'		=>	'15',
			'dim_unit'		=>	'IN',
			'packaging'		=>	'BOX',
			'contents'		=>	'OTR',
			'insurance'		=>	'0'
		),
		Array(
			'package_key'	=>	'package2',
			'weight'		=>	'50',
			'weight_unit'	=>	'LB',
			'length'		=>	'25',
			'width'			=>	'15',
			'height'		=>	'15',
			'dim_unit'		=>	'IN',
			'packaging'		=>	'BOX',
			'contents'		=>	'OTR',
			'insurance'		=>	'0'
		),
	),

	'shipment_id'	=>	1234;
);
*/

/*

Returns:

$quotes = Array(
	'package1'	=>
		Array(
			Array(
				'id'	=>	'INTSH_FDX_2DY',
				'type' => 'FDX',
				..
				'amount' =>	24.24,
			)
			Array(
				'type' => 'FDX',
				..
				'amount' =>	24.24,
			)
		),
	'package2'	=>
		Array(
			Array(
				'id'	=>	'INTSH_FDX_3DY',
				'type' => 'FDX',
				..
				'amount' =>	24.24,
			)
			Array(
				'type' => 'FDX',
				..
				'amount' =>	24.24,
			)
		),
	)
*/