<?php
/**
 * vaCentral Communication Script
 * 
 * You can modify this as you see fit, but DO NOT ABUSE. There are measures 
 * in place to guard against cheating, and offenders will be outed *publicly*. 
 * 
 * Think about the repercussions to your VA before you do something stupid.
 * 
 * http://www.vacentral.net
 * 
 * Include this into your own PIREP system to be able to send data 
 * to vaCentral about your VA. Please report any issues to the forums.
 * 
 * NOTE: This script will work for PHP 5+, 5.2+ recommended.
 * You also will need the "curl" and "SimpleXML" PHP extensions installed to use this. 
 * 
 * To use (in this instance, where your script submits a PIREP to your database):
 * 
 *  include '/path/to/vacentral_xml.php';
 * 
 *	$vac = new vaCentral_XML();
 *  $data = new stdClass();
 *	// See the send_pirep() function for all the parameters...
 *	$data->depicao = '...';
 *	// etc, finally send it: 
 *	$vac->send_pirep($data); 
 * 
 * See the functions for more information (including the data that is expected).
 * The class is nothing crazy, it just takes objects as the single parameter.
 * 
 * There are also a few settings (scroll below), to set your API key and the 
 *	URL of your site, which are both sent to the API server.
 * 
 * You can call this in a cron, maybe once every hour or so. A script which will
 * retrieve non-exported PIREPs, and then send them to vaCentral. I process 
 * PIREPs every hour for financials, ranking, and other stats data. Of course, the
 * best time to run the cron would be nightly, maybe 1-2am, during a low traffic time.
 * This will reduce load for both your server and mine.
 * 
 * ACARS data can be sent at any time (Sending them live is probably best). Schedules
 * I would like an update maybe once a week. That's not too critical. Your VA info
 * should definately update once a day (I accept 3 updates a day, that is throttled).
 * 
 * I recommend for sending PIREPs, keeping track of which PIREPs have been sent 
 * (maybe an "exported" column), that way you can make sure it's all been exported.
 * 
 * The API server will always return a response similar to this:
 * 
 * <message>
 *	 <responsecode>200</responsecode>
 *   <type>Success</type>
 *	 <detail>Updated 20 of 20 PIREPs</detail>
 * </message>
 * 
 * Reponse Code:
 *	200 - Success
 *  400 - Invalid XML received
 *  401 - Invalid API key
 * 
 * Reponse codes match HTTP error codes.
 * 
 * Type:
 *	Success or Error
 * 
 * Detail:
 *	Details of what happened
 */

/* This should be the version of your app, with your VA name in it,
For instance "VMS_AIRLINE_1.2" */
define('VAC_APP_VERSION', 'YOUR_VA_VERSION');
/* Your API key from the vacentral site*/
define('VAC_API_KEY', 'YOUR_API_KEY');
/* Your website's URL. Must match what's on your vaCentral profile */
define('SITE_URL', 'YOUR_SITES_URL');

/* Don't change this */
define('VAC_API_SERVER', 'http://api.vacentral.net');

class vaCentral_XML
{
	public $error;
	public $debug = false;
	public $xml;
	public $xml_sent;
	public $xml_response;
	
	protected $cws;
	protected $curl;
	
	public function __construct()
	{
		/* Make sure cURL is installed or enabled */
		if(!function_exists('curl_init'))
		{
			trigger_error('The cURL extension is not enabled or installed', E_USER_ERROR);
			return false;
		}
		
		/* This class is included below */
		$this->cws = new CodonWebService();
	}
	
	private function send_xml()
	{
		/* Use CWS to send a raw post */
		$resp = $this->cws->post(VAC_API_SERVER.'/update', $this->xml->asXML());
		$this->xml_response = simplexml_load_string($resp);
		
		return $this->xml_response;
	}
	
	private function set_xml($method)
	{
		$this->xml = new SimpleXMLElement('<vacentral/>');
		
		$this->xml->addChild('siteurl', SITE_URL);
		$this->xml->addChild('apikey', VAC_API_KEY);
		$this->xml->addChild('version', VAC_APP_VERSION);
		
		if($this->debug === true)
		{
			$this->xml->addChild('debug', $this->debug);
		}
		
		$this->xml->addChild('method', $method);
	}	
	
	/*
		
		This data should be sent once a day, upto three times a day.
		This is throttled on my server.
		
		$data = new stdClass();
		$data->pilotcount = 'PILOT_COUNT';
		$data->totalhours	= 'TOTAL_HOURS';
		$data->totalflights = 'TOTAL_FLIGHTS';
		$data->expenses = 'TOTAL_NUMBER_OF_EXPENSES';
		$data->expensescost = 'TOTAL_COST_OF_EXPENSES';
		$data->livefuel = 'TRUE/FALSE IF YOU'RE USING LIVE FUEL PRICES';
		
		Then
		
		$vac->send_vastats($data);
	 */
	public function send_vastats($data)
	{
		$this->set_xml('update_vainfo');
		$this->xml->addChild('pilotcount', $data->pilotcount);
		$this->xml->addChild('totalhours', $data->totalhours);
		$this->xml->addChild('totalflights', $data->totalflights);
		$this->xml->addChild('totalschedules', $data->totalschedules);
		
		# Some of the settings
		$this->xml->addChild('livefuel', $data->livefuel);
		
		# Package and send
		return $this->send_xml();
	}	
	
	/*
		$schedules = array();
		
		For every schedule:
		
			$data =  stdClass();
			
			$data->flightnum = 'FLIGHT_NUMBER'; // Including the code!
			$data->depicao = 'DEPARTURE ICAO';
			$data->arricao = 'ARRIVAL ICAO';
			$data->route = 'ROUTE';
			$data->aircraft = 'AIRCRAFT TYPE USED';
			$data->registration  = 'AIRCRAFT_REGISTRATION';
			$data->distance = 'DISTANCE BETWEEN AIRPORTS';
			$data->deptime = 'DEPARTURE TIME';
			$data->arrtime = 'ARRIVAL TIME';
			$data->daysofweek = 'DAYS SCHEDULE IS ACTIVE (0 through 6, Sunday through Saturday)
			$data->maxload = 'MOST PASSENGERS OR CARGO LOAD';
			$data->price = 'PRICE PER LOAD UNIT OF FLIGHT';
			$data->flighttype = 'P for passenger, C for cargo, H for charter';
			$data->notes = 'NOTES FOR FLIGHT';
		
		Then add each schedule to the master array
		$schedules[] = $data;
		
		
		$vac_data->send_schedules($schedules);

		
	 */
	public  function send_schedules($schedules)
	{			
		$this->set_xml('update_schedules');
		
		foreach($schedules as $sched)
		{
			$schedule_xml = $this->xml->addChild('schedule');
			
			$schedule_xml->addChild('flightnum', $sched->flightnum);
			$schedule_xml->addChild('depicao', $sched->depicao);
			$schedule_xml->addChild('arricao', $sched->arricao);
			$schedule_xml->addChild('aircraft', $sched->aircraft);
			$schedule_xml->addChild('registration', $sched->registration);
			$schedule_xml->addChild('distance', $sched->distance);
			$schedule_xml->addChild('daysofweek', $sched->daysofweek);
			$schedule_xml->addChild('maxload', $sched->maxload);
			$schedule_xml->addChild('price', $sched->price);
			$schedule_xml->addChild('flighttype', $sched->flighttype);
			$schedule_xml->addChild('notes', $sched->notes);
			$schedule_xml->addChild('deptime', $sched->deptime);
			$schedule_xml->addChild('arrtime', $sched->arrtime);
		}

		return $this->send_xml($xml);
	}
	
	/*
		$pilots = array();
		
		For every pilot:
			
			$data = stdClass();
			$data->pilotid = 'PILOT ID';
			$data->pilotname = 'PILOT FULL NAME';
			$data->location = 'PILOT LOCATION';
			
			$pilots[] = $data
		
		Then:
		$vac_data->send_pilots($pilots);
	*/
	public function send_pilots($pilots)
	{
		$this->set_xml('update_pilots');
		$this->xml->addChild('total', count($allpilots));
		
		foreach($pilots as $pilot)
		{
			$pilot_xml = $this->xml->addChild('pilot');
			$pilot_xml->addChild('pilotid', $pilot->pilotid);
			$pilot_xml->addChild('pilotname', $pilot->pilotname);
			$pilot_xml->addChild('location', $pilot->location);
		} 
		
		return $this->send_xml();
	}
	
	/*
		
		$pireps = new array();
		
		For every PIREP:
		
			$data = new stdClass();
			$data->pilotid = 'FULL PILOT ID';
			$data->uniqueid = 'A UNIQUE NUMERIC ID FOR THE FLIGHT';
			$data->pilotname = 'FULL PILOT NAME';
			$data->flightnum = 'FULL FLIGHT NUMBER WITH CODE';
			$data->depicao = 'DEPARTURE AIRPORT ICAO';
			$data->arricao = 'ARRIVAL AIRPORT ICAO';
			$data->aircraft = 'AIRCRAFT TYPE';
			$data->registration = 'AIRCRAFT REGISTRATION';
			$data->flighttime = 'FLIGHT TIME';
			$data->submitdate = 'DATE SUBMITTED';
			$data->flighttype = 'P for passenger, C for cargo, H for charter';
			$data->load = 'NUMBER OF PASSENGERS OR AMOUNT OF CARGO CARRIED';
			$data->fuelused = 'TOTAL AMOUNT OF FUEL USED';
			$data->fuelprice = 'PRICE PER FUEL UNIT';
			$data->pilotpay = 'WHAT PILOT WAS PAID FOR PRICE';
			$data->price = 'PRICE PER LOAD UNIT';
			$data->revenue = 'TOTAL REVENUE FOR THIS FLIGHT';
			
			$pireps[] = $data;
		
		$vac_data->send_all_pireps($pireps);
		
	*/
	
	public function send_all_pireps($pireps)
	{
		$this->set_xml('update_pireps');
		$this->xml->addChild('total', count($pireps));
		
		foreach($pireps as $pirep)
		{
			# Skip erronious entries
			if($pirep->aircraft == '')
				continue; 
			
			$this->get_pirep_xml($pirep);
		}
		
		return $this->send_xml();	
	}
	
	
	/*
		$data = new stdClass();
		$data->pilotid = 'FULL PILOT ID';
		$data->uniqueid = 'A UNIQUE NUMERIC ID FOR THE FLIGHT';
		$data->pilotname = 'FULL PILOT NAME';
		$data->flightnum = 'FULL FLIGHT NUMBER WITH CODE';
		$data->depicao = 'DEPARTURE AIRPORT ICAO';
		$data->arricao = 'ARRIVAL AIRPORT ICAO';
		$data->aircraft = 'AIRCRAFT TYPE';
		$data->registration = 'AIRCRAFT REGISTRATION';
		$data->flighttime = 'FLIGHT TIME';
		$data->submitdate = 'DATE SUBMITTED';
		$data->flighttype = 'P for passenger, C for cargo, H for charter';
		$data->load = 'NUMBER OF PASSENGERS OR AMOUNT OF CARGO CARRIED';
		$data->fuelused = 'TOTAL AMOUNT OF FUEL USED';
		$data->fuelprice = 'PRICE PER FUEL UNIT';
		$data->pilotpay = 'WHAT PILOT WAS PAID FOR PRICE';
		$data->price = 'PRICE PER LOAD UNIT';
		$data->revenue = 'TOTAL REVENUE FOR THIS FLIGHT';
		
		$vac_data->send_pirep($data);
		
	*/
	public function send_pirep($pirep_data)
	{
		$this->set_xml('add_pirep');
		$this->get_pirep_xml($pirep_data);
		
		return $this->send_xml();
	}
	
	/*
		Pass a list of PIREP id's to remove (must match
		the unique ID you passed in).
		
		$pireps = array(1, 2,, 4, 16, 22);
		$vac_data->remove_pireps($pireps);
	*/
	public function remove_pireps($pireps)
	{
		$this->set_xml('removepireps');
		
		foreach($pireps as $p)
		{
			$pirep_xml = $this->xml->addChild('pirep');
			$pirep_xml->addChild('uniqueid', $p);
		}
		
		return $this->send_xml();
	}
	
	protected function get_pirep_xml($pirep)
	{
		$pirep_xml = $this->xml->addChild('pirep');
		$pirep_xml->addChild('uniqueid', $pirep->uniqueid);
		$pirep_xml->addChild('pilotid', $pirep->pilotid);
		$pirep_xml->addChild('pilotname', $pirep->pilotname);
		$pirep_xml->addChild('flightnum', $pirep->flightnum);
		$pirep_xml->addChild('depicao', $pirep->depicao);
		$pirep_xml->addChild('arricao', $pirep->arricao);
		$pirep_xml->addChild('aircraft', $pirep->aircraft);
		$pirep_xml->addChild('flighttime', $pirep->flighttime);
		$pirep_xml->addChild('submitdate', $pirep->submitdate);
		$pirep_xml->addChild('flighttype', $pirep->flighttype);
		$pirep_xml->addChild('load', $pirep->load);
		$pirep_xml->addChild('fuelused', $pirep->fuelused);
		$pirep_xml->addChild('fuelprice', $pirep->fuelprice);
		$pirep_xml->addChild('pilotpay', $pirep->pilotpay);
		$pirep_xml->addChild('price', $pirep->price);
		$pirep_xml->addChild('revenue', $pirep->revenue);
	}
	
	
	/*
		
	For every ACARS flight:
	$acars_flights = array();
		
		$data = new stdClass();
		$data->unique_id = 'UNIQUE_ID FROM YOUR DATABASE';
		$data->client = 'CLIENT NAME (eg "xacars", "fsacars", "custom")';
		$data->flightnum = 'FULL FLIGHT NUMBER';
		$data->pilotid = 'FULL PILOT ID';
		$data->pilotname = 'FULL PILOT NAME';
		$data->depicao = 'DEPARTURE ICAO';
		$data->arricao = 'ARRIVAL ICAO';
		$data->deptime = 'DEPARTURE TIME, UNIX TIMESTAMP';
		$data->arrtime = 'ARRIVAL TIME, ESTIMATED OR BLANK. UNIX TIMESTAMP';
		$data->aircraft = 'AIRCRAFT FLOWN';
		$data->lat = 'CURRENT LATITUDE';
		$data->lng = 'CURRENT LONGITUDE';
		$data->heading = 'CURRENT HEADING';
		$data->phase = 'PHASE STRING (DEFAULTS TO "ENROUTE")
		$data->alt = 'CURRENT ALTITUDE, IN FEET';
		$data->gs = 'CURRENT GROUNDSPEED';
		$data->distremain = 'DISTANCE REMAINING TILL ARRIVAL';
		$data->timeremain = 'TIME REMAINING TILL ARRIVAL';
		$data->lastupdate = 'LAST UPDATE, UNIX TIMESTAMP';

	*/
	
	public function send_all_acars($acars_flights)
	{
		if(!is_array($acars_flights))
			return false;
		
		$this->set_xml('update_acars');				
		foreach($acars_flights as $flight)
		{			
			$this->create_acars_flight($flight);
		}
		
		return $this->send_xml();
	}
	
	public function send_acars_data($flight)
	{		
		$this->set_xml('update_acars_flight');
		$this->create_acars_flight($flight);
		
		return $this->send_xml();
	}	
	
	protected function create_acars_flight($flight)
	{
		$acars_xml = $this->xml->addChild('flight');
		$acars_xml->addChild('unique_id', $flight->id);
		$acars_xml->addChild('client', $flight->client);
		$acars_xml->addChild('flightnum', $flight->flightnum);
		$acars_xml->addChild('aircraft', $flight->aircraftname);
		$acars_xml->addChild('lat', $flight->lat);
		$acars_xml->addChild('lng', $flight->lng);
		$acars_xml->addChild('pilotid', $flight->pilotid);
		$acars_xml->addChild('pilotname', $flight->pilotname);
		$acars_xml->addChild('depicao', $flight->depicao);
		$acars_xml->addChild('arricao', $flight->arricao);
		$acars_xml->addChild('deptime', $flight->deptime);
		$acars_xml->addChild('arrtime', $flight->arrtime);
		$acars_xml->addChild('heading', $flight->heading);
		$acars_xml->addChild('phase',$flight->phasedetail);
		$acars_xml->addChild('alt', $flight->alt);
		$acars_xml->addChild('gs', $flight->gs);
		$acars_xml->addChild('distremain', $flight->distremain);
		$acars_xml->addChild('timeremain', $flight->timeremaining);
		$acars_xml->addChild('lastupdate', $flight->lastupdate);
	}
}





/**
 * Codon PHP Framework
 *	www.nsslive.net/codon
 * Software License Agreement (BSD License)
 *
 * Copyright (c) 2008 Nabeel Shahzad, nsslive.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Nabeel Shahzad
 * @copyright Copyright (c) 2008, Nabeel Shahzad
 * @link http://www.nsslive.net/codon
 * @license BSD License
 * @package codon_core
 */

class CodonWebService
{
	protected $type = 'curl';
	protected $curl = null;
	protected $curl_exists = true;
	public $_separator = '&';	
	
	public $errors = array();
	public $options = array(
		CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9) Gecko/2008052906 Firefox/3.0',
		CURLOPT_FOLLOWLOCATION => true,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_AUTOREFERER => true,
		CURLOPT_CONNECTTIMEOUT => 7,
		CURLOPT_HEADER => false,
		CURLOPT_FOLLOWLOCATION => true);
	
	public function __construct()
	{
		# Make sure cURL is installed
		
		if(!function_exists('curl_init'))
		{
			$this->curl_exists = false;
			$this->error('cURL not installed');
		}
		
		if($this->curl_exists == true)
		{
			if(!$this->curl = curl_init())
			{
				$this->error();
				$this->setType('fopen');
				$this->curl = null;
			}
			
			$this->setType('curl');
			@curl_setopt_array($this->curl, $this->options);
		}
		else
		{
			$this->curl = null;
			$this->setType('fopen');
		}
	}
	
	public function __destruct()
	{
		if($this->curl)
			curl_close($this->curl);
	}
	
	/**
	 * Internal error handler
	 *
	 * @param string $txt Error text
	 */
	protected function error($txt='')
	{
		if($txt != '')
			$last = $txt;
		else
			$last = curl_error($this->curl) .' ('.curl_errno($this->curl).')';
		
		$this->errors[] = $last;
	}
	
	/**
	 * Set the transfer type (curl or fopen). cURL is better
	 * POST cannot be done by fopen, it will be ignored
	 *
	 * @param string $type curl or fopen
	 * @return unknown
	 */
	public function setType($type = 'curl')
	{
		if($type != 'curl' && $type !='fopen')
		{
			$this->error('Invalid connection type');
			return false;
		}
		
		$this->type = $type;
	}
	
	/**
	 * Set the curl options, that are different from the default
	 *
	 * @param unknown_type $opt
	 * @return unknown
	 */
	public function setOptions($opt)
	{
		if(!$this->curl)
		{
			$this->error('No valid cURL session');
			return false;
		}
		
		curl_setopt_array($this->curl, $opt);
	}
	
	/**
	 * Grab a URL, but use SSL. Returns the reponse
	 *
	 * @param url $url
	 * @param array $params Associative array of key=value
	 * @param string $type post or get (get by default)
	 */
	public function getSSL($url, $params, $type='get')
	{
		// set SSL options and then go
		curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, 0);
		
		$this->get($url, $params, $type);
	}
	
	/**
	 * Grab a URL, return the reponse
	 *
	 * @param url $url
	 * @param array $params Associative array of key=value
	 */
	public function get($url, $params='')
	{
		# Builds the parameters list
		if(is_array($params))
		{
			$q_string = '';
			foreach($params as $name=>$value)
			{
				$q_string .= $name.'='.urlencode($value).$this->_separator;
			}
			
			$q_string = substr($q_string, 0, strlen($q_string)-1);
			$url = $url.'?'.$q_string;
		}
		
		if($this->type == 'fopen')
		{
			if(strtolower(ini_get('allow_url_fopen')) == 'on')
			{
				return file_get_contents($url);
			}
		}
		
		if(!$this->curl || $this->curl == null)
		{
			$this->error('cURL not installed or initialized!');
			return false;
		}
		
		curl_setopt ($this->curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt ($this->curl, CURLOPT_URL, $url);
		if(($ret = curl_exec($this->curl)) === false)
		{
			$this->error();
			return false;
		}

		return $ret;
	}
	
	/**
	 * Grab a URL, return the reponse, POST params
	 *
	 * @param url $url
	 * @param array $params Associative array of key=value
	 */
	public function post($url, $params='')
	{		
		if(!$this->curl)
		{
			$this->error('cURL not initialized');
			return false;
		}
		
		//encode our url data properly
		if(is_array($params))
		{
			foreach($params as $key=>$value)
			{				
				
				$cleaned_params[$key] = urlencode($value);
			}
		}
		else
		{
			$cleaned_params = urlencode($params);
		}
		
		curl_setopt($this->curl, CURLOPT_POST, 1);
		curl_setopt($this->curl, CURLOPT_POSTFIELDS, $cleaned_params);
		
		
		curl_setopt ($this->curl, CURLOPT_URL, $url);
		if(($ret = curl_exec($this->curl)) === false)
		{
			$this->error();
			return false;
		}
		
		return $ret;
	}
	
	/**
	 * Download a file from $url to the $tofile
	 *
	 * @param url $url URL of file to download
	 * @param path $tofile Path of file to download to
	 * @return unknown
	 */
	public function download($url, $tofile)
	{
		
		if($this->type == 'fopen')
		{
			if(strtolower(ini_get('allow_url_fopen')) == 'on')
			{
				if(file_put_contents($tofile, file_get_contents($url)) == false)
				{
					$this->error('Error getting file');
					return false;
				}
			}
		}
		
		if(!$this->curl || $this->curl == null)
			return false;
		
		if(($fp = fopen($tofile, 'wb')) == false)
		{
			$this->error('Error opening '.$tofile);
			return false;
		}
		
		curl_setopt($this->curl, CURLOPT_BINARYTRANSFER, true);
		curl_setopt($this->curl, CURLOPT_FILE, $fp);
		curl_setopt ($this->curl, CURLOPT_URL, $url);
		
		if(($ret = curl_exec($this->curl)) === false)
		{
			$this->error();
			unlink($tofile);
			return false;
		}
	}
}