<?php

require_once dirname(__FILE__) . '/serialisation.php';
require_once dirname(__FILE__) . '/transport.php';
require_once dirname(__FILE__) . '/log.php';

define('CS_REST_WRAPPER_VERSION', '2.4.0');

define('CS_REST_WEBHOOK_FORMAT_JSON', 'json');
define('CS_REST_WEBHOOK_FORMAT_XML', 'xml');

/**
 * A general result object returned from all Campaign Monitor API calls.
 * @author tobyb
 *
 */
if (!class_exists('CS_REST_Wrapper_Result'))
{

    class CS_REST_Wrapper_Result
    {

	/**
	 * The deserialised result of the API call
	 * @var mixed
	 */
	var $response;

	/**
	 * The http status code of the API call
	 * @var int
	 */
	var $http_status_code;

	function __construct($response, $code)
	{
	    $this->response		 = $response;
	    $this->http_status_code	 = $code;
	}

	/**
	 * Can be used to check if a call to the api resulted in a successful response.
	 * @return boolean False if the call failed. Check the response property for the failure reason.
	 * @access public
	 */
	function was_successful()
	{
	    return $this->http_status_code >= 200 && $this->http_status_code < 300;
	}

    }

}
/**
 * Base class for the create send PHP wrapper.
 * This class includes functions to access the general data,
 * i.e timezones, clients and getting your API Key from username and password
 * @author tobyb
 *
 */
if (!class_exists('CS_REST_Wrapper_Base'))
{

    class CS_REST_Wrapper_Base
    {

	/**
	 * The protocol to use while accessing the api
	 * @var string http or https
	 * @access private
	 */
	var $_protocol;

	/**
	 * The base route of the create send api.
	 * @var string
	 * @access private
	 */
	var $_base_route;

	/**
	 * The serialiser to use for serialisation and deserialisation
	 * of API request and response data
	 * @var CS_REST_JsonSerialiser or CS_REST_XmlSerialiser
	 * @access private
	 */
	var $_serialiser;

	/**
	 * The transport to use to send API requests
	 * @var CS_REST_CurlTransport or CS_REST_SocketTransport or your own custom transport.
	 * @access private
	 */
	var $_transport;

	/**
	 * The logger to use for debugging of all API requests
	 * @var CS_REST_Log
	 * @access private
	 */
	var $_log;

	/**
	 * The default options to use for each API request.
	 * These can be overridded by passing in an array as the call_options argument
	 * to a single api request.
	 * Valid options are:
	 *
	 * deserialise boolean:
	 *     Set this to false if you want to get the raw response.
	 *     This can be useful if your passing json directly to javascript.
	 *
	 * While there are clearly other options there is no need to change them.
	 * @var array
	 * @access private
	 */
	var $_default_call_options;

	/**
	 * Constructor.
	 * @param $api_key string Your api key (Ignored for get_apikey requests)
	 * @param $protocol string The protocol to use for requests (http|https)
	 * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE
	 * @param $host string The host to send API requests to. There is no need to change this
	 * @param $log CS_REST_Log The logger to use. Used for dependency injection
	 * @param $serialiser The serialiser to use. Used for dependency injection
	 * @param $transport The transport to use. Used for dependency injection
	 * @access public
	 */
	function __construct(
	$api_key, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL)
	{

	    $this->_log = is_null($log) ? new CS_REST_Log($debug_level) : $log;

	    $this->_protocol	 = $protocol;
	    $this->_base_route	 = $protocol . '://' . $host . '/api/v3/';

	    $this->_log->log_message('Creating wrapper for ' . $this->_base_route, get_class($this), CS_REST_LOG_VERBOSE);

	    $this->_transport = is_null($transport) ?
		    CS_REST_TRANSPORT_get_available($this->is_secure(), $this->_log) :
		    $transport;

	    $transport_type = method_exists($this->_transport, 'get_type') ? $this->_transport->get_type() : 'Unknown';
	    $this->_log->log_message('Using ' . $transport_type . ' for transport', get_class($this), CS_REST_LOG_WARNING);

	    $this->_serialiser = is_null($serialiser) ?
		    CS_REST_SERIALISATION_get_available($this->_log) : $serialiser;

	    $this->_log->log_message('Using ' . $this->_serialiser->get_type() . ' json serialising', get_class($this), CS_REST_LOG_WARNING);

	    $this->_default_call_options = array(
		'credentials'	 => $api_key . ':nopass',
		'userAgent'	 => 'CS_REST_Wrapper v' . CS_REST_WRAPPER_VERSION .
		' PHPv' . phpversion() . ' over ' . $transport_type . ' with ' . $this->_serialiser->get_type(),
		'contentType'	 => 'application/json; charset=utf-8',
		'deserialise'	 => true,
		'host'		 => $host,
		'protocol'	 => $protocol
	    );
	}

	/**
	 * @return boolean True if the wrapper is using SSL.
	 * @access public
	 */
	function is_secure()
	{
	    return $this->_protocol === 'https';
	}

	function put_request($route, $data, $call_options = array())
	{
	    return $this->_call($call_options, CS_REST_PUT, $route, $data);
	}

	function post_request($route, $data, $call_options = array())
	{
	    return $this->_call($call_options, CS_REST_POST, $route, $data);
	}

	function delete_request($route, $call_options = array())
	{
	    return $this->_call($call_options, CS_REST_DELETE, $route);
	}

	function get_request($route, $call_options = array())
	{
	    return $this->_call($call_options, CS_REST_GET, $route);
	}

	function get_request_paged($route, $page_number, $page_size, $order_field, $order_direction, $join_char = '&')
	{
	    if (!is_null($page_number))
	    {
		$route .= $join_char . 'page=' . $page_number;
		$join_char = '&';
	    }

	    if (!is_null($page_size))
	    {
		$route .= $join_char . 'pageSize=' . $page_size;
		$join_char = '&';
	    }

	    if (!is_null($order_field))
	    {
		$route .= $join_char . 'orderField=' . $order_field;
		$join_char = '&';
	    }

	    if (!is_null($order_direction))
	    {
		$route .= $join_char . 'orderDirection=' . $order_direction;
		$join_char = '&';
	    }

	    return $this->get_request($route);
	}

	/**
	 * Internal method to make a general API request based on the provided options
	 * @param $call_options
	 * @access private
	 */
	function _call($call_options, $method, $route, $data = NULL)
	{
	    $call_options['route']	 = $route;
	    $call_options['method']	 = $method;

	    if (!is_null($data))
	    {
		$call_options['data'] = $this->_serialiser->serialise($data);
	    }

	    $call_options = array_merge($this->_default_call_options, $call_options);
	    $this->_log->log_message('Making ' . $call_options['method'] . ' call to: ' . $call_options['route'], get_class($this), CS_REST_LOG_WARNING);

	    $call_result = $this->_transport->make_call($call_options);

	    $this->_log->log_message('Call result: <pre>' . var_export($call_result, true) . '</pre>', get_class($this), CS_REST_LOG_VERBOSE);

	    if ($call_options['deserialise'])
	    {
		$call_result['response'] = $this->_serialiser->deserialise($call_result['response']);
	    }

	    return new CS_REST_Wrapper_Result($call_result['response'], $call_result['code']);
	}

    }

}