<?php



/**

 * @name iContactApi

 * @package iContact

 * @author iContact <www.icontact.com>

 * @description This class is a wrapper for the iContact API.  

 * It makes integrating iContact into your app as simple as 

 * calling a method.

 * @version 2.0

 * */

if (!class_exists('iContactApi'))

{



	class iContactApi

	{



		//////////////////////////////////////////////////////////////////////////////

		/// Properties //////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////////



		protected static $oInstance = null;	// This holds the instance of this class

		protected $iAccountId = null;	// This holds the account ID

		protected $iClientFolderId = null;	// This holds the client folder ID

		protected $aConfig = array(); // This is our array for pragmatically overriding configuration constants

		protected $aErrors = array(); // This holds the errors encountered with the iContact API

		protected $sLastRequest = null;	// This holds the last request JSON

		protected $sLastResponse = null;	// This holds the last response JSON

		protected $sRequestUri = null;	// This stores the last used URL

		protected $bSandbox = false;   // This tells the system whether or not to use the iContact Sandbox or not

		protected $aSearchParameters = array(); // This is our container for search params

		protected $iTotal = 0;	   // If the results return a total, it will be stored here

		protected $aWarnings = array(); // This holds the warnings encountered with the iContact API



		//////////////////////////////////////////////////////////////////////////////

		/// Singleton ///////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////////



		/**

		 * This sets the singleton pattern instance

		 * @static

		 * @access public

		 * @param iContactApi $oInstance Instance to set to

		 * @return iContactApi $this

		 * */

		public static function setInstance($oInstance)

		{



			self::$oInstance = $oInstance;

			// Return instance of class

			return self::$oInstance;

		}



		/**

		 * This gets the singleton instance

		 * @static

		 * @access public

		 * @return iContactApi $this

		 * */

		public static function getInstance()

		{

			// Check to see if an instance has already

			// been created

			if (is_null(self::$oInstance))

			{

				// If not, return a new instance

				self::$oInstance = new self();

				return self::$oInstance;

			}

			else

			{

				// If so, return the previously created

				// instance

				return self::$oInstance;

			}

		}



		/**

		 * This resets the singleton instance to null

		 * @static

		 * @access public

		 * @return void

		 * */

		public static function resetInstance()

		{

			// Reset the instance

			self::$oInstance = null;

		}



		//////////////////////////////////////////////////////////////////////////////

		/// Constructor /////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////////



		/**

		 * This is our constuctor and simply checks for

		 * defined constants and configuration values and 

		 * then builds the configuration from that

		 * @access protected

		 * @return iContactApi $this

		 * */

		protected function __construct()

		{

			// Check for constants

			$aConstantMap = array(

				// 'ICONTACT_APIVERSION', 

				// 'ICONTACT_APISANDBOXURL', 

				'ICONTACT_APPID' => 'appId',

				// 'ICONTACT_APIURL', 

				'ICONTACT_APIUSERNAME' => 'apiUsername',

				'ICONTACT_APIPASSWORD' => 'apiPassword'

			);

			// Loop through the map

			foreach ($aConstantMap as $sConstant => $sConfigKey)

			{

				// Check for the defined constant

				if (defined($sConstant))

				{

					// Set the configuration key to the contant's value

					$this->aConfig[$sConfigKey] = constant($sConstant);

				}

			}

			// Return instance

			return $this;

		}



		//////////////////////////////////////////////////////////////////////////////

		/// Public //////////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////////



		/**

		 * This method adds a contact to your iContact account

		 * @access public

		 * @param string $sEmail

		 * @param string [$sStatus]

		 * @param string [$sPrefix]

		 * @param string [$sFirstName]

		 * @param string [$sLastName]

		 * @param string [$sSuffix]

		 * @param string [$sStreet]

		 * @param string [$sStreet2]

		 * @param string [$sCity]

		 * @param string [$sState]

		 * @param string [$sPostalCode]

		 * @param string [$sPhone]

		 * @param string [$sFax]

		 * @param string [$sBusiness]

		 *

		 * @return object

		 * */

		public function addContact($sEmail, $sStatus = 'normal', $sPrefix = null, $sFirstName = null, $sLastName = null, $sSuffix = null, $sStreet = null, $sStreet2 = null, $sCity = null, $sState = null, $sPostalCode = null, $sPhone = null, $sFax = null, $sBusiness = null)

		{

			// Valid statuses

			$aValidStatuses = array('normal', 'bounced', 'donotcontact', 'pending', 'invitable', 'deleted');

			// Contact placeholder

			$aContact = array(

				'email' => $sEmail

			);

			// Check for a prefix

			if (!empty($sPrefix))

			{

				// Add the new prefix

				$aContact['prefix'] = (string) $sPrefix;

			}

			// Check for a first name

			if (!empty($sFirstName))

			{

				// Add the new first name

				$aContact['firstName'] = (string) $sFirstName;

			}

			// Check for a last name

			if (!empty($sLastName))

			{

				// Add the new last name

				$aContact['lastName'] = (string) $sLastName;

			}

			// Check for a suffix

			if (!empty($sSuffix))

			{

				// Add the new suffix

				$aContact['suffix'] = (string) $sSuffix;

			}

			// Check for a street

			if (!empty($sStreet))

			{

				// Add the new street

				$aContact['street'] = (string) $sStreet;

			}

			// Check for a street2

			if (!empty($sStreet2))

			{

				// Add the new street 2

				$aContact['street2'] = (string) $sStreet2;

			}

			// Check for a city

			if (!empty($sCity))

			{

				// Add the new city

				$aContact['city'] = (string) $sCity;

			}

			// Check for a state

			if (!empty($sState))

			{

				// Add the new state

				$aContact['state'] = (string) $sState;

			}

			// Check for a postal code

			if (!empty($sPostalCode))

			{

				// Add the new postal code

				$aContact['postalCode'] = (string) $sPostalCode;

			}

			// Check for a phone number

			if (!empty($sPhone))

			{

				// Add the new phone number

				$aContact['phone'] = (string) $sPhone;

			}

			// Check for a fax number

			if (!empty($sFax))

			{

				// Add the new fax number

				$aContact['fax'] = (string) $sFax;

			}

			// Check for a business name

			if (!empty($sBusiness))

			{

				// Add the new business

				$aContact['business'] = (string) $sBusiness;

			}

			// Check for a valid status

			if (!empty($sStatus) && in_array($sStatus, $aValidStatuses))

			{

				// Add the new status

				$aContact['status'] = $sStatus;

			}

			else

			{

				$aContact['status'] = 'normal';

			}



			// Make the call

			$aContacts = $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/contacts", 'POST', array($aContact), 'contacts');

			// Return the contact

			return $aContacts[0];

		}



		/**

		 * This method adds a custom field or "term"

		 * to the array of search parameters

		 * @access public

		 * @param string $sName

		 * @param string $sValue

		 * @return iContactApi $this

		 * */

		public function addCustomQueryField($sName, $sValue)

		{

			// Add the field

			$this->aSearchParameters[$sName] = (string) $sValue;

			// Return instance

			return $this;

		}



		/**

		 * This message adds a list to your iContact account

		 * @access public

		 * @param string $sName

		 * @param integer $iWelcomeMessageId

		 * @param bool [$bEmailOwnerOnChange]

		 * @param bool [$bWelcomeOnManualAdd]

		 * @param bool [$bWelcomeOnSignupAdd]

		 * @param string [$sDescription]

		 * @param string [$sPublicName]

		 * @return object

		 * */

		public function addList($sName, $iWelcomeMessageId, $bEmailOwnerOnChange = true, $bWelcomeOnManualAdd = false, $bWelcomeOnSignupAdd = false, $sDescription = null, $sPublicName = null)

		{

			// Setup the list

			$aList = array(

				'name' => $sName,

				'welcomeMessageId' => $iWelcomeMessageId,

				'emailOwnerOnChange' => intval($bEmailOwnerOnChange),

				'welcomeOnManualAdd' => intval($bWelcomeOnManualAdd),

				'welcomeOnSignupAdd' => intval($bWelcomeOnSignupAdd),

				'description' => $sDescription,

				'publicname' => $sPublicName

			);

			// Make the call

			$aLists = $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/lists", 'POST', array($aList), 'lists');

			// Return the list

			return $aLists[0];

		}



		/**

		 * This method adds a message to 

		 * your iContact API account

		 * @access public

		 * @param string $sSubject

		 * @param integer $iCampaignId

		 * @param string [$sHtmlBody]

		 * @param string [$sTextBody]

		 * @param string [$sMessageName]

		 * @param integer [$iListId]

		 * @param string [$sMessageType]

		 * @return object

		 * */

		public function addMessage($sSubject, $iCampaignId, $sHtmlBody = null, $sTextBody = null, $sMessageName = null, $iListId = null, $sMessageType = 'normal')

		{

			// Valid message types

			$aValidMessageTypes = array('normal', 'autoresponder', 'welcome', 'confirmation');

			// Setup the message data

			$aMessage = array(

				'campaignId' => $iCampaignId,

				'htmlBody' => $sHtmlBody,

				'messageName' => $sMessageName,

				'messageType' => (in_array($sMessageType, $aValidMessageTypes) ? $sMessageType : 'normal'),

				'subject' => $sSubject,

				'textBody' => $sTextBody

			);

			// Add the message

			$aNewMessage = $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/messages", 'POST', array($aMessage), 'messages');

			// Return the message data

			return $aNewMessage[0];

		}



		/**

		 * This method adds a field to the order by

		 * key in the search parameters array

		 * @access public

		 * @param string $sField

		 * @param string [$sDirection]

		 * @return iContactApi $this

		 * */

		public function addOrderBy($sField, $sDirection = null)

		{

			// Check for existing order by parameters

			if (empty($this->aSearchParameters['orderby']))

			{

				// Check for a direction

				if (empty($sDirection))

				{

					// Add just the field

					$this->aSearchParameters['orderby'] = (string) $sField;

				}

				else

				{

					// Add the field and direction

					$this->aSearchParameters['orderby'] = (string) "{$sField}:{$sDirection}";

				}

			}

			else

			{

				// Check for a direction

				if (empty($sDirection))

				{

					// Append just the field

					$this->aSearchParameters['orderby'] .= (string) ",{$sField}";

				}

				else

				{

					// Append the field and direction

					$this->aSearchParameters['orderby'] .= (string) ",{$sField}:{$sDirection}";

				}

			}

			// Return failure

			return false;

		}



		/**

		 * This method handles the deleting of a single list

		 * @access public

		 * @param integer $iListId

		 * @return bool

		 * */

		public function deleteList($iListId)

		{

			// Delete the list

			return $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/lists/{$iListId}", 'delete');

		}



		/**

		 * This method handles the handshaking between this app and the iContact API

		 * @access public

		 * @param string $sResource

		 * @param string $sMethod

		 * @param string $sReturnKey

		 * @param mixed  $mPostData Array, object, or string

		 * @return array|object

		 * */

		public function makeCall($sResource, $sMethod = 'GET', $mPostData = null, $sReturnKey = null)

		{

			// List of needed constants

			$aRequiredConfigs = array('apiPassword', 'apiUsername', 'appId');

			// First off check for definitions

			foreach ($aRequiredConfigs as $sKey)

			{

				// Is it defined

				if (empty($this->aConfig[$sKey]))

				{

					// Set an error

					$this->addError("{$sKey} is undefined.");

				}

			}

			// Set the URI that we will be calling

			$sApiUrl = (string) "{$this->getUrl()}{$sResource}";

			// Initialize the cURL handle

			$rHandle = curl_init();

			// Give our handle headers

			curl_setopt($rHandle, CURLOPT_HTTPHEADER, $this->getHeaders());

			// Tell our handle that we 

			// want the data returned

			curl_setopt($rHandle, CURLOPT_RETURNTRANSFER, true);

			// Turn SSL verifcation off, so scripts do not get broken

			curl_setopt($rHandle, CURLOPT_SSL_VERIFYPEER, false);

			// Determine the request

			// method we are using

			switch (strtoupper($sMethod))

			{

				// Deleting data

				case 'DELETE' :

					// Set the cURL custom header

					curl_setopt($rHandle, CURLOPT_CUSTOMREQUEST, 'DELETE');

					break;

				// Recieving data

				case 'GET' :

					// Check for a query string

					if (!empty($this->aSearchParameters))

					{

						// Add the query string

						$sApiUrl .= (string) '?' . http_build_query($this->aSearchParameters);

					}

					break;

				// Sending data

				case 'POST' :

					// Check for POST data

					if (empty($mPostData))

					{

						// Add an error, for there is no

						// POST data to send to the API

						$this->addError('No POST data was provided.');

					}

					else

					{

						// Tell our handle that 

						// we want to send data

						curl_setopt($rHandle, CURLOPT_POST, true);

						// Give our handle the data

						curl_setopt($rHandle, CURLOPT_POSTFIELDS, json_encode($mPostData));

						// Set the request JSON

						$this->sLastRequest = (string) json_encode($mPostData);

					}

					break;

				// Uploading data

				case 'PUT' :

					if (empty($mPostData))

					{

						// Is there data?

						$this->addError('No file or data specified for PUT request');

					}

					elseif (!is_string($mPostData) || !file_exists($mPostData))

					{

						// Not a file, so we assume this is just data

						curl_setopt($rHandle, CURLOPT_CUSTOMREQUEST, "PUT");

						curl_setopt($rHandle, CURLOPT_POSTFIELDS, $mPostData);

					}

					else

					{

						$rFileContentHandle = fopen($mPostData, 'r');

						if ($rFileContentHandle === false)

						{

							$this->addError('A non-existant file was specified for POST data, or the file could not be opened.');

						}

						else

						{

							// Found a file, so upload its contents

							curl_setopt($rHandle, CURLOPT_PUT, true);

							curl_setopt($rHandle, CURLOPT_INFILE, $rFileContentHandle);

						}

					}

					break;

			}

			// Store the URL into the instance

			$this->sRequestUri = (string) $sApiUrl;

			// Give our handle a URL

			curl_setopt($rHandle, CURLOPT_URL, $sApiUrl);

			// Try to execute the handle

			if (!$sResponse = curl_exec($rHandle))

			{

				// Add an error, for we could

				// not even execute the handle

				$this->addError('We were unable to execute the cURL handle.');

			}

			// Set the response JSON

			$this->sLastResponse = (string) $sResponse;

			// Try to decode the response

			if ((!$aResponse = json_decode($sResponse)) && (strtoupper($sMethod) != 'DELETE'))

			{

				// Add an error, for the API

				// did not return valid JSON

				$this->addError('The iContact API did not return valid JSON.');

			}

			// Close the cURL handle

			curl_close($rHandle);

			// Check for errors from the API

			if (!empty($aResponse->errors))

			{

				// Loop through the errors

				foreach ($aResponse->errors as $sError)

				{

					// Add the error

					$this->addError($sError, 1);

				}

			}

			// Check for warnings from the API

			if (!empty($aResponse->warnings))

			{

				// Loop through the warnings

				foreach ($aResponse->warnings as $sWarning)

				{

					// Add the warning

					$this->addWarning($sWarning);

				}

			}

			// Check for set errors

			if (!empty($this->aErrors))

			{

				// Throw a new exception

				throw new Exception('Errors have occurred and the system cannot continue.  Use getErrors() for details.');

			}

			// Check for a total

			if (!empty($aResponse->total))

			{

				// Store the total records

				// into the current instsnce

				$this->iTotal = (integer) $aResponse->total;

			}

			// Return the response

			if (strtoupper($sMethod) == 'DELETE')

			{

				// Return success

				return true;

			}

			elseif (empty($sReturnKey))

			{

				// Return the entire 

				// base response

				return $aResponse;

			}

			else

			{

				// Return the narrowed resposne

				return $aResponse->$sReturnKey;

			}

		}



		/**

		 * This method sends a message

		 * @access public

		 * @param string $sIncludeListId

		 * @param integer $iMessageId

		 * @param string [$sExcludeListIds]

		 * @param string [$sExcludeSegmentIds]

		 * @param string [$sIncludeSegmentIds]

		 * @param string [$sScheduledTime]

		 * @return object

		 * */

		public function sendMessage($sIncludeListIds, $iMessageId, $sExcludeListIds = null, $sExcludeSegmentIds = null, $sIncludeSegmentIds = null, $sScheduledTime = null)

		{

			// Send the message

			$aSends = $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/sends", 'POST', array(

				array(

					'excludeListIds' => $sExcludeListIds,

					'excludeSegmentIds' => $sExcludeSegmentIds,

					'includeListIds' => $sIncludeListIds,

					'includeSegmentIds' => $sIncludeSegmentIds,

					'scheduledTime' => (empty($sScheduledTime) ? null : date('c', strtotime($sScheduledTime)))

				)

					), 'sends');

			// Return the send

			return $aSends;

		}



		/**

		 * This method subscribes a contact to a list

		 * @access public

		 * @param integer $iContactId

		 * @param integer $iListId

		 * @param string  $sStatus

		 * @return object

		 * */

		public function subscribeContactToList($iContactId, $iListId, $sStatus = 'normal')

		{

			// Valid statuses

			$aValidStatuses = array('normal', 'pending', 'unsubscribed');

			// Setup the subscription and make the call

			$aSubscriptions = $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/subscriptions", 'POST', array(

				array(

					'contactId' => $iContactId,

					'listId' => $iListId,

					'status' => $sStatus

				)

					), 'subscriptions');

			// Return the subscription

			return $aSubscriptions;

		}



		/**

		 * This method updates a contact in your iContact account

		 * @access public

		 * @param integer $iContactId

		 * @param string  $sEmail

		 * @param string  $sPrefix

		 * @param string  $sFirstName

		 * @param string  $sLastName

		 * @param string  $sSuffix

		 * @param string  $sStreet

		 * @param string  $sStreet2

		 * @param string  $sCity

		 * @param string  $sState

		 * @param string  $sPostalCode

		 * @param string  $sPhone

		 * @param string  $sFax

		 * @param string  $sBusiness

		 * @param string  $sStatus

		 * @return bool|object

		 * */

		public function updateContact($iContactId, $sEmail = null, $sPrefix = null, $sFirstName = null, $sLastName = null, $sSuffix = null, $sStreet = null, $sStreet2 = null, $sCity = null, $sState = null, $sPostalCode = null, $sPhone = null, $sFax = null, $sBusiness = null, $sStatus = null)

		{

			// Valid statuses

			$aValidStatuses = array('normal', 'bounced', 'donotcontact', 'pending', 'invitable', 'deleted');

			// Contact placeholder

			$aContact = array();

			// Check for an email address

			if (!empty($sEmail))

			{

				// Add the new email

				$aContact['email'] = (string) $sEmail;

			}

			// Check for a prefix

			if (!empty($sPrefix))

			{

				// Add the new prefix

				$aContact['prefix'] = (string) $sPrefix;

			}

			// Check for a first name

			if (!empty($sFirstName))

			{

				// Add the new first name

				$aContact['firstName'] = (string) $sFirstName;

			}

			// Check for a last name

			if (!empty($sLastName))

			{

				// Add the new last name

				$aContact['lastName'] = (string) $sLastName;

			}

			// Check for a suffix

			if (!empty($sSuffix))

			{

				// Add the new suffix

				$aContact['suffix'] = (string) $sSuffix;

			}

			// Check for a street

			if (!empty($sStreet))

			{

				// Add the new street

				$aContact['street'] = (string) $sStreet;

			}

			// Check for a street2

			if (!empty($sStreet2))

			{

				// Add the new street 2

				$aContact['street2'] = (string) $sStreet2;

			}

			// Check for a city

			if (!empty($sCity))

			{

				// Add the new city

				$aContact['city'] = (string) $sCity;

			}

			// Check for a state

			if (!empty($sState))

			{

				// Add the new state

				$aContact['state'] = (string) $sState;

			}

			// Check for a postal code

			if (!empty($sPostalCode))

			{

				// Add the new postal code

				$aContact['postalCode'] = (string) $sPostalCode;

			}

			// Check for a phone number

			if (!empty($sPhone))

			{

				// Add the new phone number

				$aContact['phone'] = (string) $sPhone;

			}

			// Check for a fax number

			if (!empty($sFax))

			{

				// Add the new fax number

				$aContact['fax'] = (string) $sFax;

			}

			// Check for a business name

			if (!empty($sBusiness))

			{

				// Add the new business

				$aContact['business'] = (string) $sBusiness;

			}

			// Check for a valid status

			if (!empty($sStatus) && in_array($sStatus, $aValidStatuses))

			{

				// Add the new status

				$aContact['status'] = $sStatus;

			}

			// Make sure the contact isn't empty

			if (!empty($aContact))

			{

				// Make the call

				$oContact = $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/contacts/{$iContactId}", 'POST', array($aContact), 'contact');

				// Return the contact

				return $oContact;

			}

			// Inevitably return failure

			return false;

		}



		/**

		 * This method uploads a CSV file to the iContact API

		 * @access public

		 * @param string $sFile

		 * @param integer [$iListId]

		 * @param integer [$iUploadId]

		 * @return string|bool

		 * */

		public function uploadData($sFile, $iListId = null, $iUploadId = null)

		{

			// Check for an upload ID

			if (empty($iUploadId))

			{

				// Make the call

				$aUploads = $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/uploads", 'POST', array(

					array(

						'action' => 'add',

						'listIds' => $iListId

					)

						), 'uploads');

				// Store the uploadID

				$iUploadId = $aUploads[0]->uploadId;

			}

			// Upload the data

			if ($this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/uploads/{$iUploadId}/data", 'PUT', $sFile, 'uploadId'))

			{

				// Loop until the upload is complete

				while (true)

				{

					// Grab the upload

					$aUpload = $this->getUpload($iUploadId);

					// Check to see if the upload

					// has finished uploading

					if ($aUpload->status != 'receiving')

					{

						// Return the upload

						return $this->makeCall("/a/{$this->setAccountId()}/c{$this->setClientFolderId()}/uploads/{$iUploadId}/data", 'GET');

					}

				}

			}

			// Return failure

			return false;

		}



		/**

		 * This message updates a list on your iContact account

		 * @access public

		 * @param string $sName

		 * @param integer $iListId

		 * @param string $sName

		 * @param integer $iWelcomeMessageId

		 * @param bool [$bEmailOwnerOnChange]

		 * @param bool [$bWelcomeOnManualAdd]

		 * @param bool [$bWelcomeOnSignupAdd]

		 * @param string [$sDescription]

		 * @param string [$sPublicName]

		 * @return object

		 * */

		public function updateList($iListId, $sName, $iWelcomeMessageId, $bEmailOwnerOnChange = true, $bWelcomeOnManualAdd = false, $bWelcomeOnSignupAdd = false, $sDescription = null, $sPublicName = null)

		{

			// Setup the list

			$aList = array(

				'name' => $sName,

				'welcomeMessageId' => $iWelcomeMessageId,

				'emailOwnerOnChange' => intval($bEmailOwnerOnChange),

				'welcomeOnManualAdd' => intval($bWelcomeOnManualAdd),

				'welcomeOnSignupAdd' => intval($bWelcomeOnSignupAdd),

				'description' => $sDescription,

				'publicname' => $sPublicName

			);

			// Return the list

			return $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/lists/{$iListId}", 'POST', $aList, 'list');

			;

		}



		/**

		 * This method tells the system whether

		 * or not to use the sandbox or not, the

		 * sandbox is turned off by defualt and 

		 * by default this method turns it on

		 * @access public

		 * @param bool [$bUse]

		 * @return iContactApi $this

		 * */

		public function useSandbox($bUse = true)

		{

			// Set the sandbox status

			$this->bSandbox = (bool) $bUse;

			// Return instance

			return $this;

		}



		//////////////////////////////////////////////////////////////////////////////

		/// PROTECTED ///////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////////



		/**

		 * This method appends an error to the list

		 * of errors encountered with the iContact API

		 * @access protected

		 * @param string $sText

		 * @param integer [$iCode]

		 * @return iContactApi $this

		 * */

		protected function addError($sText)

		{

			// Append the error

			array_push($this->aErrors, $sText);

			// Return instance

			return $this;

		}



		/**

		 * This method appends a warning to the list

		 * of warnings encountered with the iContact API

		 * @access protected

		 * @param string $sText

		 * @return iContactApi $this

		 * */

		public function addWarning($sText)

		{

			// Append the warning

			array_push($this->aWarnings, $sText);

			// Return instance

			return $this;

		}



		//////////////////////////////////////////////////////////////////////////////

		/// Getters /////////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////////



		/**

		 * This method grabs the campaigns associated

		 * your iContact account

		 * @access public

		 * @return object

		 * */

		public function getCampaigns()

		{

			// Make the call and return the data

			return $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/campaigns", 'GET');

		}



		/**

		 * This method grabs a single contact

		 * from your iContact Account

		 * @access public

		 * @param integer $iContactId

		 * @return object

		 * */

		public function getContact($iContactId)

		{

			// Make the call and return the data

			return $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/contacts/{$iContactId}", 'GET', null, 'contact');

		}



		/**

		 * This method grabs the contacts associated

		 * with you iContact API account

		 * @access public

		 * @return array

		 * */

		public function getContacts()

		{

			// Make the call and return the data

			return $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/contacts", 'GET');

		}



		/**

		 * This method returns any set 

		 * errors in the current instance

		 * @access public

		 * @return array|bool

		 * */

		public function getErrors()

		{

			// Check for errors

			if (empty($this->aErrors))

			{

				// Return false, for 

				// there are no errors

				return false;

			}

			else

			{

				// Return the errors

				return $this->aErrors;

			}

		}



		/**

		 * This method builds the header array

		 * for making calls to the API

		 * @access public

		 * @return array

		 * */

		public function getHeaders()

		{

			// Return the headers

			return array(

				'Except:',

				'Accept:  application/json',

				'Content-type:  application/json',

				'Api-Version:  ' . (defined('ICONTACT_APIVERSION') ? constant('ICONTACT_APIVERSION') : '2.2'),

				'Api-AppId:  ' . (!empty($this->aConfig['appId']) ? $this->aConfig['appId'] : constant('ICONTACT_APPID')),

				'Api-Username:  ' . (!empty($this->aConfig['apiUsername']) ? $this->aConfig['apiUsername'] : constant('ICONTACT_APIUSERNAME')),

				'Api-Password:  ' . (!empty($this->aConfig['apiPassword']) ? $this->aConfig['apiPassword'] : constant('ICONTACT_APIPASSWORD'))

			);

		}



		/**

		 * This method returns the last 

		 * API POST request JSON

		 * @access public

		 * @param bool [$bDecode]

		 * @return string|object

		 * */

		public function getLastRequest($bDecode = false)

		{

			// Check to see if we need

			// to decode the raw JSON

			if ($bDecode === true)

			{

				// Return the decoded JSON

				return json_decode($this->sLastRequest);

			}

			// Return the raw JSON

			return $this->sLastRequest;

		}



		/**

		 * This method returns the last

		 * API response JSON

		 * @access public

		 * @param bool [$bDecode]

		 * @return string|object

		 * */

		public function getLastResponse($bDecode = false)

		{

			// Check to see if we need

			// to decode the raw JSON

			if ($bDecode === true)

			{

				// Return the decoded JSON

				return json_decode($this->sLastResponse);

			}

			// Return the raw JSON

			return $this->sLastResponse;

		}



		/**

		 * This method grabs a list of lists

		 * that are associated with you iContact

		 * API account

		 * @access public

		 * @return array

		 * */

		public function getLists()

		{

			// Make the call and return the lists

			return $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/lists", 'GET', null, 'lists');

		}



		/**

		 * This method lists the opens of a

		 * single message based on the messageID

		 * @access public

		 * @param integer iMessageId

		 * @return integer

		 * */

		public function getMessageOpens($iMessageId)

		{

			// Make the call and return the data

			return $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/messages/{$iMessageId}/opens", 'GET', null, 'total');

		}



		public function getMessages($sType = null)

		{

			// Check for a message type

			if (!empty($sType))

			{

				$this->addCustomQueryField('messageType', $sType);

			}

			// Return the messages

			return $this->makeCall("/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}/messages", 'GET', null, 'messages');

		}



		/**

		 * This method returns the URL

		 * that the last API request

		 * called

		 * @access public

		 * @return string

		 * */

		public function getRequestUri()

		{

			// Return the URL

			return $this->sRequestUri;

		}



		/**

		 * This method returns the count of the

		 * total number of records from the most

		 * recent API call, if there is one

		 * @access public

		 * @return integer

		 * */

		public function getTotal()

		{

			// Return the total records

			return $this->iTotal;

		}



		/**

		 * This method simply returns the base URL for 

		 * your API/Sandbox account

		 * @access public

		 * @param bool [$bFull]

		 * @return string

		 * */

		public function getUrl($bFull = false)

		{

			// Set the sandbox URL

			$sSandboxUrl = defined('ICONTACT_APISANDBOXURL') ? constant('ICONTACT_APISANDBOXURL') : 'https://app.sandbox.icontact.com/icp';

			// Set the production URL

			$sApiUrl = defined('ICONTACT_APIURL') ? constant('ICONTACT_APIURL') : 'https://app.icontact.com/icp';

			// Determine which one needs to be returned with the URL

			$sBaseUrl = ($this->bSandbox === true) ? $sSandboxUrl : $sApiUrl;

			// Do we need to return the entire url or just 

			// the base url of the API service

			if ($bFull === false)

			{

				// Return the base url

				return $sBaseUrl;

			}

			else

			{

				// Return the base url and account details

				return $sBaseUrl . "/a/{$this->setAccountId()}/c/{$this->setClientFolderId()}";

			}

		}



		/**

		 * This method grabs a specific upload

		 * @access public

		 * @param integer $iUploadId

		 * @return object

		 * */

		public function getUpload($iUploadId)

		{

			// Return the upload data

			return $this->makeCall("/a/{$this->setAccountId()}/c{$this->setClientFolderId()}/uploads/{$iUploadId}/data");

		}



		/**

		 * This method grabs the uploads associated

		 * with your iContact Account

		 * @access public

		 * @return array

		 * */

		public function getUploads()

		{

			// Return the uploads

			return $this->makeCall("/a/{$this->setAccountId()}/c{$this->setClientFolderId()}/uploads");

		}



		/**

		 * This method returns the warnings encountered

		 * while communicating with the iContact API

		 * @access public

		 * @return array

		 * */

		public function getWarnings()

		{

			// Return the current system warnings

			return $this->aWarnings;

		}



		//////////////////////////////////////////////////////////////////////////////

		/// Setters /////////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////////



		/**

		 * This method fetches the Account ID

		 * from the iContact API if it has not

		 * already been stored in the instance

		 * @access public

		 * @param integer [$iAccountId]

		 * @return integer

		 * */

		public function setAccountId($iAccountId = null)

		{

			// Check for an overriding

			// Account ID

			if (!empty($iAccountId))

			{

				// Override the Account ID

				$this->iAccountId = (integer) $iAccountId;

			}

			else

			{

				// Check to see if the 

				// Account ID has already

				// been stored in the 

				// instance

				if (empty($this->iAccountId))

				{

					// Load the Account ID

					if ($aAccounts = $this->makeCall('/a/', 'get', null, 'accounts'))

					{

						// Set the account

						$aAccount = $aAccounts[0];

						// Make sure the account is active

						if (intval($aAccount->enabled) === 1)

						{

							// The account is active

							// set the Account ID

							$this->iAccountId = (integer) $aAccount->accountId;

						}

						else

						{

							// Set an error, for this account

							// has been disabled

							$this->addError('Your account has been disabled.');

						}

					}

				}

			}

			// Inevitably return instance

			return $this->iAccountId;

		}



		/**

		 * This method fetches the Client 

		 * Folder ID from the iContact API

		 * if it has not already been stored 

		 * in the instance and the Account ID

		 * has also been stored in the instance

		 * @access public

		 * @param integer [$iClientFolderId]

		 * @return integer

		 * */

		public function setClientFolderId($iClientFolderId = null)

		{

			// Check for an overriding 

			// Client Folder ID

			if (!empty($iClientFolderId))

			{

				// Set the Client Folder ID

				$this->iClientFolderId = (integer) $iClientFolderId;

			}

			elseif (empty($this->iClientFolderId))

			{

				// Check for an Account ID

				if (empty($this->iAccountId))

				{

					// Set the Account ID

					$this->setAccountId();

				}

				// Set the resource

				$sResource = (string) "/a/{$this->iAccountId}/c/";

				// Find the Client Folder ID

				if ($aClients = $this->makeCall($sResource, 'get', null, 'clientfolders'))

				{

					if (empty($aClients))

					{

						// Add an error, for there

						// are no client folders

						$this->addError('No client folders were found for this account.');

					}

					else

					{

						// Grab the default client folder

						$aClient = $aClients[0];

						// Set the Client Folder ID

						$this->iClientFolderId = (integer) $aClient->clientFolderId;

					}

				}

			}

			// Inevitably return instance

			return $this->iClientFolderId;

		}



		/**

		 * This method sets configuration into the

		 * plugin to pragmatically override constants

		 * @access public

		 * @param array $aConfig

		 * @return iContactApi $this

		 * */

		public function setConfig($aConfig)

		{

			// Combine the arrays

			$this->aConfig = (array) array_merge($this->aConfig, $aConfig);

			// Return instance

			return $this;

		}



		/**

		 * This method sets the result limit

		 * for GET requests to the iContact API

		 * @access public

		 * @param integer $iLimit

		 * @return iContactApi $this

		 * */

		public function setLimit($iLimit)

		{

			// Set the limit in the search parameters

			$this->aSearchParameters['limit'] = (integer) $iLimit;

			// Return instance

			return $this;

		}



		/**

		 * This method sets the result index

		 * offset for paginating results from

		 * GET requests to the iContact API

		 * @access public

		 * @param integer $iOffset

		 * @return iContactApi $this

		 * */

		public function setOffset($iOffset)

		{

			// Set the offset in the search parameters

			$this->aSearchParameters['offset'] = (integer) $iOffset;

			// Return instance

			return $this;

		}



	}



}

?>