<?php

if (!defined('ABSPATH')) {
    exit;
}
abstract class WC_Shipping_Method extends WC_Settings_API
{
    public $supports = array('settings');
    public $id = '';
    public $method_title = '';
    public $method_description = '';
    public $enabled = 'yes';
    public $title;
    public $rates = array();
    public $tax_status = 'taxable';
    public $fee = null;
    public $minimum_fee = null;
    public $instance_id = 0;
    public $instance_form_fields = array();
    public $instance_settings = array();
    public $availability;
    public $countries = array();
    public function __construct($instance_id = 0)
    {
        $this->instance_id = absint($instance_id);
    }
    public function supports($feature)
    {
        return apply_filters('woocommerce_shipping_method_supports', in_array($feature, $this->supports), $feature, $this);
    }
    public function calculate_shipping($package = array())
    {
    }
    public function is_taxable()
    {
        return wc_tax_enabled() && 'taxable' === $this->tax_status && (WC()->customer && !WC()->customer->get_is_vat_exempt());
    }
    public function is_enabled()
    {
        return 'yes' === $this->enabled;
    }
    public function get_instance_id()
    {
        return $this->instance_id;
    }
    public function get_method_title()
    {
        return apply_filters('woocommerce_shipping_method_title', $this->method_title, $this);
    }
    public function get_method_description()
    {
        return apply_filters('woocommerce_shipping_method_description', $this->method_description, $this);
    }
    public function get_title()
    {
        return apply_filters('woocommerce_shipping_method_title', $this->title, $this->id);
    }
    public function get_rates_for_package($package)
    {
        $this->rates = array();
        if ($this->is_available($package) && (empty($package['ship_via']) || in_array($this->id, $package['ship_via']))) {
            $this->calculate_shipping($package);
        }
        return $this->rates;
    }
    public function get_rate_id($suffix = '')
    {
        $rate_id = array($this->id);
        if ($this->instance_id) {
            $rate_id[] = $this->instance_id;
        }
        if ($suffix) {
            $rate_id[] = $suffix;
        }
        return implode(':', $rate_id);
    }
    public function add_rate($args = array())
    {
        $args = apply_filters('woocommerce_shipping_method_add_rate_args', wp_parse_args($args, array('id' => $this->get_rate_id(), 'label' => '', 'cost' => '0', 'taxes' => '', 'calc_tax' => 'per_order', 'meta_data' => array(), 'package' => false, 'price_decimals' => wc_get_price_decimals())), $this);
        if (!$args['id'] || !$args['label']) {
            return;
        }
        $total_cost = is_array($args['cost']) ? array_sum($args['cost']) : $args['cost'];
        $taxes = $args['taxes'];
        if (!is_array($taxes) && false !== $taxes && $total_cost > 0 && $this->is_taxable()) {
            $taxes = 'per_item' === $args['calc_tax'] ? $this->get_taxes_per_item($args['cost']) : WC_Tax::calc_shipping_tax($total_cost, WC_Tax::get_shipping_tax_rates());
        }
        $total_cost = wc_format_decimal($total_cost, $args['price_decimals']);
        $rate = new WC_Shipping_Rate();
        $rate->set_id($args['id']);
        $rate->set_method_id($this->id);
        $rate->set_instance_id($this->instance_id);
        $rate->set_label($args['label']);
        $rate->set_cost($total_cost);
        $rate->set_taxes($taxes);
        if (!empty($args['meta_data'])) {
            foreach ($args['meta_data'] as $key => $value) {
                $rate->add_meta_data($key, $value);
            }
        }
        if ($args['package']) {
            $items_in_package = array();
            foreach ($args['package']['contents'] as $item) {
                $product = $item['data'];
                $items_in_package[] = $product->get_name() . ' &times; ' . $item['quantity'];
            }
            $rate->add_meta_data(__('Items', 'woocommerce'), implode(', ', $items_in_package));
        }
        $this->rates[$args['id']] = apply_filters('woocommerce_shipping_method_add_rate', $rate, $args, $this);
    }
    protected function get_taxes_per_item($costs)
    {
        $taxes = array();
        if (is_array($costs)) {
            $cart = WC()->cart->get_cart();
            foreach ($costs as $cost_key => $amount) {
                if (!isset($cart[$cost_key])) {
                    continue;
                }
                $item_taxes = WC_Tax::calc_shipping_tax($amount, WC_Tax::get_shipping_tax_rates($cart[$cost_key]['data']->get_tax_class()));
                foreach (array_keys($taxes + $item_taxes) as $key) {
                    $taxes[$key] = (isset($item_taxes[$key]) ? $item_taxes[$key] : 0) + (isset($taxes[$key]) ? $taxes[$key] : 0);
                }
            }
            if (isset($costs['order'])) {
                $item_taxes = WC_Tax::calc_shipping_tax($costs['order'], WC_Tax::get_shipping_tax_rates());
                foreach (array_keys($taxes + $item_taxes) as $key) {
                    $taxes[$key] = (isset($item_taxes[$key]) ? $item_taxes[$key] : 0) + (isset($taxes[$key]) ? $taxes[$key] : 0);
                }
            }
        }
        return $taxes;
    }
    public function is_available($package)
    {
        $available = $this->is_enabled();
        if (!$this->instance_id && $available) {
            $countries = is_array($this->countries) ? $this->countries : array();
            switch ($this->availability) {
                case 'specific':
                case 'including':
                    $available = in_array($package['destination']['country'], array_intersect($countries, array_keys(WC()->countries->get_shipping_countries())));
                    break;
                case 'excluding':
                    $available = in_array($package['destination']['country'], array_diff(array_keys(WC()->countries->get_shipping_countries()), $countries));
                    break;
                default:
                    $available = in_array($package['destination']['country'], array_keys(WC()->countries->get_shipping_countries()));
                    break;
            }
        }
        return apply_filters('woocommerce_shipping_' . $this->id . '_is_available', $available, $package, $this);
    }
    public function get_fee($fee, $total)
    {
        if (strstr($fee, '%')) {
            $fee = $total / 100 * str_replace('%', '', $fee);
        }
        if (!empty($this->minimum_fee) && $this->minimum_fee > $fee) {
            $fee = $this->minimum_fee;
        }
        return $fee;
    }
    public function has_settings()
    {
        return $this->instance_id ? $this->supports('instance-settings') : $this->supports('settings');
    }
    public function get_admin_options_html()
    {
        if ($this->instance_id) {
            $settings_html = $this->generate_settings_html($this->get_instance_form_fields(), false);
        } else {
            $settings_html = $this->generate_settings_html($this->get_form_fields(), false);
        }
        return '<table class="form-table">' . $settings_html . '</table>';
    }
    public function admin_options()
    {
        if (!$this->instance_id) {
            echo '<h2>' . esc_html($this->get_method_title()) . '</h2>';
        }
        echo wp_kses_post(wpautop($this->get_method_description()));
        echo $this->get_admin_options_html();
    }
    public function get_option($key, $empty_value = null)
    {
        if ($this->instance_id && array_key_exists($key, $this->get_instance_form_fields())) {
            return $this->get_instance_option($key, $empty_value);
        }
        $option = apply_filters('woocommerce_shipping_' . $this->id . '_option', parent::get_option($key, $empty_value), $key, $this);
        return $option;
    }
    public function get_instance_option($key, $empty_value = null)
    {
        if (empty($this->instance_settings)) {
            $this->init_instance_settings();
        }
        if (!isset($this->instance_settings[$key])) {
            $form_fields = $this->get_instance_form_fields();
            $this->instance_settings[$key] = $this->get_field_default($form_fields[$key]);
        }
        if (!is_null($empty_value) && '' === $this->instance_settings[$key]) {
            $this->instance_settings[$key] = $empty_value;
        }
        $instance_option = apply_filters('woocommerce_shipping_' . $this->id . '_instance_option', $this->instance_settings[$key], $key, $this);
        return $instance_option;
    }
    public function get_instance_form_fields()
    {
        return apply_filters('woocommerce_shipping_instance_form_fields_' . $this->id, array_map(array($this, 'set_defaults'), $this->instance_form_fields));
    }
    public function get_instance_option_key()
    {
        return $this->instance_id ? $this->plugin_id . $this->id . '_' . $this->instance_id . '_settings' : '';
    }
    public function init_instance_settings()
    {
        $this->instance_settings = get_option($this->get_instance_option_key(), null);
        if (!is_array($this->instance_settings)) {
            $form_fields = $this->get_instance_form_fields();
            $this->instance_settings = array_merge(array_fill_keys(array_keys($form_fields), ''), wp_list_pluck($form_fields, 'default'));
        }
    }
    public function process_admin_options()
    {
        if (!$this->instance_id) {
            return parent::process_admin_options();
        }
        if (!isset($_REQUEST['instance_id']) || absint($_REQUEST['instance_id']) !== $this->instance_id) {
            return false;
        }
        $this->init_instance_settings();
        $post_data = $this->get_post_data();
        foreach ($this->get_instance_form_fields() as $key => $field) {
            if ('title' !== $this->get_field_type($field)) {
                try {
                    $this->instance_settings[$key] = $this->get_field_value($key, $field, $post_data);
                } catch (Exception $e) {
                    $this->add_error($e->getMessage());
                }
            }
        }
        return update_option($this->get_instance_option_key(), apply_filters('woocommerce_shipping_' . $this->id . '_instance_settings_values', $this->instance_settings, $this), 'yes');
    }
}