<?php
/**
 * Installment Plan Info Module
 * 
 * @author  Kyo (AKA Yasuhiro Sota)
 * @version 1.1.3
 * @license Commercial License
 * @package catalog
 * @subpackage  catalog.controller.module
 */
if (!defined('IS_MIJOSHOP')) {
  define('IS_MIJOSHOP', defined('_JEXEC'));
}

if (IS_MIJOSHOP) {
  // No Permission
  defined('_JEXEC') or die('Restricted access');
}

require_once DIR_SYSTEM . 'library/installment_plan_info/matheval.class.php';
require_once DIR_SYSTEM . 'library/installment_plan_info/installment_plan_info.php';
      
class ControllerModuleInstallmentPlanInfo extends Controller {

/**
 * Debug mode
 *
 * @var boolean
 */  
  private $debug = false;

/**
 * Name of module key
 *
 * @var string
 */  
  protected $module_key = null;

/**
 * Base directory and path to image directory.
 *
 * @var string
 */  
  private $image_base_path = null;
  
/**
 * Constructor.
 *
 * @param object $registry
 * @return void
 */
	public function __construct($registry) {
    parent::__construct($registry);
    
    $this->module_key = InstallmentPlanInfo::$module_key;
    
    $this->image_base_path = InstallmentPlanInfo::getImageBasePath();
	}
  
/**
 * index method
 *
 * @param array $setting
 * @return void
 */
	protected function index($setting) {

    if ($setting) {
      $this->_index($setting);
      
    } else {
      
      $this->load->model('design/layout');
      $this->load->model('catalog/category');
      $this->load->model('catalog/product');
      $this->load->model('catalog/information');

      if (isset($this->request->get['route'])) {
        $route = (string)$this->request->get['route'];
      } else {
        $route = 'common/home';
      }

      $layout_id = 0;

      if ($route == 'product/category' && isset($this->request->get['path'])) {
        $path = explode('_', (string)$this->request->get['path']);

        $layout_id = $this->model_catalog_category->getCategoryLayoutId(end($path));			
      }

      if ($route == 'product/product' && isset($this->request->get['product_id'])) {
        $layout_id = $this->model_catalog_product->getProductLayoutId($this->request->get['product_id']);
      }

      if ($route == 'information/information' && isset($this->request->get['information_id'])) {
        $layout_id = $this->model_catalog_information->getInformationLayoutId($this->request->get['information_id']);
      }

      if (!$layout_id) {
        $layout_id = $this->model_design_layout->getLayout($route);
      }

      if (!$layout_id) {
        $layout_id = $this->config->get('config_layout_id');
      }

      $module_data = array();

      $this->load->model('setting/extension');

      $extensions = $this->model_setting_extension->getExtensions('module');		

      foreach ($extensions as $extension) {
        $modules = $this->config->get($extension['code'] . '_module');

        if ($modules) {
          foreach ($modules as $module) {
           
            if (isset($layout_id) && is_array($layout_id)) {
              foreach ($layout_id as $element) {
                if ($module['layout_id'] == $element['layout_id'] && $module['position'] == 'installment_plan_info' && $module['status']) {
                  $module_data[] = array(
                    'code'       => $extension['code'],
                    'setting'    => $module,
                    'sort_order' => $module['sort_order']
                  );
                }
              }
            } else {
              if ($module['layout_id'] == $layout_id && $module['position'] == 'installment_plan_info' && $module['status']) {
                $module_data[] = array(
                  'code'       => $extension['code'],
                  'setting'    => $module,
                  'sort_order' => $module['sort_order']
                );				
              }
            }
          }
        }
      }

      $sort_order = array(); 

      foreach ($module_data as $key => $value) {
        $sort_order[$key] = $value['sort_order'];
      }

      array_multisort($sort_order, SORT_ASC, $module_data);

      $modules = array();

      foreach ($module_data as $module) {      
        $module = $this->getChild('module/' . $module['code'] . '/_index', $module['setting']);

        if ($module) {
          $modules[] = $module;
        }
      }

      foreach ($modules as $module) { 
        $this->output .= $module;
      }
      
    }

	}

/**
 * _index method
 *
 * @param array $setting
 * @return void
 */
  protected function _index($setting) {
    
    static $module = 0;
    
    if ($this->debug === true) {
      echo '<pre class="installment-plan-info-debug">Installment Plan Info Module is currently running in debug mode.</pre>';
    }

    if (!$setting['content_id']) {
      return false;
    }

    // Get product data.
    if (isset($this->request->get['product_id'])) {
      $product_id = (int)$this->request->get['product_id'];
    } else {
      $product_id = 0;
    }

    if ($product_id <= 0) {
      return false;
    }
    
    // Get the settings
    $content = $this->config->get($this->module_key . '_' . $setting['content_id']);

    // Stores
    $stores = array();

    if (isset($content['stores'])) {
      $stores = (array)$content['stores'];
    }

    if (!$stores || !in_array($this->config->get('config_store_id'), $stores)) {
      return false;
    }

    // Access levels
    $customer_group_display = array();

    if (isset($content['access_levels'])) {
      $customer_group_display = (array)$content['access_levels'];
    }    

    if (!$this->customer->isLogged() && !in_array(0, $customer_group_display)) {
      return false;
    }

    if ($this->customer->isLogged()) {

      $this->load->model('account/customer_group');

      $customer_group_info = $this->model_account_customer_group->getCustomerGroup($this->customer->getCustomerGroupId());

      if (!in_array($customer_group_info['customer_group_id'], $customer_group_display)) {
        return false;
      }
    }

    // Stylesheet
    if ($content['use_default_stylesheet']) {
      if (file_exists('catalog/view/theme/' . $this->config->get('config_template') . '/stylesheet/installment_plan_info.css')) {
        $this->document->addStyle('catalog/view/theme/' . $this->config->get('config_template') . '/stylesheet/installment_plan_info.css');
      } else {
        $this->document->addStyle('catalog/view/theme/default/stylesheet/installment_plan_info.css');
      }
    }

    if ($content['stylesheet']) {
      $stylesheet_paths = explode("\r\n", (string) $content['stylesheet']);

      foreach ($stylesheet_paths as $css_file_path) {
        if (trim($css_file_path)) {
          if (file_exists('catalog/view/theme/' . $this->config->get('config_template') . '/stylesheet/' . $css_file_path)) {
            $this->document->addStyle('catalog/view/theme/' . $this->config->get('config_template') . '/stylesheet/' . $css_file_path);
          } else {
            $this->document->addStyle('catalog/view/theme/default/stylesheet/' . $css_file_path);
          }
        }
      }
    }
    
    // Get product info.
    $this->load->model('catalog/product');

    $product_info = $this->model_catalog_product->getProduct($product_id);
    
    
    // Price
    $price = false;

    if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
      $price_unformatted = $this->tax->calculate($product_info['price'], $product_info['tax_class_id'], $this->config->get('config_tax'));
    } else {
      $price_unformatted = false;
    }

    if ((float)$product_info['special']) {
      $special_price_unformatted = $this->tax->calculate($product_info['special'], $product_info['tax_class_id'], $this->config->get('config_tax'));
    } else {
      $special_price_unformatted = false;
    }

    if ($special_price_unformatted) {
      $price = $special_price_unformatted;
    } else {
      $price = $price_unformatted;
    }
    
    // Quantity
    if (isset($product_info['minimum']) && is_numeric($product_info['minimum']) && $product_info['minimum'] > 1) {
      $price = $price * $product_info['minimum'];
    }    
    
    
    if ($this->debug === true) {
      $this->cache->delete($this->module_key);
    }
    
    
    // Try to get cache data.  
    $installment_plan_info_data = $this->cache->get($this->module_key . '.' . (int)$module . '.' . (int)$product_id . '.' . (int)$this->config->get('config_store_id'). '.' . $this->config->get('config_language_id') . '.' . strtolower($this->currency->getCode()));
    
    if ($installment_plan_info_data && $installment_plan_info_data['_price'] == $price) {

      $this->data = $installment_plan_info_data;
      
    } else {
      $this->data = $this->_getData($setting, $price, $content);
      
      $this->cache->set($this->module_key . '.' . (int)$module . '.' . (int)$product_id . '.' . (int)$this->config->get('config_store_id'). '.' . $this->config->get('config_language_id') . '.' . strtolower($this->currency->getCode()), $this->data);
    }
    
    
    // Assign additional data to the veiw for auto installment price update.
    $this->data['setting'] = $setting;
    $this->data['product_id'] = $product_id;    
    
    // Add up the module count.
    $this->data['module'] = $module++;

    
    // Template
		if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/installment_plan_info.tpl')) {
			$this->template = $this->config->get('config_template') . '/template/module/installment_plan_info.tpl';
		} else {
			$this->template = 'default/template/module/installment_plan_info.tpl';
		}
								
		$this->render();    
  }
  
/**
 * ajax_get_template method
 *
 * @param array $setting
 * @return void
 */  
  public function ajax_index() {
    
    if (!isset($this->request->post)) {
      return false;
    }

    // Setting
    $setting = array(
        'content_id' => $this->request->post['content_id'],
        'image_width' => $this->request->post['image_width'],
        'image_height' => $this->request->post['image_height'],
        'layout_id' => $this->request->post['layout_id'],
        'position' => $this->request->post['position'],
        'status' => $this->request->post['status'],
        'sort_order' => $this->request->post['sort_order']
    );
    
    // Module
    if (!isset($this->request->post['module'])) {
      return false;
    }
    $module = (int)$this->request->post['module'];
    
    // Product Id
    if (!isset($this->request->post['product_id'])) {
      return false;
    }
    $product_id = (int)$this->request->post['product_id'];
    
    // Quantity
    if (!isset($this->request->post['quantity'])) {
      return false;
    }
    
    if (!is_numeric($this->request->post['quantity'])) {
      return false;
    }
    
    $quantity = (int)$this->request->post['quantity'];

    // Product Option value Ids
    if (isset($this->request->post['product_option_value_ids'])) {
      $product_option_value_ids = (array)$this->request->post['product_option_value_ids'];
    } else {
      $product_option_value_ids = array();
    }
    
    
    // Get the settings
    $content = $this->config->get($this->module_key . '_' . $setting['content_id']);
    
    
    // Stores
    $stores = array();

    if (isset($content['stores'])) {
      $stores = (array)$content['stores'];
    }

    if (!$stores || !in_array($this->config->get('config_store_id'), $stores)) {
      return false;
    }

    // Access levels
    $customer_group_display = array();

    if (isset($content['access_levels'])) {
      $customer_group_display = (array)$content['access_levels'];
    }    

    if (!$this->customer->isLogged() && !in_array(0, $customer_group_display)) {
      return false;
    }

    if ($this->customer->isLogged()) {

      $this->load->model('account/customer_group');

      $customer_group_info = $this->model_account_customer_group->getCustomerGroup($this->customer->getCustomerGroupId());

      if (!in_array($customer_group_info['customer_group_id'], $customer_group_display)) {
        return false;
      }
    }    

    
    // Get product info.
    $this->load->model('catalog/product');

    $product_info = $this->model_catalog_product->getProduct($product_id);   

    
    // Price
    $price = false;

    if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
      $price_unformatted = $this->tax->calculate($product_info['price'], $product_info['tax_class_id'], $this->config->get('config_tax'));
    } else {
      $price_unformatted = false;
    }

    if ((float)$product_info['special']) {
      $special_price_unformatted = $this->tax->calculate($product_info['special'], $product_info['tax_class_id'], $this->config->get('config_tax'));
    } else {
      $special_price_unformatted = false;
    }

    if ($special_price_unformatted) {
      $price = $special_price_unformatted;
    } else {
      $price = $price_unformatted;
    }
    
    // Product Discounts    
    if ($this->customer->isLogged()) {
      $customer_group_id = $this->customer->getCustomerGroupId();
    } else {
      $customer_group_id = $this->config->get('config_customer_group_id');
    }    
    
    $product_discount_query = $this->db->query(
      "SELECT price FROM " . DB_PREFIX . "product_discount"
      . " WHERE product_id = '" . (int)$product_id . "' AND customer_group_id = '" . (int)$customer_group_id . "'"
      . " AND quantity <= '" . (int)$quantity  . "'"
      . " AND ((date_start = '0000-00-00' OR date_start < NOW()) AND (date_end = '0000-00-00' OR date_end > NOW()))"
      . " ORDER BY quantity DESC, priority ASC, price ASC"
      . " LIMIT 1"
    );

    if ($product_discount_query->num_rows) {
      $discount_price_unformatted = $this->tax->calculate($product_discount_query->row['price'], $product_info['tax_class_id'], $this->config->get('config_tax'));
      $price = $discount_price_unformatted;
    } 

    
    // Product option values
    if ($product_option_value_ids) {
      
      $this->load->model('module/installment_plan_info');

      $option_values = $this->model_module_installment_plan_info->getProductOptionValues($product_id, $product_option_value_ids);

      foreach ($option_values as $option_value) {
        if (!$option_value['subtract'] || ($option_value['quantity'] > 0)) {
          if ((($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) && (float)$option_value['price']) {
            $option_price = $this->tax->calculate($option_value['price'], $product_info['tax_class_id'], $this->config->get('config_tax'));
          } else {
            $option_price = false;
          }

          if ($option_price) {
            $price = $price + $option_price;
          }
        }
      }
      
    }
    
    // Quantity
    if ($quantity && $quantity > 1) {
      $price = $price * $quantity;
    }   

    // Get data.
    $this->data = $this->_getData($setting, $price, $content);
    
    // Assign additional data to the veiw for auto installment price update.
    $this->data['setting'] = $setting;
    $this->data['product_id'] = $product_id;    
    

    $this->data['module'] = $module;

    
    // Template
		if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/installment_plan_info.tpl')) {
			$this->template = $this->config->get('config_template') . '/template/module/installment_plan_info.tpl';
		} else {
			$this->template = 'default/template/module/installment_plan_info.tpl';
		}

    $this->response->setOutput($this->render());
  }
  
/**
 * _getData method
 *
 * @param array $setting
 * @param float $price
 * @param array $content
 * @return View data
 */  
  private function _getData($setting, $price, $content) {
    
    $data = array();
    
    // Price value to use for cache.
    $data['_price'] = $price;
    
    // Key
    if ($content['key']) {
      $data['key'] = $content['key'];
    } else {
      $data['key'] = "";
    }

    // Assign data to the view.
    $this->language->load('module/installment_plan_info');

    // Title
    if (isset($content['title'][(int) $this->config->get('config_language_id')]) && $content['title'][(int) $this->config->get('config_language_id')]) {
      $data['heading_title'] = $content['title'][(int) $this->config->get('config_language_id')];
    } else {
      $data['heading_title'] = $this->language->get('heading_title');
    }

    // Title link
    if ($content['title_link']) {
      $data['heading_title_link'] = $content['title_link'];
    } else {
      $data['heading_title_link'] = "";
    }

    // General Promotional Message
    if (isset($content['general_promo_message'][(int) $this->config->get('config_language_id')]) && $content['general_promo_message'][(int) $this->config->get('config_language_id')]) {
      $data['general_promo_message'] = $content['general_promo_message'][(int) $this->config->get('config_language_id')];
    } else {
      $data['general_promo_message'] = false;
    }

    
    // Installment plans
    $data['installment_plans'] = array();
    
    // Promo messages
    $data['promo_msgs'] = array();

    
    // Minimum Installment Amount
    if ($this->session->data['currency']) {
      $currency_code = $this->session->data['currency'];
    } else {
      $currency_code = $this->config->get('config_currency');
    }

    if (isset($content['min_instal_amt'][$currency_code])) {
      $min_instal_amt = (float)$content['min_instal_amt'][$currency_code];
    } else {
      $min_instal_amt = 0;
    }

    if (isset($content['installment_plans']) && $content['installment_plans']) {

      // Instantiate a math class
      $math = new EvalMath;

      // Get formulas for payment calculation.
      $formulas = InstallmentPlanInfo::getFormulas();

      foreach ($content['installment_plans'] as $key => $plan) {

        if (!isset($plan['no_of_instal'])) {
          continue;
        }

        $data['installment_plans'][$key]['no_of_instal'] = $plan['no_of_instal'];
        $data['installment_plans'][$key]['plan_type'] = $plan['plan_type'];
        $data['installment_plans'][$key]['comment'] = null;
        $data['installment_plans'][$key]['promo_msg'] = null;


        foreach ($plan['payments'] as $paymentKey => $payment) {

          if ($plan['plan_type'] == 1) {  //  Equal payment method
            $plan_type_key = 'equal';
            $_price = $price;

          } else if ($plan['plan_type'] == 2) {  //  Variable payment method
            $plan_type_key = 'variable';
            $_price = $price * ($payment['principal'] / 100);
          }

          // Set priciple to 100% if not specified yet.
          if (!isset($payment['principal'])) {
            $payment['principal'] = 100;
          }

          $payment['principal'] = (float)$payment['principal'];

          // Get type of formula.
          $formula_type = null;

          if (isset($plan['formula_type']) && $plan['formula_type']) {
            $formula_type = $plan['formula_type'];
          }

          // Apply formula.
          $formula = null;
          
          if (isset($formulas[$formula_type][$plan_type_key])) {
          
            foreach ($formulas[$formula_type][$plan_type_key] as $operation  => $value) {
              if ($value) {
                $op = str_replace(
                  array('[disc]', '[int]', '[instal]', '[price]', '[prin]'),
                  array((float)$payment['discount'], (float)$payment['interest'], (int)$plan['no_of_instal'], (float)$_price, (float)$payment['principal']),
                $operation);

                if (eval("return ($op);")) { 
                  $formula = $value;
                  break;
                }
              }
            }
            unset($operation, $op, $value);
          }

          // Calculate the amount for an installment paymment by using a formula above.
          $amount = null;

          if ($formula) {
            $_formula = str_replace(
              array('[disc]', '[int]', '[instal]', '[price]', '[prin]'),
              array((float)$payment['discount'], (float)$payment['interest'], (int)$plan['no_of_instal'], (float)$_price, (float)$payment['principal']),
            $formula);

            $amount = $math->evaluate($_formula);
            unset($_formula);
          }


          // Remove a row that contains an amount smaller than the minimum installment amount.
          if($amount <= $min_instal_amt) {
            unset($data['installment_plans'][$key]);
            continue;
          }

          $data['installment_plans'][$key]['payments'][$paymentKey]['installment'] = $payment['installment'];

          if (isset($payment['principal'])) {
            $data['installment_plans'][$key]['payments'][$paymentKey]['principal'] = $payment['principal'];
          }

          $data['installment_plans'][$key]['payments'][$paymentKey]['interest'] = $payment['interest'];
          $data['installment_plans'][$key]['payments'][$paymentKey]['amount'] = $amount;
          $data['installment_plans'][$key]['payments'][$paymentKey]['formatted_amount'] = $this->currency->format($amount);

          // Comment
          if (isset($plan['comment'][(int) $this->config->get('config_language_id')]) && $plan['comment'][(int) $this->config->get('config_language_id')]) {

            if (isset($data['installment_plans'][$key]['comment'])) {
              $comment = $data['installment_plans'][$key]['comment'];
            } else {
              $comment = $plan['comment'][(int) $this->config->get('config_language_id')];
            }

            // Replace tokens
            $comment = str_replace(
              array('[d'. $paymentKey . ']', '[i'. $paymentKey . ']', '[p'. $paymentKey . ']', '[x]'),
              array($payment['discount'], round($payment['interest'], 2), $this->currency->format($amount), $plan['no_of_instal']),
            $comment);

            $data['installment_plans'][$key]['comment'] = $comment;
          }

          // Promo messages
          if (isset($plan['promo_msg'][(int) $this->config->get('config_language_id')]) && $plan['promo_msg'][(int) $this->config->get('config_language_id')]) {

            if (isset($data['installment_plans'][$key]['promo_msg'])) {
              $promo_msg = $data['installment_plans'][$key]['promo_msg'];
            } else {
              $promo_msg = $plan['promo_msg'][(int) $this->config->get('config_language_id')];
            }

            // Replace tokens
            $promo_msg = str_replace(
              array('[d'. $paymentKey . ']', '[i'. $paymentKey . ']', '[p'. $paymentKey . ']', '[x]'),
              array($payment['discount'], round($payment['interest'], 2), $this->currency->format($amount), $plan['no_of_instal']),
            $promo_msg);

            $data['installment_plans'][$key]['promo_msg'] = $promo_msg;
          }

        } // END of foreach


        // Promo messages
        if (isset($promo_msg)) {
          if ($promo_msg) {
            $data['promo_msgs'][] = $promo_msg;
          }
          unset($promo_msg);
        }


      } // END of foreach
    }


    // Payment Methods
    $data['payment_methods'] = array();

    $this->load->model('tool/image');

    $array_payment_methods = $this->language->get('array_payment_methods');

    if (isset($content['payment_methods']) && $content['payment_methods']) {

      foreach ($content['payment_methods'] as $key => $value) {

        if ($value['status']) {
          foreach ($array_payment_methods as $k => $name) {
            if ($k == $key) {

              $image = null;

              if (file_exists(DIR_IMAGE . $this->image_base_path . 'payment_methods' . DIRECTORY_SEPARATOR . $key . '.png')) {
                $image = $this->model_tool_image->resize($this->image_base_path . 'payment_methods' . DIRECTORY_SEPARATOR . $key . '.png', $setting['image_width'], $setting['image_height']);
              }

              $no_of_instal = null;

              if (isset($value['no_of_instal']) && $value['no_of_instal']) {
                $no_of_instal = sprintf($this->language->get('text_payment_method_max_term'), (int)$value['no_of_instal']);
              }

              $data['payment_methods'][$key] = array(
                  'name' => $name,
                  'thumb' => $image,
                  'no_of_instal' => $no_of_instal
              );
            }
          }
        }
      }
    }    
    
    return $data;
  }

}
?>