<?php

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

/**
 * Standard Boxtal carrier class.
 */

class envoimoinscher_carrier extends WC_Shipping_Method {

	/** @var string Boxtal operator code */
	public $ope_code;

	/** @var string Boxtal service code */
	public $srv_code;

	/**
	 * __construct function.
	 *
	 * @access public
	 * @return void
	 */
	public function  __construct($instance_id = 0) {

		$this->id = self::getCalledClass();
		$this->instance_id = absint( $instance_id );

		$service = envoimoinscher_model::get_service_by_carrier_code($this->id);

		$this->ope_code = $service->ope_code;
		$this->srv_code = $service->srv_code;

        $lang = get_locale();
		$this->title = envoimoinscher_model::get_translation($service->srv_name_bo, $lang, true);
		$this->method_title = envoimoinscher_model::get_translation($service->srv_name_bo, $lang, true);

        $this->supports = array(
            'settings',
            'shipping-zones',
            'instance-settings',
            'instance-settings-modal',
        );

		$this->init();
	}

	/**
	 * init function.
	 *
	 * @access public
	 * @return void
	 */
	public function init() {
        
        // prevent instance page from being displayed
        if (isset($_GET['page']) && 'wc-settings' == $_GET['page'] 
            && isset($_GET['tab']) && 'shipping' == $_GET['tab']
            && isset($_GET['instance_id']) && $this->instance_id && $this->instance_id == $_GET['instance_id']) {
            wp_redirect(admin_url('admin.php?page=wc-settings&tab=shipping&section='.$this->id));
            exit;
        }

        $this->supports = array(
            'settings',
            'shipping-zones',
            'instance-settings',
            'global-instance',
        );
        
		// Load the settings API
		$this->init_settings(); // This is part of the settings API. Loads settings you previously init.
		$this->init_form_fields(); // This is part of the settings API. Override the method to add your own settings
		// Add rate calculation
		add_filter('woocommerce_calculated_shipping',array(&$this, 'calculate_shipping'));

		// Process settings
		add_action('woocommerce_update_options_shipping_'.$this->id, array(&$this, 'process_admin_options'));
	}

	/**
	 * update carrier options
	 * @access public
	 * @return void
	 *
	 */
	public function process_admin_options(){

		parent::process_admin_options();

        // process multilingual fields
        $srv_name_trads = array();
        $srv_desc_trads = array();
        foreach ($_POST as $key => $value) {
			if ('woocommerce_'.$this->id.'_srv_name' == substr($key, 0, -6)) {
                $srv_name_trads[substr($key, -5)] = $this->removeslashes($value);
            }
            if ('woocommerce_'.$this->id.'_srv_description' == substr($key, 0, -6)) {
                $srv_desc_trads[substr($key, -5)] = $this->removeslashes($value);
            }
		}

        $current_settings = get_option('woocommerce_'.$this->ope_code.'_'.$this->srv_code.'_settings');

        if($current_settings !== false) {
            $current_settings['srv_name'] = $srv_name_trads;
            $current_settings['srv_description'] = $srv_desc_trads;
            update_option('woocommerce_'.$this->ope_code.'_'.$this->srv_code.'_settings', $current_settings);
        }

        // process pricing
        $pricing_items = json_decode(stripslashes($_POST['pricing']));
        envoimoinscher_model::add_pricing($this->id, $pricing_items);
	}

    /**
	 * helper function to remove slashes (stripslashes doesn't work when there's too many slashes).
	 *
	 * @access public
	 * @return string
	 */
    public function removeslashes($string) {
        $string = implode("",explode("\\",$string));
        return stripslashes(trim($string));
    }

	/**
	 * init_form_fields function.
	 *
	 * @access public
	 * @return void
	 */
	public function init_form_fields() {

		$service = envoimoinscher_model::get_service_by_carrier_code($this->id);

        // get default tracking urls
        $tracking_urls = envoimoinscher_model::$tracking_urls;

		$this->form_fields = array(
			'enabled' => array(
				'title' => __( 'Enable/Disable', 'envoimoinscher' ),
				'type' => 'checkbox',
				'default' => 'yes',
			),
			'srv_name' => array(
				'title' => __( 'Label', 'envoimoinscher' ),
				'type' => 'multilingual_text',
				'description' => __( 'This controls the label which the user sees during checkout.', 'envoimoinscher' ),
				'default' => $service->srv_name,
                'class' => 'input-text regular-input',
			),
			'srv_description' => array(
				'title' => __( 'Description', 'envoimoinscher' ),
				'type' => 'multilingual_text',
				'description' => __( 'This controls the description which the user sees during checkout.', 'envoimoinscher' ),
				'default' => $service->srv_description,
                'class' => 'input-text regular-input',
			),
			'carrier_tracking_url' => array(
				'title' => __( 'Carrier tracking url', 'envoimoinscher' ),
				'description' => __( 'Use this field to add a carrier tracking URL to your customer order view page. If you use @ it will be replaced by the carrier tracking reference to get a direct URL to your order tracking. Leave blank if you don\'t want to display a tracking link.', 'envoimoinscher' ),
				'type' => 'text',
				'default' => isset($tracking_urls[$this->id]) ? $tracking_urls[$this->id] : '',
                'class' => 'emc_carrier_tracking_url'
			),
		);

	}

	/*
	 * Fix for PHP 5.2
	 */
	public static function getCalledClass(){

		if ( function_exists('get_called_class') ) {
			return get_called_class();
		}
		else {
			$arr = array();
			$arrTraces = debug_backtrace();
			foreach ($arrTraces as $arrTrace){
				 if(!array_key_exists("class", $arrTrace)) continue;
				 if(count($arr)==0) $arr[] = $arrTrace['class'];
				 else if(get_parent_class($arrTrace['class'])==end($arr)) $arr[] = $arrTrace['class'];
			}
			return end($arr);
		}
	}

    /*
	 * Fix for WP 3.9
	 */
	public static function custom_get_price_decimal_separator(){

		if (function_exists('wc_get_price_decimal_separator')) {
            return wc_get_price_decimal_separator();
        } else {
            $separator = stripslashes( get_option( 'woocommerce_price_decimal_sep' ) );
            return $separator ? $separator : '.';
        }
	}

	/**
	 * admin_options function.
	 *
	 * @access public
	 * @return void
	 */
	public function admin_options() {
		?>
            <h3><?php echo $this->method_title; ?></h3>
            <table class='form-table'>
                 <?php $this->generate_settings_html(); ?>
            </table>
		<?php
		include_once ('admin/views/html-admin-rate-table.php');
	}

	/**
	 * Generate Radio Input HTML.
	 *
	 * @param mixed $key
	 * @param mixed $data
	 * @since 1.0.
	 * @return string
	 */
	public function generate_radio_html( $key, $data ) {

		$field    = $this->plugin_id . $this->id . '_' . $key;
		$defaults = array(
			'title'             => '',
			'disabled'          => false,
			'class'             => '',
			'css'               => '',
			'placeholder'       => '',
			'type'              => 'radio',
			'desc_tip'          => false,
			'description'       => '',
			'custom_attributes' => array()
		);

		$data = wp_parse_args( $data, $defaults );

		ob_start();
		?>
		<tr valign="top">
			<th scope="row" class="titledesc">
				<label for="<?php echo esc_attr( $field ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
				<?php echo $this->get_tooltip_html( $data ); ?>
			</th>
			<td class="forminp">
				<fieldset>
					<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
					<ul class="radio <?php echo esc_attr( $data['class'] ); ?>"  id="<?php echo esc_attr( $field ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?>>
						<?php foreach ( (array) $data['options'] as $option_key => $option_value ) : ?>
							<li><label><input name="<?php echo esc_attr( $field ); ?>" value="<?php echo esc_attr( $option_key ); ?>" type="radio" <?php checked( $option_key, esc_attr( $this->get_option( $key ) ) ); ?>><?php echo esc_attr( $option_value ); ?></label></li>
						<?php endforeach; ?>
					</ul>
					<?php echo $this->get_description_html( $data ); ?>
				</fieldset>
			</td>
		</tr>
		<?php

		return ob_get_clean();
	}

	/**
	 * Generate multilingual text type field html.
	 *
	 * @param mixed $key
	 * @param mixed $data
	 * @since 1.0.0
	 * @return string
	 */
	public function generate_multilingual_text_html ($key, $data){

		$field    = $this->plugin_id . $this->id . '_' . $key;
		$defaults = array(
			'title'             => '',
			'disabled'          => false,
			'class'             => '',
			'css'               => '',
			'placeholder'       => '',
			'type'              => 'text',
			'desc_tip'          => false,
			'description'       => '',
			'custom_attributes' => array()
		);

		$data = wp_parse_args( $data, $defaults );

        // get field value
        $value = $this->get_option($key);

        // get installed languages & current language
        $current_language = get_locale();
        $languages = get_available_languages();
        array_push($languages, 'en_US'); // 'en_US' is always added by default and not returned by get_available_languages

		ob_start();
		?>
		<tr valign="top">
            <th scope="row" class="titledesc">
				<label for="<?php echo esc_attr( $field ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
				<?php echo $this->get_tooltip_html( $data ); ?>
			</th>
			<td class="forminp">
				<fieldset class="multilingual_fieldset">
					<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
					<?php
                        foreach ($languages as $key => $language) {
                            echo '<input type="text" class="'.esc_attr( $data['class'] ).' multilingual_field multilingual_field_'.$language.'" ';
                            echo 'name="'.esc_attr( $field ).'_'.$language.'" id="'.esc_attr( $field ).$language.'" value="';
                            echo esc_attr(envoimoinscher_model::get_translation($value, $language, false)).'" ';
                            if ($language != $current_language) {
                                echo 'style="display:none"';
                            }
                            echo '>';
                        }
                    ?>
                    <select class="multilingual_field_select">
                        <?php
                            foreach ($languages as $key => $language) {
                                echo '<option value="'.$language.'" ';
                                if ($language == $current_language) {
                                    echo 'selected=selected';
                                }
                                echo '>'.substr($language, 0, 2).'</option>';
                            }
                        ?>
                    </select>
				</fieldset>
				<?php echo $this->get_description_html( $data ); ?>
			</td>
		</tr>
		<?php

		return ob_get_clean();
	}

	/**
	 * calculate_shipping function.
	 *
	 * @access public
	 * @return void
	 */
	public function calculate_shipping( $package = array() ) {
        if(empty($package)) {
			return;
		}
        
		// get carrier settings
		$carrier_settings = get_option('woocommerce_'.$this->id.'_settings');

		// get package address
		$to = array(
			'country' => isset($package['destination']['country'])? $package['destination']['country']	: '',
			'state' => isset($package['destination']['state'])? $package['destination']['state']	: '',
			'zipcode' => isset($package['destination']['postcode'])	? trim($package['destination']['postcode']) : '',
			'city' => isset($package['destination']['city'])? $package['destination']['city'] : '',
			'address' => (isset($package['destination']['address'])? $package['destination']['address'] : '').
				(isset($package['destination']['address_2'])? $package['destination']['address_2'] : ''),
			'type' => 'individual'
		);

        // get package zones (if zones exists)
        $package_zone = array();
        if (envoimoinscher_model::is_zones_enabled()) {
            $package_zone = WC_Shipping_Zones::get_zone_matching_package($package);
        }

		// exit calculation if country or required fields (postal code or state) are not set
		if($to['country'] == ''){
			return;
		} else {
            $countries = EMC()->get_activated_countries();
            $address_fields = $countries->get_address_fields($to['country'], 'shipping_');
            if($address_fields['shipping_state']['required'] && $to['state'] == '') {
                return;
            }
            if($address_fields['shipping_postcode']['required'] && $to['zipcode'] == '') {
                return;
            }
        }

		$offers = envoimoinscher_model::split_package_get_quotation($to, $package);

        // stop there if no results
		if (!is_array($offers)) return;

        // stop there if all addresses don't have the carrier, else calculate live rate
        $live_rate = 0;
        foreach ($offers as $suborder_key => $carriers) {
            if (!isset($carriers[$this->id])) {
                return;
            } else {
                $live_rate += $carriers[$this->id]['price']['tax-exclusive'];
                envoimoinscher_model::log('Quotation - price for carrier '.$this->id.' is '.$carriers[$this->id]['price']['tax-exclusive']);
            }
        }

        // manage rate
        $cart_weight = envoimoinscher_model::get_cart_weight();
        $final_rate = '';
		$pricing_items = envoimoinscher_model::get_pricing($this->id);
        // get shipping classes in package without duplicates
        $package_shipping_classes = array();
        foreach ($package['contents'] as $cart_item) {
            $shipping_class = $cart_item['data']->get_shipping_class();
            if ($shipping_class == '' && !in_array('none', $package_shipping_classes)) {
                array_push($package_shipping_classes, 'none');
            } elseif (!in_array($shipping_class, $package_shipping_classes) && $shipping_class != '') {
                array_push($package_shipping_classes, $shipping_class);
            }
        }

        foreach ($pricing_items as $pricing_item) {
            envoimoinscher_model::log('Pricing rule - looking at pricing rule : minimum weight '.$pricing_item['weight-from'].' maximum weight '
            .$pricing_item['weight-to'].' minimum price '.$pricing_item['price-from'].' maximum price '.$pricing_item['price-to']);
            /* check if conditions in pricing_item meet current situation */
            if ($pricing_item['weight-from'] != '' && $cart_weight < floatval(str_replace(',', '.', $pricing_item['weight-from']))) {
                envoimoinscher_model::log('Pricing rule - pricing rule rejected because of minimum weight, weight is '.$cart_weight);
                continue;
            }
            if ($pricing_item['weight-to'] != '' && $cart_weight >= floatval(str_replace(',', '.', $pricing_item['weight-to']))) {
                envoimoinscher_model::log('Pricing rule - pricing rule rejected because of maximum weight price, weight is '.$cart_weight);
                continue;
            }
            if ($pricing_item['price-from'] != '' && $package['contents_cost'] < floatval(str_replace(',', '.', $pricing_item['price-from']))) {
                envoimoinscher_model::log('Pricing rule - pricing rule rejected because of minimum price, price is '.$package['contents_cost']);
                continue;
            }
            if ($pricing_item['price-to'] != '' && $package['contents_cost'] >= floatval(str_replace(',', '.', $pricing_item['price-to']))) {
                envoimoinscher_model::log('Pricing rule - pricing rule rejected because of maximum price, price is '.$package['contents_cost']);
                continue;
            }
            $test_shipping_class = array_diff($package_shipping_classes, $pricing_item['shipping-class']);
            if (!empty($test_shipping_class)) {
                envoimoinscher_model::log('Pricing rule - pricing rule rejected because of shipping class, shipping class is/are '.implode('/', $package_shipping_classes));
                continue;
            }
            if (envoimoinscher_model::is_zones_enabled()) {
                if ($pricing_item['zones'] == null || !in_array((string)$package_zone->get_id(), $pricing_item['zones'], true)) {
                    envoimoinscher_model::log('Pricing rule - pricing rule rejected because of zone, zone is '.$package_zone->get_zone_name());
                    continue;
                }
            }
            else {
                if ($pricing_item['zones'] == null || !in_array((string)$to['country'], $pricing_item['zones'],true)) {
                    envoimoinscher_model::log('Pricing rule - pricing rule rejected because of country, country is '.$to['country']);
                    continue;
                }
            }
            envoimoinscher_model::log('Pricing rule - pricing rule validated');

            /* if this is a match, apply pricing */
            switch ($pricing_item['pricing']) {
                case "live":
                    $final_rate = $live_rate;
                    // add handling fees
                    if($pricing_item['handling-fees'] != '') {
                        $handling_fees = floatval(str_replace(',', '.', $pricing_item['handling-fees']));
                        if($handling_fees != 0) {
                            // check if percentage
                            if(strpos($pricing_item['handling-fees'], '%') !== false) {
                                $final_rate = $final_rate * (1 + $handling_fees/100);
                            } else {
                                $final_rate = $final_rate + $handling_fees;
                            }
                        }
                    }
                    envoimoinscher_model::log('Pricing rule - final price for carrier '.$this->id.' after application (live quotation) is '.$final_rate);
                    break;

                case "rate":
                    $final_rate = $pricing_item['flat-rate'];
                    // add handling fees
                    if($pricing_item['handling-fees'] != '') {
                        $handling_fees = floatval(str_replace(',', '.', $pricing_item['handling-fees']));
                        if($handling_fees != 0) {
                            // check if percentage
                            if(strpos($pricing_item['handling-fees'], '%') !== false) {
                                $final_rate = $final_rate * (1 + $handling_fees/100);
                            } else {
                                $final_rate = $final_rate + $handling_fees;
                            }
                        }
                    }
                    envoimoinscher_model::log('Pricing rule - final price for carrier '.$this->id.' after application (flat rate) is '.$final_rate);
                    break;

                case "free":
                    $final_rate = 0;
                    envoimoinscher_model::log('Pricing rule - carrier '.$this->id.' is free');
                    break;

                case "deactivate":
                    envoimoinscher_model::log('Pricing rule - carrier '.$this->id.' is deactivated');
                    break;

                default :
                    break;
            }

            // exit loop
            break;
        }

        // in case no pricing item is a match
        if ($final_rate === '') {
            return;
        }

		// set carrier shipping cost
        $lang = get_locale();
		$rate = array(
			'id' => $this->id,
			'label' => envoimoinscher_model::get_translation($carrier_settings['srv_name'], $lang, false),
			'cost' => $final_rate,
            'package' => $package
		);

		$this->add_rate($rate);
	}

}/* end of class */
