<?php
define('PLEXUM_LOG_FILE_PATH', dirname(__FILE__) . '/log/plexum/');

/**
 * @filename        Plexum.php
 * @description     This class is for sending notification of sales to a Plexum X6 site
 * @version         1.0
 * @package
 * @author          Mohammad Sajjad Hossain - info@sajjadhossain.com
 *
 * @link            http://sajjadhossain.com
 * @created on      February 25, 2011
 * @Dependencies
 * @license
 ***/
class Plexum
{
    private $siteUrl;

    private $requestVariables = array(
                                    'type' => 'cart',           //Indicate to record sales transaction.
                                    'return_api' => 'yes',      //To indicate if the sales information is passed silently (e.g. using PHP, Perl), if no value is provided, it will default to "no".
                                    'return_location' => '',    //If "return_api" value is empty or set to no, you can provide url where to redirect customer after sales is recorded.
                                    'return_img' => 'no'        //Indicate to return an image if the sales information is being passed through image tag
                                );

    private $error;

    private $transactionType = 'cart';

    private $items = array();

    private $success = false;

    private $trackingId;

    private $isDuplicate = false;

    private $isAuthenticationFailed = false;

    private $debug = false;

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

    /**
    *@desc URL to which the notification will be posted.
    * @param string $url
    */
    public function setSiteUrl($url)
    {
        $this->siteUrl = $url;
    }

    /**
    *@desc UserId of the user that referred the sale.
    * @param string $id
    */
    public function setUserId($id)
    {
        $this->requestVariables['return_userid'] = $id;
    }

    /**
    *@desc Indicate to not credit the user that referred the sale but pass the sale to the user upline sponsor, if no value is provided, it will default to "no". Possible values: yes/no.
    * @param string $pass
    */
    public function setPass($pass)
    {
        $this->requestVariables['return_pass'] = strtolower($pass) == 'yes' ?  'yes' : 'no';
    }

    /**
    *@desc Sales order number, supplied by your shopping cart software.
    * @param string $id
    */
    public function setOrderId($id)
    {
        $this->requestVariables['return_orderid'] = $id;
    }

    /**
    *@desc Total amount of the sale, which commission calculation will be based on, if commission-able amount is not supplied in return_commissionable variable.
    * @param float $amount
    */
    public function setAmount($amount)
    {
        $this->requestVariables['return_amt'] = $amount;
    }

    /**
    *@desc Total amount to based commission calculation on, if an amount is supplied (e.g. 20.00).
    * @param float $amount
    */
    public function setCommissionableAmount($amount)
    {
        $this->requestVariables['return_commissionable'] = $amount;
    }

    /**
    *@desc To automatically approved orders despite the financial & Plan manager preferences. Possible values: yes/no.
    * @param string $approve
    */
    public function setAutomaticOrderApprove($approve)
    {
        $this->requestVariables['return_approved'] = strtolower($approve) == 'yes' ? 'yes' : 'no';
    }

    /**
    *@desc Customer name supplied from the shopping cart.
    * @param string $name
    */
    public function setCustomerName($name)
    {
        $this->requestVariables['return_custname'] = $name;
    }

    /**
    *@desc Name to use in identifying the sales (e.g. Xyz Store).
    * @param string $name
    */
    public function setSourceName($name)
    {
        $this->requestVariables['return_source'] = $name;
    }

    /**
    *@desc List of item purchased (e.g. Quantity, Price Each, Item Name|2,29.00, Mouse Pad).
    * @param string $itemName
    * @param int $quantity
    * @param float $price
    */
    public function setItem($itemName, $quantity, $price)
    {
        $this->items[] = array( 'name'      => $itemName,
                                'quantity'  => $quantity,
                                'price'     => $price);
    }

    private function setItemsForPost()
    {
        if(!empty($this->items))
        {
            $temp = '';

            foreach($this->items as $item)
            {
                $temp[] = $item['quantity'] . ',' . $item['price'] . ',' . $item['name'];
            }

            $this->requestVariables['return_item_info'] = implode('|', $temp);
        }
    }

    /**
    *@desc To indicate if the sales is a recurring transaction, if no value is provided, it will default to "no". Possible values: yes/no.
    * @param string $value
    */
    public function setIsRecurring($value)
    {
        $this->requestVariables['return_recurring'] = strtolower($value) == 'yes' ? 'yes' : 'no';
    }

    /**
    *@desc Secret code to verify the transaction is coming from the actual site, this code is what is set on Financial & Plan Manager Preferences.
    * @param string $code
    */
    public function setSecretCode($code)
    {
        $this->requestVariables['return_st'] = $code;
    }

    public function enableDebugging()
    {
        $this->debug = true;
    }

    /**
    *@desc Defines whether the notification was successfully processed or not
    * @return boolean
    */
    public function isSuccess()
    {
        return $this->success;
    }

    /**
    *@desc Returns the error message
    * @return string
    */
    public function getError()
    {
        return $this->error;
    }

    public function validateInfo()
    {
        if(empty($this->requestVariables['return_userid']))
        {
            $this->error = 'User ID is missing';
            return false;
        }

        if(empty($this->requestVariables['return_orderid']))
        {
            $this->error = 'Order ID is missing';
            return false;
        }

        if(empty($this->requestVariables['return_amt']))
        {
            $this->error = 'Amount is missing';
            return false;
        }

        return true;
    }

    public function notify()
    {
        if(empty($this->siteUrl))
        {
            $this->logMessage('Site URL is missing.');
            $this->error = 'Site URL has not been set';
            return;
        }

        if(!$this->validateInfo())
        {
            $this->logMessage($this->error);
            return;
        }

        $this->setItemsForPost();

        $this->logMessage('Preparing request...');

        $nameValuePairs = array();

        foreach($this->requestVariables as $key => $value)
        {
            if($value)
            {
                $nameValuePairs[] = $key .'=' . urlencode($value);
            }
        }

        $requestString = implode('&', $nameValuePairs);

        $this->logMessage($requestString);

        $this->logMessage('Initializing cURL...');

        $ch = curl_init();

        $this->logMessage('Sending Request to : ' . $this->siteUrl);
        curl_setopt($ch, CURLOPT_URL, $this->siteUrl);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $requestString);
        curl_setopt($ch,CURLOPT_USERAGENT, 'MSH Plexum Class');
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_VERBOSE, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

        $this->logMessage('Getting response...');
        $response = trim(curl_exec($ch));

        $this->logMessage(urldecode($response));

        if (curl_errno($ch))
        {
            $this->error = 'cURL Error # ' . curl_errno($ch) . ' : ' . curl_error($ch);

            $this->logMessage($error);
        }
        else
        {
            curl_close($ch);
        }

        if (strstr($response, 'ok'))
        {
            list ($status, $trackingId) = explode(',', $result);
            $this->success = true;
            $this->trackingId = $trackingId;
        }
        else if ($response == 'duplicate_order')
        {
            $this->error = 'Duplicate order and order is not recorded on Plexum';
        }
        else if ($response == 'authentication_filed')
        {
            $this->error = 'Secret code or domain do not match settings on Plexum security setup and order is not recorded on Plexum.';
        }
        else
        {
            $this->error = 'An error occured';
        }

        $this->logMessage('Done...');
    }

    private function logMessage($message)
    {
        if($this->debug)
        {
            $fileName = PLEXUM_LOG_FILE_PATH . 'log_' . date('Y-m-d') . '.php';

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

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

            $this->debugText .= $text;

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

//End of file Plexum.php