<?php
/**
 * BoxBilling
 *
 * LICENSE
 *
 * This source file is subject to the license that is bundled
 * with this package in the file LICENSE.txt
 * It is also available through the world-wide-web at this URL:
 * http://www.boxbilling.com/LICENSE.txt
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@boxbilling.com so we can send you a copy immediately.
 *
 * @copyright Copyright (c) 2010-2012 BoxBilling (http://www.boxbilling.com)
 * @license   http://www.boxbilling.com/LICENSE.txt
 * @version   $Id$
 */
class Payment_Adapter_TwoCheckout extends Payment_AdapterAbstract
{
    public function init()
    {
        if(!$this->getParam('vendor_nr')) {
            throw new Payment_Exception('Payment gateway "2Checkout" is not configured properly. Please update configuration parameter "Vendor account number" at "Configuration -> Payments".');
        }

        if(!$this->getParam('secret')) {
            throw new Payment_Exception('Payment gateway "2Checkout" is not configured properly. Please update configuration parameter "Secret word" at "Configuration -> Payments".');
        }
    }
    
    public static function getConfig()
    {
        return array(
            'supports_one_time_payments'   =>  true,
            'supports_subscriptions'     =>  true,
            'description'     =>  'Allows to start accepting payments by 2Checkout. You must enable INS notifications by logging on to your 2checkout account and navigating to <i>Notifications -> Settings</i> section. Set <i>\'Global URL\'</i> to BoxBilling Callback URL and click on <i>\'Enable All Notifications\'</i> and "Save settings".',
            'form'  => array(
                'vendor_nr' => array('text', array(
                            'label' => '2CO Account #', 
                            'description' => '2Checkout account number is number with which you login to 2CO account',
                    ),
                 ),
                'secret' => array('password', array(
                            'label' => 'Secret word', 
                            'description' => 'To set up the secret word please log in to your 2CO account, click on the “Account” tab, then click on “Site Management” subcategory. On the “Site Management” page you will enter the Secret Word in the field provided under Direct Return. After you have entered your Secret Word click the blue “Save Changes” button at the bottom of the page.',
                    ),
                 ),
                'single_page' => array('radio', array(
                            'multiOptions' => array('1'=>'Single page', '0'=>'Multi-page'),
                            'label' => 'Checkout page type',
                    ),
                 ),
            ),
        );
    }
    
    /**
     * Return payment gateway type
     * @return string
     */
    public function getType()
    {
        return Payment_AdapterAbstract::TYPE_FORM;
    }

    /**
     * Return payment gateway type
     * @return string
     */
    public function getServiceUrl()
    {
        if((bool)$this->getParam('single_page') === false) {
            return 'https://www.2checkout.com/checkout/purchase';
        }
		return 'https://www.2checkout.com/checkout/spurchase';
    }

    public function getInvoiceId($data)
    {
        $id = parent::getInvoiceId($data);
        if(!is_null($id)) {
            return $id;
        }
        
        return isset($data['post']['merchant_order_id']) ? (int)$data['post']['merchant_order_id'] : NULL;
    }

    /**
     * Return form params
     * @see http://www.2checkout.com/community/blog/category/knowledge-base/tech-support/3rd-party-carts/parameter-sets
     * @param Payment_Invoice $invoice
     */
    public function singlePayment(Payment_Invoice $invoice)
    {
        $b = $invoice->getBuyer();
        
        $data = array();
        $data['sid']                = $this->getParam('vendor_nr');
        $data['mode']               = '2CO';
        foreach($invoice->getItems() as $i=>$item) {
            $data['li_'.$i.'_type']         = 'product';
            $data['li_'.$i.'_name']         = $item->getTitle();
            $data['li_'.$i.'_product_id']   = $item->getId();
            $data['li_'.$i.'_price']        = $item->getTotalWithTax();
            $data['li_'.$i.'_quantity']     = 1;
        }
        $data['card_holder_name']   = $b->getFirstName().' '.$b->getLastName();
        $data['phone']              = $b->getPhoneCountryCode().$b->getPhone();
        $data['email']              = $b->getEmail();
        $data['street_address']     = $b->getAddress();
        $data['city']               = $b->getCity();
        $data['state']              = $b->getState();
        $data['zip']                = $b->getZip();
        $data['country']            = $b->getCountry();
       
        $data['merchant_order_id']  = $invoice->getId();
        
        $data['return_url']         = $this->getParam('return_url');
        $data['x_receipt_link_url'] = $this->getParam('notify_url');
        $data['fixed'] = 'Y';
        $data['skip_landing']       = 1;
        
        if($this->testMode) {
            $data['demo'] = 'Y';
        }
        
        return $data;
    }

    /**
     * Perform recurent payment
     * @param Payment_Invoice $invoice
     * @see http://www.2checkout.com/blog/knowledge-base/merchants/tech-support/3rd-party-carts/parameter-sets/pass-through-product-parameter-set/
     */
    public function recurrentPayment(Payment_Invoice $invoice)
    {
    	$subs = $invoice->getSubscription();
    	$buyer = $invoice->getBuyer();
        
        $data = array();
        $data['sid']				=	$this->getParam('vendor_nr');
        $data['mode']				=	'2CO';

        switch ($subs->getUnit()) {
            case 'W':
                $unit = 'Week';
                break;
            
            case 'Y':
                $unit = 'Year';
                break;

            case 'M':
            default:
                $unit = 'Month';
                break;
        }
        
        foreach($invoice->getItems() as $i => $item) {
        	$data['li_' . $i . '_type']			= 'product';
        	$data['li_' . $i . '_name'] 		= $item->getTitle();
        	$data['li_' . $i . '_quantity']		= 1;
        	$data['li_' . $i . '_tangible']		= 'N';
        	$data['li_' . $i . '_description']	= $item->getDescription();
        	$data['li_' . $i . '_recurrence']	= $subs->getCycle() . ' ' . $unit;
            $data['li_' . $i . '_price']		= $item->getTotalWithTax();
        }

        $data['merchant_order_id']  = $invoice->getId();

        $data['fixed']              = 'Y';
        $data['skip_landing']       = 1;
        $data['id_type']            = 1;

        $data['return_url']         = $this->getParam('return_url');
        $data['x_receipt_link_url'] = $this->getParam('notify_url');

        $data['card_holder_name']   = $buyer->getFirstName(). ' '.$buyer->getLastName();
        $data['phone']              = $buyer->getPhoneCountryCode().$buyer->getPhone();
        $data['email']              = $buyer->getEmail();
        $data['street_address']     = $buyer->getAddress();
        $data['city']         		= $buyer->getCity();
        $data['state']        		= $buyer->getState();
        $data['zip']          		= $buyer->getZip();
        $data['country']      		= $buyer->getCountry();
        $data['subscription']		= 1;

    	if($this->testMode) {
            $data['demo'] = 'Y';
        }

        return $data;
    }

    /**
     * Handle IPN and return response object
     * @todo
     * @return Payment_Transaction
     */
    public function getTransaction($data, Payment_Invoice $invoice)
    {
        $ipn = $data['post'];
        
        $tx = new Payment_Transaction();
        $tx->setId($ipn['key']);
        $tx->setAmount($ipn['total']);
        $tx->setCurrency($invoice->getCurrency());
        
        if($ipn['credit_card_processed'] == 'Y') {
            $tx->setType(Payment_Transaction::TXTYPE_PAYMENT);
            $tx->setStatus(Payment_Transaction::STATUS_COMPLETE);
        }
        
        if (isset($ipn['subscription']) && $ipn['subscription'] == 1) {
            $tx->setSubscriptionId($ipn["order_number"]);
        	$tx->setType(Payment_Transaction::TXTYPE_SUBSCR_CREATE);
            $tx->setStatus(Payment_Transaction::STATUS_COMPLETE);
        }

        return $tx;
    }

    /**
     * Check if Ipn is valid
     * @see https://www.2checkout.com/static/va/documentation/INS/INS_User_Guide_04_08_2009.pdf
     */
    public function isIpnValid($data, Payment_Invoice $invoice)
    {
        $ipn = $data['post'];

        $secret         = $this->getParam('secret');
        $vendorNumber   = $this->getParam('vendor_nr');
        $orderNumber    = $ipn["order_number"];
        $orderTotal     = $ipn["total"];

        // If demo mode, the order number must be forced to 1
        if($ipn['demo'] == 'Y') {
            $orderNumber = "1";
        }
        
        // Calculate md5 hash as 2co formula: md5(secret_word + vendor_number + order_number + total)
        $key = strtoupper(md5($secret . $vendorNumber . $orderNumber . $orderTotal));
        error_log(sprintf('Returned MD5 Hash %s should be %s', $ipn['key'], $key));
        return ($ipn["key"] == $key);
    }
}