<?php
class ControllerPaymentOfflineCC extends Controller {

	private $name = '';
	protected $errors = array();

	protected function index() {

		$this->name = basename(__FILE__, '.php');

		$this->data = array_merge($this->data, $this->load->language('payment/' . $this->name));

    	$this->data['button_continue'] = $this->language->get('button_continue');
		$this->data['button_back'] = $this->language->get('button_back');

		// form action processes on this page
    	$this->data['action'] = (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=payment/' . $this->name . '/callback&order_id=' . $this->session->data['order_id']);

		$this->load->model('checkout/order');

		$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);

		$this->data['error'] 			= (isset($this->session->data['error'])) ? $this->session->data['error'] : NULL;
		$this->data['text_creditcard'] 	= $this->language->get('text_creditcard');
		$this->data['text_blank'] 		= $this->language->get('text_blank');
		$this->data['entry_cc_type'] 	= $this->language->get('entry_cc_type');
		$this->data['entry_cc_name'] 	= $this->language->get('entry_cc_name');
		$this->data['entry_cc_number'] 	= $this->language->get('entry_cc_number');
		$this->data['entry_cc_expire'] 	= $this->language->get('entry_cc_expire');
		$this->data['entry_cc_cvv']  	= $this->language->get('entry_cc_cvv');
		$this->data['entry_cc_startdate']= $this->language->get('entry_cc_startdate');
		$this->data['entry_cc_issuenum']= $this->language->get('entry_cc_issuenum');
		$this->data['extra_cc_number'] 	= $this->language->get('extra_cc_number');
		$this->data['extra_cc_expire'] 	= $this->language->get('extra_cc_expire');
		$this->data['extra_cc_cvv']  	= $this->language->get('extra_cc_cvv');
		$this->data['extra_cc_startdate']= $this->language->get('extra_cc_startdate');
		$this->data['extra_cc_issuenum']= $this->language->get('extra_extra_cc_issuenumcc_cvv');

		$this->data['types'] 			= $this->getTypes();

		$this->data['cc_type_val'] 		= (isset($this->session->data['cc_type'])) ? $this->session->data['cc_type'] : NULL;
		$this->data['cc_name_val'] 		= (isset($this->session->data['cc_name'])) ? $this->session->data['cc_name'] : NULL;
		$this->data['cc_number_val'] 	= (isset($this->session->data['cc_number'])) ? $this->session->data['cc_number'] : NULL;
		$this->data['cc_month_val'] 	= (isset($this->session->data['cc_month'])) ? $this->session->data['cc_month'] : NULL;
		$this->data['cc_year_val'] 		= (isset($this->session->data['cc_year'])) ? $this->session->data['cc_year'] : NULL;
		$this->data['cc_cvv_val'] 		= (isset($this->session->data['cc_cvv'])) ? $this->session->data['cc_cvv'] : NULL;
		$this->data['cc_startdate_val'] = (isset($this->session->data['cc_startdate'])) ? $this->session->data['cc_startdate'] : NULL;
        $this->data['cc_issuenum_val'] 	= (isset($this->session->data['cc_issuenum'])) ? $this->session->data['cc_issuenum'] : NULL;

		unset($this->session->data['error']);
		unset($this->session->data['cc_type']);
		unset($this->session->data['cc_name']);
		unset($this->session->data['cc_number']);
		unset($this->session->data['cc_month']);
		unset($this->session->data['cc_year']);
		unset($this->session->data['cc_cvv']);
		unset($this->session->data['cc_startdate']);
		unset($this->session->data['cc_issuenum']);


		if (method_exists($this->document, 'addBreadcrumb')) { //1.4.x
			$this->data['back'] = (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/payment');
		} else {
			$this->data['back'] = (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/checkout');
		}

		$this->id       = 'payment';
		//$this->template = $this->config->get('config_template') . 'payment/' . $this->name . '.tpl';
		if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/payment/' . $this->name . '.tpl')) {
            $this->template = $this->config->get('config_template') . '/template/payment/' . $this->name . '.tpl';
        } else {
            $this->template = 'default/template/payment/' . $this->name . '.tpl';
        }

		$this->render();
	}

	public function confirm() {
		return;
	}

	public function fail($msg) {
		echo '<html><head><script type="text/javascript">';
		echo 'alert("'.$msg.'");';
		echo 'window.location="' . (HTTPS_SERVER  . 'index.php?route=checkout/checkout') . '";';
		echo '</script></head></html>';
	}

	public function callback() {
		$this->name = basename(__FILE__, '.php');
		$order_id = $this->request->get['order_id'];

		$this->load->model('checkout/order');

		$order_info = $this->model_checkout_order->getOrder($order_id);

		if ($order_info) {

			if ($this->request->server['REQUEST_METHOD'] == 'POST') {

	            // Validate Client Form (populated and valid)
	            if (!$this->validateForm()) {
	                if (!empty($this->errors)) {
	                    $this->session->data['error'] = $this->errors[0];
	                }
	                if (method_exists($this->document, 'addBreadcrumb')) { //1.4.x
						$this->redirect((isset($this->session->data['guest'])) ? (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/guest_step_3') : (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/confirm'));
					} else {
						$this->fail($this->session->data['error']);
					}
					return;
	            }

	           $this->data['types'] = $this->getTypes();

	    		$ccType = $this->request->post['cc_type'];
	    		$ccName = $this->request->post['cc_name'];
        		$ccNumber = preg_replace('/[^0-9 -]/', '', $this->request->post['cc_number']); // strip non numerics from the text but leave spaces for the moment.
        		$ccMonth = $this->request->post['cc_month'];
        		$ccYear = $this->request->post['cc_year'];
        		$ccCVV = $this->request->post['cc_cvv'];
        		$ccStartDate = (isset($this->request->post['cc_startdate'])) ? $this->request->post['cc_startdate'] : NULL;
        		$ccIssueNum = (isset($this->request->post['cc_issuenum'])) ? $this->request->post['cc_issuenum'] : NULL;

        		foreach ($this->data['types'] as $type) {
        			if ($type['code'] == $ccType) {
        				$ccTypeText = $type['text'];
        				$this->session->data['cc_type'] = $type['text'];
					}
				}

        		if ($this->config->get($this->name . '_mode') == 1) {
	    			$mail = new Mail();
					$mail->protocol = $this->config->get('config_mail_protocol');
					$mail->parameter = $this->config->get('config_mail_parameter');
					$mail->hostname = $this->config->get('config_smtp_host');
					$mail->username = $this->config->get('config_smtp_username');
					$mail->password = $this->config->get('config_smtp_password');
					$mail->port = $this->config->get('config_smtp_port');
					$mail->timeout = $this->config->get('config_smtp_timeout');
					$mail->setTo($this->config->get('config_email'));
					$mail->setFrom($this->config->get('config_email'));
	    			$mail->setSender((($this->config->get('config_name')) ? $this->config->get('config_name') : $this->config->get('config_store')));
	    			$mail->setSubject(sprintf($this->language->get('email_subject'), $order_id));
	    			$mail->setText(sprintf($this->language->get('email_message'), $order_id, $ccTypeText, $ccName, $ccNumber, $ccMonth .'/'. $ccYear, $ccCVV, $ccStartDate, $ccIssueNum));
					$mail->addAttachment(DIR_IMAGE . $this->config->get('config_logo'));
					$mail->send();
				}

				// Now we strip away spaces and dashes from ccnumber
				$ccNumber = preg_replace('/[ -]/', '', $ccNumber);

	            // Have to first confirm with the store status. this sends out an email
	            $this->model_checkout_order->confirm($order_id, $this->config->get($this->name . '_order_status_id'));



	            switch($this->config->get($this->name . '_mode')) {
					case 0:
					case 1:
						// Encrypt Card number and update DB Order with CC Data
						if ($this->config->get($this->name . '_encryption') != '') {
							$this->load->library('encryption');
							$encryption = new Encryption($this->config->get($this->name . '_encryption'));
							$ccNumber = $encryption->encrypt($ccNumber);
						}
						$this->db->query("INSERT `" . DB_PREFIX . "offline_cc_data` SET order_id = '" . (int)$order_id . "', cc_type = '" . $this->db->escape($ccTypeText) . "', cc_name = '" . $this->db->escape($ccName) . "', cc_number = '" . $this->db->escape($ccNumber) . "', cc_exp = '" . (int)$ccMonth . "/" . (int)$ccYear . "', cc_cvv = '" . (int)$ccCVV . "'");
						break;

					case 2:
						$ccNumberA = 'xxxx' . substr($ccNumber, 4, 8) . 'xxxx';
						$ccNumberB = substr($ccNumber, 0, 4) . 'xxxxxxxx' . substr($ccNumber, 12, strlen($ccNumber));

						if ($this->config->get($this->name . '_encryption') != '') {
							$this->load->library('encryption');
							$encryption = new Encryption($this->config->get($this->name . '_encryption'));
							$ccNumberA = $encryption->encrypt($ccNumberA);
						}
						$this->db->query("INSERT `" . DB_PREFIX . "offline_cc_data` SET order_id = '" . (int)$order_id . "', cc_type = '" . $this->db->escape($ccTypeText) . "', cc_name = '" . $this->db->escape($ccName) . "', cc_number = '" . $this->db->escape($ccNumberA) . "', cc_exp = '" . (int)$ccMonth . "/" . (int)$ccYear . "', cc_cvv = ''");
						$mail = new Mail();
						$mail->protocol = $this->config->get('config_mail_protocol');
						$mail->parameter = $this->config->get('config_mail_parameter');
						$mail->hostname = $this->config->get('config_smtp_host');
						$mail->username = $this->config->get('config_smtp_username');
						$mail->password = $this->config->get('config_smtp_password');
						$mail->port = $this->config->get('config_smtp_port');
						$mail->timeout = $this->config->get('config_smtp_timeout');
						$mail->setTo($this->config->get('config_email'));
						$mail->setFrom($this->config->get('config_email'));
	    				$mail->setSender((($this->config->get('config_name')) ? $this->config->get('config_name') : $this->config->get('config_store')));
	    				$mail->setSubject(sprintf($this->language->get('email_subject'), $order_id));
	    				$mail->setText(sprintf($this->language->get('email_message_pci'), $order_id, $ccTypeText, $ccNumberB, $ccMonth .'/'. $ccYear, $ccCVV, $ccStartDate, $ccIssueNum));
	    				$mail->send();
						break;
				}

				// Added fields for Maestro/Solo cards
				if ($ccType == 'solo' || $ccType == $this->name . 'maestro') {
					$this->db->query("UPDATE `" . DB_PREFIX . "offline_cc_data` SET cc_startdate = '" . $this->db->escape($ccStartDate) . "', cc_IssueNum = '" . $this->db->escape($ccIssueNum) . "' where order_id = '" . (int)$order_id . "'");
				}

				// Now update with the correct payment custom status. this does not send an email
				//$this->model_checkout_order->update($order_id, $this->config->get('config_order_status_id'),'',FALSE);

	            unset($this->session->data['error']);
	            unset($this->session->data['cc_type']);
	            unset($this->session->data['cc_name']);
				unset($this->session->data['cc_number']);
				unset($this->session->data['cc_month']);
				unset($this->session->data['cc_year']);
				unset($this->session->data['cc_cvv']);
				unset($this->session->data['cc_startdate']);
				unset($this->session->data['cc_issuenum']);

	            $this->redirect((((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/success'));

	        }
	        // Form wasn't POST, hack attempt? Fail.
	        if (method_exists($this->document, 'addBreadcrumb')) { //1.4.x
				$this->redirect((isset($this->session->data['guest'])) ? (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/guest_step_3') : (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/confirm'));
			} else {
				$this->fail($this->session->data['error']);
			}
		}
		// No order found. Fail.
		if (method_exists($this->document, 'addBreadcrumb')) { //1.4.x
			$this->redirect((isset($this->session->data['guest'])) ? (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/guest_step_3') : (((HTTPS_SERVER) ? HTTPS_SERVER : HTTP_SERVER) . 'index.php?route=checkout/confirm'));
		} else {
			$this->fail($this->session->data['error']);
		}
	}


	// Pre-Validates user input from the form before attempting to send to CC Processor.
    private function validateForm() {
		$this->name = basename(__FILE__, '.php');
        $this->load->language('payment/' . $this->name);

        // Save the fields to the session for repopulation
        $this->session->data['cc_type'] = $this->request->post['cc_type'];
        $this->session->data['cc_name'] = $this->request->post['cc_name'];
        $this->session->data['cc_number'] = $this->request->post['cc_number'];
        $this->session->data['cc_month'] = $this->request->post['cc_month'];
        $this->session->data['cc_year'] = $this->request->post['cc_year'];
        $this->session->data['cc_cvv'] = $this->request->post['cc_cvv'];
        $this->session->data['cc_startdate'] = (isset($this->request->post['cc_startdate'])) ? $this->request->post['cc_startdate'] : NULL;
        $this->session->data['cc_issuenum'] = (isset($this->request->post['cc_issuenum'])) ? $this->request->post['cc_issuenum'] : NULL;

        $this->errors = array();
        $ccType = $this->request->post['cc_type'];
        $ccNumber = preg_replace('/[^0-9 -]/', '', $this->request->post['cc_number']); // strip non numerics from the text but leave spaces.
        $ccMonth = $this->request->post['cc_month'];
        $ccYear = $this->request->post['cc_year'];
        $ccCVV = $this->request->post['cc_cvv'];

        if (strlen($this->request->post['cc_name']) == 0) {
         	$this->errors[] = $this->language->get('error_cc_name_missing');
        }

        if (strlen($ccNumber) == 0) {
            $this->errors[] = $this->language->get('error_cc_number_missing');
        } elseif (strlen($ccNumber) <> strlen($this->request->post['cc_number'])) {
            $this->errors[] = $this->language->get('error_cc_number_not_numeric');
        }

        if (strlen($ccMonth) == 0) {
            $this->errors[] = $this->language->get('error_cc_month_missing');
        }

        if (strlen($ccYear) == 0) {
            $this->errors[] = $this->language->get('error_cc_year_missing');
        }

        if (strlen($ccCVV) == 0) {
            $this->errors[] = $this->language->get('error_cc_cvv_missing');
        }

        //  No point to continue validating if we already have an error.
        if (count($this->errors) > 0) {
            return false;
        }

        //  now we remove spaces & dashes from the credit card number so that we can test it as a number.
        $ccNumber = preg_replace('/[ -]/', '', $ccNumber);

        //  and remove all non numerics from the following and validate them.
        $ccMonth = preg_replace('/[^0-9]/', '', $ccMonth);
        $ccYear = preg_replace('/[^0-9]/', '', $ccYear);

        if (strlen($ccMonth) <> strlen($this->request->post['cc_month'])) {
            $this->errors[] = $this->language->get('error_cc_month_not_numeric');
        }
        if (strlen($ccYear) <> strlen($this->request->post['cc_year'])) {
            $this->errors[] = $this->language->get('error_cc_year_not_numeric');
        }

        //  No point to continue validating if we already have an error.
        if (count($this->errors) > 0) {
            return false;
        }

        //  Valid credit card number ?
        $cardNumber = strrev($ccNumber);
        $numSum = 0;
        for($i = 0; $i < strlen($cardNumber); $i++) {
            $currentNum = substr($cardNumber, $i, 1);

            // Double every second digit
            if ($i % 2 == 1) {
                $currentNum *= 2;
            }

            // Add digits of 2-digit numbers together
            if ($currentNum > 9) {
                $firstNum = $currentNum % 10;
                $secondNum = ($currentNum - $firstNum) / 10;
                $currentNum = $firstNum + $secondNum;
            }
            $numSum += $currentNum;
        }
        if ($numSum % 10 != 0) {
            $this->errors[] = $this->language->get('error_cc_number_invalid');
            return false;
        }

        //  Valid number(s) for card type?
        switch ($ccType) {
            case $this->name . '_t_mastercard':
                if (!(preg_match("/^5[1-5][0-9]{14}$/", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type');
                if (!(preg_match("/^[0-9][0-9][0-9]$/", $ccCVV)))
                    $this->errors[] = $this->language->get('error_three_cvv');
                break;
            case $this->name . '_t_visa':
                if (!(preg_match("/^4[0-9]{12}([0-9]{3})?$/", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type');
                if (!(preg_match("/^[0-9][0-9][0-9]$/", $ccCVV)))
                    $this->errors[] = $this->language->get('error_three_cvv');
                break;
             case $this->name . '_t_amex':
                if (!(preg_match("/^3[47][0-9]{13}$/", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type');
                if (!(preg_match("/^[0-9][0-9][0-9][0-9]$/", $ccCVV)))
                    $this->errors[] = $this->language->get('error_four_cvv');
                break;
             case $this->name . '_t_disc':
                if (!(preg_match("/^6011[0-9]{12}$/", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type');
                if (!(preg_match("/^[0-9][0-9][0-9]$/", $ccCVV)))
                    $this->errors[] = $this->language->get('error_three_cvv');
                break;
             case $this->name . '_t_diner':
                if (!(preg_match("/^3(0[0-5]|[68][0-9])[0-9]{11}$/", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type');
                if (!(preg_match("/^[0-9][0-9][0-9]$/", $ccCVV)))
                    $this->errors[] = $this->language->get('error_three_cvv');
                break;
             case $this->name . '_t_jcb':
                if (!(preg_match("^/3(0[0-5]|[68][0-9])[0-9]{11}$/", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type');
                if (!(preg_match("/^[0-9][0-9][0-9]$/", $ccCVV)))
                    $this->errors[] = $this->language->get('error_three_cvv');
                break;
             case $this->name . '_t_maestro' || $this->name . '_t_solo':
                //if (!(preg("/(^(5[0678])\d{11,18}$)|(^(6[^05])\d{11,18}$)|(^(601)[^1]\d{9,16}$)|(^(6011)\d{9,11}$)|(^(6011)\d{13,16}$)|(^(65)\d{11,13}$)|(^(65)\d{15,18}$)|(^(49030)[2-9](\d{10}$|\d{12,13}$))|(^(49033)[5-9](\d{10}$|\d{12,13}$))|(^(49110)[1-2](\d{10}$|\d{12,13}$))|(^(49117)[4-9](\d{10}$|\d{12,13}$))|(^(49118)[0-2](\d{10}$|\d{12,13}$))|(^(4936)(\d{12}$|\d{14,15}$))/", $ccNumber))) {
                //    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type');
				//}
                //if (!(preg("/^[0-9][0-9][0-9]$/", $ccCVV)))
                //    $this->errors[] = $this->language->get('error_three_cvv');
                break;
             default:
                // got to do something here but it is an error by the implementer.
                $this->errors[] = "unsupported credit card type = " . $ccType;
        }

        // Month must be in the range 1 to 12
        $ccMonth = (int)$ccMonth;
        if ($ccMonth < 1 || $ccMonth > 12) {
            $this->errors[] = $this->language->get('error_cc_month_invalid_range');
        }

        // Year cannot be more than 10 years into the future
        $ccYear = (int)$ccYear;
        $currentYear = (int)date('y');
        if ($ccYear  > $currentYear + 10) {
            $this->errors[] = $this->language->get('error_cc_year_invalid_range');
        }

        // Cannot expire within the next 3 days because the payment is processed on weekdays and it could be friday night
        $margin = 3;
        // $margin days before the 1st day of the month after ValidTo date on card
        $ccExpiresLimit = mktime(0,0,0, $ccMonth + 1,  1 - $margin, $ccYear);
        $today = mktime(0,0,0);
        if ($today >= mktime(0,0,0, $ccMonth + 1,  1, $ccYear)) {
            $this->errors[] = $this->language->get('error_cc_expired');
        } else if ($today >= $ccExpiresLimit) {
            $this->errors[] = $this->language->get('error_cc_expires_too_soon');
        }

        return (count($this->errors) == 0);
    }

    function getTypes(){
    	$this->name = basename(__FILE__, '.php');

	    $types[] = array(
			'code'	=> 'visa',
			'text' 		=> $this->language->get('text_visa')
		);

		$types[] = array(
			'code'	=> 'mastercard',
			'text' 		=> $this->language->get('text_mastercard')
		);

		$types[] = array(
			'code'	=> 'amex',
			'text' 		=> $this->language->get('text_amex')
		);

		$types[] = array(
			'code'	=> 'disc',
			'text' 		=> $this->language->get('text_disc')
		);

		$types[] = array(
			'code'	=> 'diner',
			'text' 		=> $this->language->get('text_diner')
		);

		$types[] = array(
			'code'	=> 'jcb',
			'text' 		=> $this->language->get('text_jcb')
		);

		$types[] = array(
			'code'	=> 'solo',
			'text' 		=> $this->language->get('text_solo')
		);

		$types[] = array(
			'code'	=> 'maestro',
			'text' 		=> $this->language->get('text_maestro')
		);

		// Get list of allowed services
		$allowed_types = $this->db->query("select `value` from " . DB_PREFIX . "setting where `group` = '" . $this->name . "' AND `key` = '" . $this->name . "_types'");

		$allowTypes = explode(',', $allowed_types->row['value']);

		$allowed = array();

		foreach ($types as $type) {
			if (in_array($type['code'], $allowTypes)) {
	        	$allowed[] = $type;
			}
		}

		return $allowed;
	}
}
?>