<?php
class USPS
{
	var $user_id;
	var $password;
	var $api;
	var $request_xml;
	var $package_index = 0;
	var $current_result = array();

	var $country_list = array(
	"Great Britain",
	"United States",
	"Afghanistan",
	"Albania",
	"Algeria",
	"Andorra",
	"Angola",
	"Anguilla",
	"Antigua and Barbadua",
	"Argentina",
	"Armenia",
	"Aruba",
	"Ascension",
	"Australia",
	"Austria",
	"Azerbaijan",
	"Bahamas",
	"Bahrain",
	"Bangladesh",
	"Barbados",
	"Belarus",
	"Belgium",
	"Belize",
	"Benin",
	"Bermuda",
	"Bhutan",
	"Bolivia",
	"Bosnia-Herzegovina",
	"Botswana",
	"Brazil",
	"British Virgin Islands",
	"Brunei Darussalam",
	"Bulgaria",
	"Burkina Faso",
	"Burma",
	"Burundi",
	"Cambodia",
	"Cameroon",
	"Canada",
	"Cape Verde",
	"Cayman Islands",
	"Central African Republic",
	"Chad",
	"Chile",
	"China",
	"Colombia",
	"Comoros",
	"Democratic Republic of the Congo",
	"Republic of the Congo",
	"Costa Rica",
	"Ivory Coast",
	"Croatia",
	"Cuba",
	"Cyprus",
	"Czech Republic",
	"Denmark",
	"Djibouti",
	"Dominica",
	"Dominican Republic",
	"Ecuador",
	"Egypt",
	"El Salvador",
	"Equitorial Guinea",
	"Eritrea",
	"Estonia",
	"Ethiopia",
	"Falkland Islands",
	"Faroe Islands",
	"Fiji",
	"Finland",
	"France",
	"French Guiana",
	"French Polynesia",
	"Gabon",
	"Gambia",
	"Republic of Georgia",
	"Germany",
	"Ghana",
	"Gibraltar",
	"Great Britain and Northern Ireland",
	"Greece",
	"Greenland",
	"Grenanda",
	"Guadeloupe",
	"Guatemala",
	"Guinea",
	"Guinea-Bissau",
	"Guyana",
	"Haiti",
	"Honduras",
	"Hong Kong",
	"Hungary",
	"Iceland",
	"India",
	"Indonesia",
	"Iran",
	"Iraq",
	"Ireland",
	"Israel",
	"Italy",
	"Jamaica",
	"Japan",
	"Jordan",
	"Kazakhstan",
	"Kenya",
	"Kiribati",
	"Democratic People's Republic of Korea",
	"Republic of Korea",
	"Kuwait",
	"Kyrgyzstan",
	"Laos",
	"Latvia",
	"Lebanon",
	"Lesotho",
	"Liberia",
	"Libya",
	"Liechtenstein",
	"Lithuania",
	"Luxembourg",
	"Macao",
	"Macedonia",
	"Madagascar",
	"Malawi",
	"Malaysia",
	"Maldives",
	"Mali",
	"Malta",
	"Martinique",
	"Mauritania",
	"Mauritius",
	"Mexico",
	"Moldova",
	"Mongolia",
	"Montserrat",
	"Morocco",
	"Mozambique",
	"Namibia",
	"Nauru",
	"Nepal",
	"Netherlands",
	"Netherlands Antilles",
	"New Caledonia",
	"New Zealand",
	"Nicaragua",
	"Niger",
	"Nigeria",
	"Norway",
	"Oman",
	"Pakistan",
	"Panama",
	"Papua New Guinea",
	"Paraguay",
	"Peru",
	"Philippines",
	"Pitcairn Island",
	"Poland",
	"Portugal",
	"Qatar",
	"Reunion",
	"Romania",
	"Russia",
	"Rwanda",
	"St. Christopher and Nevis",
	"St. Helena",
	"St. Lucia",
	"St. Pierre and Miquelon",
	"St. Vincent and the Grenadines",
	"San Marino",
	"Sao Tome and Principe",
	"Saudi Arabia",
	"Senegal",
	"Serbia-Montenegro",
	"Seychelles",
	"Sierra Leone",
	"Singapore",
	"Slovak Republic",
	"Slovenia",
	"Solomon Islands",
	"Somalia",
	"South Africa",
	"Spain",
	"Sri Lanka",
	"Sudan",
	"Suriname",
	"Swaziland",
	"Sweden",
	"Switzerland",
	"Syria",
	"Taiwan",
	"Tajikistan",
	"Tanzania",
	"Thailand",
	"Togo",
	"Tonga",
	"Trinidad and Tobago",
	"Tristan de Cunha",
	"Tunisia",
	"Turkey",
	"Turkmenistan",
	"Turks and Caicos Islands",
	"Tuvalu",
	"Uganda",
	"Ukraine",
	"United Arab Emirates",
	"Uruguay",
	"Uzbekistan",
	"Vanuatu",
	"Vatican City",
	"Venezuela",
	"Vietnam",
	"Wallis and Futuna Islands",
	"Western Samoa",
	"Yemen",
	"Zambia",
	"Zimbabwe");

	function debug($error){
	
		global $module;
		if($module['debug']==1) { echo $error; exit; }
	
	}

	function USPS($user_id, $password, $api = 'RateV2')
	{
		if(empty($user_id) || empty($password)) {
		
			$this->debug("USPS ERROR: User ID or Password was empty. Please make sure this has been added correctly to the admin side of your store.");
			return false;
			
		} else {
			$this->user_id = $user_id;
			$this->password = $password;
			$this->api = $api;
			$this->request_xml = '<' . $api . 'Request USERID="' . $user_id . '" PASSWORD="' . $password . '">';
		}
	}

	function reset()
	{
		$this->api = '';
		$this->current_result = '';
		$this->request_xml = '';
		$this->package_index = 0;
	}

	function add_package($attribs = '')
	{
		if(!is_array($attribs)) { 
			$this->debug("USPS ERROR: Package array was empty.");
			return false;
		}

		//Check to make sure array has required values for API
		if($this->api == 'RateV2') {
			
			if(!$attribs['service'] || !$attribs['zip_origin'] || !$attribs['zip_dest'] || !$attribs['size']) {

				 $this->debug("USPS ERROR: One of the following variables was empty. service = '".$attribs['service']."', zip_origin = '".$attribs['zip_origin']."', zip_dest = '".$attribs['zip_dest']."', size = '".$attribs['size']."'");
				 return false;
			
			 }
		
		}

		if($this->api == 'RateV2')
		{
			//Check service type
			if(empty($attribs['service'])) { 
				$this->debug("USPS ERROR: Service variable was empty.");
				return false;
			} else {
				switch(strtolower($attribs['service']))
				{
					case 'express':
					case 'first class':
					case 'priority':
					case 'parcel':
					case 'bpm':
					case 'library':
					case 'media':
					case 'all':
						break;
					default:
						$this->debug("USPS ERROR: Service variable was not recognised.");
						return false;
				}
			}

			//Check ZIP codes
			if(!isset($attribs['zip_origin'])) { $this->debug("USPS ERROR: Zip Origin was not set."); return false; }
			if(!isset($attribs['zip_dest'])) { $this->debug("USPS ERROR: Zip Destination was not set."); return false; }

			//Check weight
			if($attribs['pounds'] + $attribs['ounces'] == 0) {  $this->debug("USPS ERROR: No weight set."); return false; }
			

			//Check container for Express and Priority
			if(strtolower($attribs['service']) == 'express' || strtolower($attribs['service']) == 'priority')
			{
				if(!isset($attribs['container'])) {  $this->debug("USPS ERROR: Container for express or priority post was not set."); return false; }
				else {
					switch(strtolower($attribs['container']))
					{
						case 'flat rate envelope':
						case 'flat rate box':
							break;
						default:
							$this->debug("USPS ERROR: Container not recognised.");
							return false;
					}
				}
			}

			//Check size
			if(!$attribs['size']) return false;
			else {
				switch(strtolower($attribs['size']))
				{
					case 'regular':
					case 'large':
					case 'oversize':
						break;
					default:
						$this->debug("USPS ERROR: Size not recognised.");
						return false;
				}
			}

			//Check machinable for parcel post
			if(strtolower($attribs['service']) == 'parcel') {
				if(empty($attribs['machinable'])) { $this->debug("USPS ERROR: Machinable variable for parcel service not set."); return false; }
			}

			//Add the package to the XML request
			$this->request_xml .= '<Package ID="' . $this->package_index . '">';
			
			$this->package_index++;
			
			$this->request_xml .= '<Service>' . strtoupper($attribs['service']) . '</Service>';
			$this->request_xml .= '<ZipOrigination>' . $attribs['zip_origin'] . '</ZipOrigination>';
			$this->request_xml .= '<ZipDestination>' . $attribs['zip_dest'] . '</ZipDestination>';
			$this->request_xml .= '<Pounds>' . $attribs['pounds'] . '</Pounds>';
			$this->request_xml .= '<Ounces>' . $attribs['ounces'] . '</Ounces>';
			
			if(strtolower($attribs['service']) == 'express' || strtolower($attribs['service']) == 'priority') {
				
				$this->request_xml .= '<Container>' . $attribs['container'] . '</Container>';
				
			}
			
			$this->request_xml .= '<Size>' . ucfirst(strtolower($attribs['size'])) . '</Size>';
			
			if(strtolower($attribs['service']) == 'parcel' || strtolower($attribs['service']) == 'all') {
				
				$this->request_xml .= '<Machinable>' . $attribs['machinable'] . '</Machinable>';
			}
			
			$this->request_xml .= '</Package>';
				
			
		
		}

		else if($this->api == 'IntlRate')
		{
			
			//if(!$attribs['pounds']) { $this->debug("USPS ERROR: International pounds not set."); return false; }
			//if(!$attribs['ounces']) { $this->debug("USPS ERROR: International ounces not set."); return false; }

			if(!$attribs['mail_type']) { $this->debug("USPS ERROR: International mail type not set."); return false; }
			else {
				switch(strtolower($attribs['mail_type']))
				{
					case 'package':
					case 'postcards or aerogrammes':
					case 'matter for the blind':
					case 'envelope':
						break;
					default:
						$this->debug("USPS ERROR: Mail type not recognised.");
						return false;
				}
			}

			if(!isset($attribs['country'])) { $this->debug("USPS ERROR: Country not set."); return false; }
			if(!in_array($attribs['country'], $this->country_list)) { return false; }

			//Add the package to the XML request
			$this->request_xml .= '<Package ID="' . $this->package_index . '">';
			$this->package_index++;	
			$this->request_xml .= '<Pounds>' . $attribs['pounds'] . '</Pounds>';
			$this->request_xml .= '<Ounces>' . $attribs['ounces'] . '</Ounces>';
			$this->request_xml .= '<MailType>' . $attribs['mail_type'] . '</MailType>';
			$this->request_xml .= '<Country>' . $attribs['country'] . '</Country>';
			$this->request_xml .= '</Package>';
		}

		return true;
	}

	function submit_request()
	{
		global $module;
		require_once("xmlize.inc.php"); 

		$this->request_xml .= '</' . $this->api . 'Request>';

		//Create a cURL instance and retrieve XML response
		if(!is_callable("curl_exec")) die("USPS::submit_request: curl_exec is uncallable");
		
		if($module['test']==1){
			$USPSURL = "http://testing.shippingapis.com/ShippingAPITest.dll";
		} else {
			$USPSURL = "https://secure.shippingapis.com/ShippingAPI.dll";
		}
		$ch = curl_init($USPSURL);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, "API=" . $this->api . "&XML=" . $this->request_xml);
		curl_setopt($ch, CURLOPT_TIMEOUT, 60);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		$return_xml = curl_exec($ch);
		
		if(eregi("Authorization failure",$return_xml)){
			
			echo "<strong>Authorization Error connecting to United States Postal Service Server:</strong> ".$USPSURL."<p>Please register at <a href='http://www.usps.com/webtools/'>http://www.usps.com/webtools/</a> and enter the correct username and password in the CubeCart control panel. You MUST have a successful test transaction before USPS will give you access to the live server.</p>
<p>Please go back and verify your login information.  Remember, you must have your USPS issued username entered and <i>something</i> in the password box.</p>";
			exit;
		
		} elseif(eregi("error",$return_xml)){
			
			echo "<strong>Request XML:</strong><hr />".nl2br(htmlspecialchars($this->request_xml))."<hr />"; 
			echo "<strong>Return XML:</strong><hr />".nl2br(htmlspecialchars($return_xml));
			exit;
		
		}

		//The return XML will be parsed with XMLIZE into the $xml array

		$xml = xmlize($return_xml);
		
#		echo "<pre>\n";
#		print_r($xml);
#		echo "\n</pre>\n";
#		traverse_xmlize($xml, 'xml_');
#		print '<pre>' . implode("", $GLOBALS['traverse_array']) . '</pre>';


		if(isset($xml['RateV2Response']))
		{
			//Domestic return data needs to be parsed differently from international data

			$package_id = 0;

			if(isset($xml['RateV2Response']['#']['Package']['0']['#']['Error']))
			{
				$x_errorDesc = $xml['RateV2Response']['#']['Package']['#']['Error'];
				$this->current_result[$package_id]['Error']['Description'] = $x_errorDesc;
			}
			else if(isset($xml['RateV2Response']['#']['Package']['0']['#']['ZipOrigination']))
			{
				$x_postage = $xml['RateV2Response']['#']['Package']['0']['#']['Postage'];

				for($i=0; $i < count($x_postage); $i++)
				{
					$x_mailservice = $x_postage[$i]['#']['MailService']['0']['#'];
					$x_rate = $x_postage[$i]['#']['Rate']['0']['#'];

#					echo "MailService = ".$x_mailservice."<br>";
#					echo "Rate = ".$x_rate."<br>";
					
					$this->current_result[$package_id]['Postage'][$x_mailservice] = $x_rate;
				} 
			}
		}

		else if(isset($xml['IntlRateResponse']))
		{
			//This is international data, so parse it accordingly

			$package_id = 0;

			if(isset($xml['IntlRateResponse']['#']['Package']['0']['#']['Error']))
			{
				$x_errorDesc = $xml['IntlRateResponse']['#']['Package']['#']['Error'];
				$this->current_result[$package_id]['Error']['Description'] = $x_errorDesc;
			}
			else if(isset($xml['IntlRateResponse']))
			{
				$x_postage = $xml['IntlRateResponse']['#']['Package']['0']['#']['Service'];

				for($i=0; $i < count($x_postage); $i++)
				{
					$x_mailservice = $x_postage[$i]['#']['SvcDescription']['0']['#'];
					$x_rate = $x_postage[$i]['#']['Postage']['0']['#'];

#					echo "MailService = ".$x_mailservice."<br>";
#					echo "Rate = ".$x_rate."<br>";
					
					$this->current_result[$package_id]['Postage'][$x_mailservice] = $x_rate;
				} 
			}
		}

		return true;
	}

	function get_rates($package_id = 0)
	{
		if($this->current_result[$package_id]['Error']) return $this->current_result[$package_id]['Error']['Description'];

#		if($this->api == 'RateV2')
			return $this->current_result[$package_id]['Postage'];
#		else if($this->api == 'IntlRate')
#		{
			//SvcDescription and Postage
#			$result = array();

#			foreach($this->current_result[$package_id]['Service'] as $service)
#			{
#				$key = $service['SvcDescription'];
#				$result[$key] = $service['Postage'];
#			}

			return $result;
#		}
#		else return false;
	}

	function get_prohibitions($package_id)
	{
		if($this->api == 'IntlRate') return $this->current_result[$package_id]['Prohibitions'];
		else return false;
	}

	function get_restrictions($package_id)
	{
		if($this->api == 'IntlRate') return $this->current_result[$package_id]['Restrictions'];
		else return false;
	}

	function get_observations($package_id)
	{
		if($this->api == 'IntlRate') return $this->current_result[$package_id]['Observations'];
		else return false;
	}

	function get_areas_served($package_id)
	{
		if($this->api == 'IntlRate') return $this->current_result[$package_id]['AreasServed'];
		else return false;
	}

	function get_package_error($package_id)
	{
		if($this->current_result[$package_id]['Error']) return $this->current_result[$package_id]['Error'];
	}
}

?>