<?php
/**
 * @filename        MSHiContact.php
 * @description     This class is for using iContacts API 2.0. This class is based on the PHP sample code provided by iContact.
 * @version         1.0
 * @package
 * @author          Mohammad Sajjad Hossain - info@sajjadhossain.com
 *
 * @link            http://sajjadhossain.com
 * @created on      April 15, 2011
 * @Dependencies
 * @license
 ***/
class MSHiContact{
    private $testHost = 'https://app.sandbox.icontact.com/icp/';
    private $host = 'https://app.icontact.com/icp/';
    private $requestURL = '';
    private $testRequestURL = '';
    private $targetScript = '';
    private $requestString = '';

    /**
    *@desc Obtained when one register the API application. This identifier is used to uniquely identify the application.
    */
    private $appId = '';

    /**
    *@desc The iContact username for logging into iContact account. If you are using the sandbox for testing, this is your sandbox environment username.
    */
    private $userName = '';

    /**
    *@desc The API application password set when the application was registered. This API password is used as input when your application authenticates to the API.
    */
    private $password = '';

    /**
    *@desc Account ID
    */
    private $accountId = 0;

    /**
    *@desc Client Folder ID
    */
    private $clientFolderId = 0;

    /**
    *@desc List of accounts
    */
    private $accounts = array();

    /**
    *@desc List of client folders
    */
    private $clientFolders = array();

    /**
    *@desc List ID
    */
    private $listId = 0;

    /**
    *@desc List of lists
    */
    private $lists = array();

    /**
    *@desc Subscription ID
    */
    private $subscriptionId = 0;

    /**
    *@desc Recuest method. Possible values GET, POST, PUT, DELETE
    */
    private $method = 'GET';

    /**
    *@desc Enable/disable test mode
    */
    private $testMode = false;

    /**
    *@desc Enable/disable debugging
    */
    private $debug = false;

    //Contact Information
    /**
    *@desc Contact ID
    */
    private $contactId = 0;

    /**
    *@desc First name of the contact
    */
    private $firstName = '';

    /**
    *@desc Last name of the contact
    */
    private $lastName = '';

    /**
    *@desc Email address of the contact
    */
    private $email = '';

    /**
    *@desc Address Line 1 of the contact
    */
    private $address1 = '';

    /**
    *@desc Address Line 2 of the contact
    */
    private $address2 = '';

    /**
    *@desc City name of the contact
    */
    private $city = '';

    /**
    *@desc State name of the contact
    */
    private $state = '';

    /**
    *@desc Zip code of the contact
    */
    private $zip = '';

    /**
    *@desc Phone number of the contact
    */
    private $phone = '';

    //Response Variables
    /**
    *@desc Full response returned by iContact
    */
    private $rawResponse;

    /**
    *@desc If request successful or not
    */
    private $isSuccess = false;

    /**
    *@desc List of errors
    */
    private $errors = array();

    /**
    *@desc Constructor
    */
    public function MSHiContact(){}

    /**
    *@desc Sets API APP ID
    */
    public function setAPIAppID($id){
        $this->appId = trim($id);
    }

    /**
    *@desc Sets API User Name
    */
    public function setAPIUserName($name){
        $this->userName = trim($name);
    }

    /**
    *@desc Sets API Password
    */
    public function setAPIPassword($password){
        $this->password = trim($password);
    }

    /**
    *@desc Sets Account ID
    */
    public function setAccountId($id){
        $this->accountId = $id;
    }

    /**
    *@desc Sets Client Folder ID
    */
    public function setClientFolderId($id){
        $this->clientFolderId = $id;
    }

    /**
    *@desc Sets List ID
    */
    public function setListId($id){
        $this->listId = $id;
    }

    /**
    *@desc Sets contact ID
    */
    public function setContactId($id){
        $this->contactId = $id;
    }

    /**
    *@desc Sets First Name
    */
    public function setFirstName($name){
        $this->firstName = $name;
    }

    /**
    *@desc Sets Last Name
    */
    public function setLastName($name){
        $this->lastName = $name;
    }

    /**
    *@desc Sets email address
    */
    public function setEmail($email){
        $this->email = $email;
    }

    /**
    *@desc Sets address line 1
    */
    public function setAddressLine1($addr){
        $this->address1 = $addr;
    }

    /**
    *@desc Sets address line 2
    */
    public function setAddressLine2($addr){
        $this->address2 = $addr;
    }

    /**
    *@desc Stes city
    */
    public function setCity($city){
        $this->city = $city;
    }

    /**
    *@desc Sets state
    */
    public function setState($state){
        $this->state = $state;
    }

    /**
    *@desc Sets zip code
    */
    public function setZipCode($zip){
        $this->zip = $zip;
    }

    /**
    *@desc Sets phone
    */
    public function setPhone($phone){
        $this->phone = $phone;
    }

    /**
    *@desc Returns contact ID
    */
    public function getContactId(){
        return $this->contactId;
    }

    /**
    *@desc Returns request URL
    */
    private function getRequestURL(){
        $url = '';
        if($this->testMode){
            $url = $this->testHost . $this->targetScript;
        }
        else{
            $url = $this->host . $this->targetScript;
        }
        $this->logMessage('Sending request to: ' . $url);
        return $url;
    }

    /**
    *@desc Enables test mode
    */
    public function enableTestMode(){
        $this->testMode = true;
    }

    /**
    *@desc Enables debug mode
    */
    public function enableDebugging(){
        $this->debug = true;
    }

    /**
    *@desc Sends request
    */
    private function postRequest(){
        $this->validateBasicInformation();

        if(!empty($this->errors)){
            $this->logMessage($this->getErrors());
            return false;
        }

        $curl = curl_init();

        $headers = array(
            'Accept: application/xml',
            'Content-Type: application/xml',
            'Api-Version: 2.0',
            'Api-AppId: ' . $this->appId,
            'Api-Username: ' . $this->userName,
            'Api-Password: ' . $this->password,
        );

        $url = $this->getRequestURL();

        $this->logMessage('Sending request to: ' . $url);

        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

        switch ($this->method){
            case 'POST':
                $this->logMessage('Sending POST message');
                curl_setopt($curl, CURLOPT_POST, true);
                curl_setopt($curl, CURLOPT_POSTFIELDS, $this->requestString);
                break;
            case 'PUT':
                $this->logMessage('Sending PUT message');
                curl_setopt($curl, CURLOPT_PUT, true);
                $file_handle = fopen($this->requestString, 'r');
                curl_setopt($curl, CURLOPT_INFILE, $file_handle);
                break;
            case 'DELETE':
                $this->logMessage('Sending DELETE message');
                curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
                break;
        }

        $this->rawResponse = curl_exec($curl);
        $this->logMessage("Raw Response:\n" . $this->rawResponse);

        if (curl_errno($ch)){
            $this->logMessage('CURL:' . curl_errno($ch) . ': ' . curl_error($ch));
            return false;
        }
        else{
            curl_close($ch);
        }
        $this->isSuccess = true;
        return true;
    }

    /**
    *@desc Validates basic credentials
    */
    private function validateBasicInformation(){
        if(empty($this->appId) || empty($this->userName) || empty($this->password)){
            $this->errors[] = 'Account credentials missing';
        }
    }

    /**
    *@desc Validates account ID
    */
    private function validateAccountId(){
        if(empty($this->accountId)){
            $this->errors[] = 'Account ID is missing';
        }
    }

    /**
    *@desc Validates client folder ID
    */
    private function validateClientFolderId(){
        if(empty($this->clientFolderId)){
            $this->errors[] = 'Client Folder ID is missing';
        }
    }

    /**
    *@desc Returns list of accounts
    */
    public function getAccounts(){
        if(empty($this->accounts)){
            $this->targetScript = 'a/';
            $this->postRequest();

            if(!empty($this->rawResponse)){
                $responseXML = simplexml_load_string($this->rawResponse);

                foreach($responseXML->accounts->account as $account){
                    if(!empty($account->accountId)){
                        $temp = array();
                        $temp['account_id'] = (string) $account->accountId;
                        $temp['first_name'] = (string) $account->firstName;
                        $temp['last_name'] = (string) $account->lastName;
                        $this->accounts[] = $temp;
                    }
                }
            }
        }

        return $this->accounts;
    }

    /**
    *@desc Returns list of client folders
    */
    public function getClientFolders(){
        $this->validateAccountId();
        $this->targetScript = 'a/' . $this->accountId . '/c';
        $this->postRequest();

        if(!empty($this->rawResponse)){
            $responseXML = simplexml_load_string($this->rawResponse);

            foreach($responseXML->clientfolders->clientfolder as $folder){
                if(!empty($folder->clientFolderId)){
                    $temp = array();
                    $temp['folder_id'] = (string) $folder->clientFolderId;
                    $temp['name'] = (string) $folder->name;
                    $this->clientFolders[] = $temp;
                }
            }
        }

        return $this->clientFolders;
    }

    /**
    *@desc Returns list of lists
    */
    public function getAllLists(){
        $this->validateAccountId();
        $this->validateClientFolderId();
        $this->targetScript = 'a/' . $this->accountId . '/c/' . $this->clientFolderId . '/lists';
        $this->postRequest();

        if(!empty($this->rawResponse)){
            $responseXML = simplexml_load_string($this->rawResponse);

            foreach($responseXML->lists->list as $list){
                if(!empty($list->listId)){
                    $temp = array();
                    $temp['list_id'] = (string) $list->listId;
                    $temp['name'] = (string) $list->name;
                    $this->lists[] = $temp;
                }
            }
        }

        return $this->lists;
    }

    /**
    *@desc Creates a contact
    */
    public function createContact(){
        $this->validateAccountId();
        $this->validateClientFolderId();

        if(empty($this->email)){
            $this->errors[] = 'Email address in missing';
        }

        $this->targetScript = 'a/' . $this->accountId . '/c/' . $this->clientFolderId . '/contacts/';
        $this->method = 'POST';

        $this->requestString = '<contacts>
                                    <contact>
                                       <email>' . $this->email . '</email>
                                       <firstName>' . $this->convertForXML($this->firstName) . '</firstName>
                                       <lastName>' . $this->convertForXML($this->lastName) . '</lastName>
                                       <street>' . $this->convertForXML($this->address1) . '</street>
                                       <street2>' . $this->convertForXML($this->address2) . '</street2>
                                       <city>' . $this->convertForXML($this->city) . '</city>
                                       <state>' . $this->state . '</state>
                                       <postalCode>' . $this->convertForXML($this->zip) . '</postalCode>
                                       <phone>' . $this->convertForXML($this->phone) . '</phone>
                                       <status>normal</status>
                                    </contact>
                                </contacts>';
        $this->postRequest();

        if(!empty($this->rawResponse)){
            $responseXML = simplexml_load_string($this->rawResponse);

            if(!empty($responseXML->contacts->contact->contactId)){
                $this->contactId = (string) $responseXML->contacts->contact->contactId;
            }
            else{
                $this->errors[] = 'Contact could not be added';
            }
        }
    }

    /**
    *@desc Subscribes a contact to a list
    */
    public function subscribeContactToList(){
        $this->validateAccountId();
        $this->validateClientFolderId();

        if(empty($this->contactId)){
            $this->errors[] = 'Contact ID is missing';
        }
        if(empty($this->listId)){
            $this->errors[] = 'List ID is missing';
        }

        $this->targetScript = 'a/' . $this->accountId . '/c/' . $this->clientFolderId . '/subscriptions/';
        $this->method = 'POST';

        $this->requestString = '<subscriptions>
                                    <subscription>
                                        <contactId>' . $this->contactId . '</contactId>
                                        <listId>' . $this->listId . '</listId>
                                        <status>normal</status>
                                    </subscription>
                                </subscriptions>';

        $this->postRequest();

        if(!empty($this->rawResponse)){
            $responseXML = simplexml_load_string($this->rawResponse);

            if(!empty($responseXML->subscriptions->subscription->subscriptionId)){
                $this->subscriptionId = (string) $responseXML->subscriptions->subscription->subscriptionId;
            }
            else{
                $this->errors[] = 'Contact could not be added';
            }
        }
    }

    /**
    *@desc If request was successful or not
    */
    public function isSuccess(){
        return $this->isSuccess;
    }

    /**
    *@desc Returns errors
    */
    public function getErrors($delimeter = ' '){
        if(!empty($this->errors)){
            return implode($delimeter, $this->errors);
        }

        return '';
    }

    /**
    *@desc For logging debug messages
    *
    * @param string
    */
    private function logMessage($message){
        if($this->debug){
            $fileName = dirname(__FILE__) . '/log/icontact/log_' . date('Y-m-d') . '.php';

            $text = "$message\n\r-----------------------------------------------------------------------------\n\r";

            if(!file_exists($fileName)){
                $text = "<?php die('Access Denied'); ?>\n\n" . $text;
            }

            $f = fopen($fileName, 'ab');
            flock($f, LOCK_EX);
            fwrite($f, $text);
            flock($f, LOCK_UN);
            fclose($f);
        }
    }

    /**
    *@desc For debugging
    */
    private function dumpVar($var){
        echo '<pre>', print_r($var, true), '</pre>';
        exit;
    }

    /**
    *@desc Copy of xml_convert function of CI XML helper
    * Convert Reserved XML characters to Entities
    *
    * @access   public
    * @param    string
    * @return   string
    */
    private function convertForXML($str)
    {
      $temp = '__TEMP_AMPERSANDS__';

      // Replace entities to temporary markers so that
      // ampersands won't get messed up
      $str = preg_replace("/&#(\d+);/", "$temp\\1;", $str);
      $str = preg_replace("/&(\w+);/",  "$temp\\1;", $str);

      $str = str_replace(array("&","<",">","\"", "'", "-"),
                   array("&amp;", "&lt;", "&gt;", "&quot;", "&#39;", "&#45;"),
                   $str);

      // Decode the temp markers back to entities
      $str = preg_replace("/$temp(\d+);/","&#\\1;",$str);
      $str = preg_replace("/$temp(\w+);/","&\\1;", $str);

      return $str;
    }
}

//End of MSHiContact.php file