coupons ))
            self::$applied_coupons = jigoshop_session::instance()->coupons;
        self::$tax = new jigoshop_tax(100); //initialize tax on the cart with divisor of 100
        // needed to calculate cart total for cart widget. Separated from calculate_totals
        // so that shipping doesn't need to be calculated so many times. Calling the server
        // api's ofter per page request isn't a good idea.
        self::calculate_cart_total();
    }
    /** Gets the cart data from the PHP session */
    function get_cart_from_session() {
        if (isset( jigoshop_session::instance()->cart ) && is_array( jigoshop_session::instance()->cart )) :
            $cart = jigoshop_session::instance()->cart;
            foreach ($cart as $key => $values) :
                if ($values['data']->exists() && $values['quantity'] > 0) :
                    self::$cart_contents[$key] = array(
                        'product_id'    => $values['product_id'],
                        'variation_id'  => $values['variation_id'],
                        'variation'     => $values['variation'],
                        'quantity'      => $values['quantity'],
                        'data'          => $values['data']
                    );
                endif;
            endforeach;
        else :
            self::$cart_contents = array();
        endif;
        if (!is_array(self::$cart_contents))
            self::$cart_contents = array();
    }
    /** sets the php session data for the cart and coupon */
    function set_session() {
        // we get here from cart additions, quantity adjustments, and coupon additions
        // reset any chosen shipping methods as these adjustments can effect shipping (free shipping)
        unset( jigoshop_session::instance()->chosen_shipping_method_id );
        unset( jigoshop_session::instance()->selected_rate_id ); // calculable shipping
        jigoshop_session::instance()->cart = self::$cart_contents;
        jigoshop_session::instance()->coupons = self::$applied_coupons;
        // This has to be tested. I believe all that needs to be calculated at time of setting session
        // is really the cart total and not shipping. All functions that use set_session are functions
        // that either add to the cart or apply coupons, etc. If the cart page is reloaded, the full
        // calculate_totals is already called.
        self::calculate_cart_total();
    }
    /** Empty the cart */
    function empty_cart() {
        self::$cart_contents = array();
        self::$applied_coupons = array();
        self::reset_totals();
        unset(jigoshop_session::instance()->cart);
        unset(jigoshop_session::instance()->coupons);
        unset(jigoshop_session::instance()->chosen_shipping_method_id);
        unset(jigoshop_session::instance()->selected_rate_id);
    }
    /**
     * Check if product is in the cart and return cart item key
     *
     * @param int $product_id
     * @param int $variation_id optional variation id
     * @param array $variation array of attributre values
     * @return int|null
     */
    function find_product_in_cart($product_id, $variation_id, $variation = array()) {
        foreach (self::$cart_contents as $cart_item_key => $cart_item) {
            if (empty($variation_id) && $cart_item['product_id'] == $product_id) {
                return $cart_item_key;
            } else if ($cart_item['product_id'] == $product_id && $cart_item['variation_id'] == $variation_id) {
                if ($variation == $cart_item['variation']) {
                    return $cart_item_key;
                }
            }
        }
        return NULL;
    }
    /**
     * Add a product to the cart
     *
     * @param   string	product_id	contains the id of the product to add to the cart
     * @param   string	quantity	contains the quantity of the item to add
     * @param   int     variation_id
     * @param   array   variation attribute values
     */
    function add_to_cart($product_id, $quantity = 1, $variation_id = '', $variation = array()) {
        if ($quantity < 0) {
            $quantity = 0;
        }
        $found_cart_item_key = self::find_product_in_cart($product_id, $variation_id, $variation);
        if (empty($variation_id)) {
            $product = new jigoshop_product($product_id);
        } else {
            $product = new jigoshop_product_variation($variation_id);
        }
        //product with a given ID doesn't exists
        if (empty($product)) {
            return false;
        }
        // prevents adding products with no price to the cart
        if ($product->get_price() === '') {
            jigoshop::add_error(__('You cannot add this product to your cart because its price is not yet announced', 'jigoshop'));
            return false;
        }
        // prevents adding products to the cart without enough quantity on hand
        $in_cart_qty = is_numeric($found_cart_item_key) ? self::$cart_contents[$found_cart_item_key]['quantity'] : 0;
        if ($product->managing_stock() && !$product->has_enough_stock($quantity + $in_cart_qty)) :
            if ($in_cart_qty > 0) :
				$error = (get_option('jigoshop_show_stock') == 'yes') ? sprintf(__('We are sorry.  We do not have enough "%s" to fill your request.  You have %d of them in your Cart and we have %d available at this time.', 'jigoshop'), $product->get_title(), $in_cart_qty, $product->get_stock()) : sprintf(__('We are sorry.  We do not have enough "%s" to fill your request.', 'jigoshop'), $product->get_title());
            else :
				$error = (get_option('jigoshop_show_stock') == 'yes') ? sprintf(__('We are sorry.  We do not have enough "%s" to fill your request. There are only %d left in stock.', 'jigoshop'), $product->get_title(), $product->get_stock()) : sprintf(__('We are sorry.  We do not have enough "%s" to fill your request.', 'jigoshop'), $product->get_title());
			endif;
			jigoshop::add_error($error);
            return false;
        endif;
        //if product is already in the cart change its quantity
        if (is_numeric($found_cart_item_key)) {
            $quantity = (int) $quantity + self::$cart_contents[$found_cart_item_key]['quantity'];
            self::set_quantity($found_cart_item_key, $quantity);
        } else {//othervise add new product to the cart
            $cart_item_key = sizeof(self::$cart_contents);
            self::$cart_contents[$cart_item_key] = array(
                'product_id' => $product_id,
                'variation_id' => $variation_id,
                'variation' => $variation,
                'quantity' => (int) $quantity,
                'data' => $product
            );
        }
        self::set_session();
        return true;
    }
    /**
     * Set the quantity for an item in the cart
     * Remove the item from the cart if no quantity
     * Also remove any product discounts if applied
     *
     * @param   string	cart_item_key	contains the id of the cart item
     * @param   string	quantity	contains the quantity of the item
     */
    function set_quantity($cart_item, $quantity = 1) {
        if ($quantity == 0 || $quantity < 0) :
            $_product = self::$cart_contents[$cart_item];
            if (self::$applied_coupons) :
                foreach (self::$applied_coupons as $key => $code) :
                    $coupon = jigoshop_coupons::get_coupon($code);
                    if (jigoshop_coupons::is_valid_product($code, $_product)) :
                        if ($coupon['type'] == 'fixed_product') {
                            self::$discount_total = self::$discount_total - ( $coupon['amount'] * $_product['quantity'] );
                            unset(self::$applied_coupons[$key]);
                        } else if ($coupon['type'] == 'percent_product') {
                            self::$discount_total = self::$discount_total - (( $_product['data']->get_price() * $_product['quantity'] / 100 ) * $coupon['amount']);
                            unset(self::$applied_coupons[$key]);
                        }
                    endif;
                endforeach;
            endif;
            unset(self::$cart_contents[$cart_item]);
        else :
            self::$cart_contents[$cart_item]['quantity'] = $quantity;
        endif;
        self::set_session();
    }
    /**
     * Returns the contents of the cart
     *
     * @return   array	cart_contents
     */
    static function get_cart() {
        return self::$cart_contents;
    }
    /**
     * Gets cross sells based on the items in the cart
     *
     * @deprecated - this functionality is within the Cross/Up Sells extension
     *
     * @return   array	cross_sells	item ids of cross sells
     */
    function get_cross_sells() {
        $cross_sells = array();
        $in_cart = array();
        if (sizeof(self::$cart_contents) > 0) :
        	foreach (self::$cart_contents as $cart_item_key => $values) :
				if ($values['quantity'] > 0) :
					$product = new jigoshop_product( $values['product_id'] );
					$cross_ids = $product->get_cross_sells();
					$cross_sells = array_merge($cross_ids, $cross_sells);
					$in_cart[] = $values['product_id'];
				endif;
            endforeach;
        endif;
        $cross_sells = array_diff($cross_sells, $in_cart);
        return $cross_sells;
    }
    /** gets the url to the cart page */
    function get_cart_url() {
        $cart_page_id = jigoshop_get_page_id('cart');
        if ($cart_page_id)
            return apply_filters('jigoshop_get_cart_url', get_permalink($cart_page_id));
    }
    /** gets the url to the checkout page */
    function get_checkout_url() {
        $checkout_page_id = jigoshop_get_page_id('checkout');
        if ($checkout_page_id) :
            if (is_ssl())
                return str_replace('http:', 'https:', get_permalink($checkout_page_id));
            return apply_filters('jigoshop_get_checkout_url', get_permalink($checkout_page_id));
        endif;
    }
    /** gets the url to the shop page */
    function get_shop_url() {
        $shop_page_id = jigoshop_get_page_id('shop');
        if ($shop_page_id) :
            return apply_filters('jigoshop_get_shop_page_id', get_permalink($shop_page_id));
        endif;
    }
    /** gets the url to remove an item from the cart */
    function get_remove_url($cart_item_key) {
        $cart_page_id = jigoshop_get_page_id('cart');
        if ($cart_page_id)
            return apply_filters('jigoshop_get_remove_url', jigoshop::nonce_url( 'cart', add_query_arg('remove_item', $cart_item_key, get_permalink($cart_page_id))));
    }
    /** looks through the cart to see if shipping is actually required */
    function needs_shipping() {
        if (!jigoshop_shipping::is_enabled())
            return false;
        if (!is_array(self::$cart_contents))
            return false;
        $needs_shipping = false;
        foreach (self::$cart_contents as $cart_item_key => $values) :
            $_product = $values['data'];
            if ($_product->is_type('simple') || $_product->is_type('variable')) :
                $needs_shipping = true;
            endif;
        endforeach;
        return $needs_shipping;
    }
    /** Sees if we need a shipping address */
    function ship_to_billing_address_only() {
        return (get_option('jigoshop_ship_to_billing_address_only') == 'yes');
    }
    /** looks at the totals to see if payment is actually required */
    function needs_payment() {
        if (self::$total > 0)
            return true;
        return false;
    }
    /** looks through the cart to check each item is in stock */
    function check_cart_item_stock() {
        foreach (self::$cart_contents as $cart_item_key => $values) {
            $_product = $values['data'];
            if (!$_product->is_in_stock() || ($_product->managing_stock() && !$_product->has_enough_stock($values['quantity']))) {
                $error = new WP_Error();
				$errormsg = (get_option('jigoshop_show_stock') == 'yes') ? sprintf(__('Sorry, we do not have enough "%s" in stock to fulfill your order. We only have %d available at this time. Please edit your cart and try again. We apologize for any inconvenience caused.', 'jigoshop'), $_product->get_title(), $_product->get_stock()) : sprintf(__('Sorry, we do not have enough "%s" in stock to fulfill your order. Please edit your cart and try again. We apologize for any inconvenience caused.', 'jigoshop'), $_product->get_title());
				$error->add('out-of-stock',$errormsg);
                return $error;
            }
        }
        return true;
    }
    /** reset all Cart totals */
    static function reset_totals() {
        self::$total = 0;
        self::$cart_contents_total = 0;
        self::$cart_contents_total_ex_tax = 0;
        self::$cart_contents_weight = 0;
        self::$cart_contents_count = 0;
        self::$shipping_tax_total = 0;
        self::$subtotal = 0;
        self::$subtotal_ex_tax = 0;
        self::$discount_total = 0;
        self::$shipping_total = 0;
        self::$cart_dl_count = 0;
        self::$cart_contents_total_ex_dl = 0; /* for table rate shipping */
        self::$subtotal_inc_tax = 0;
        self::$tax = new jigoshop_tax(100);
        jigoshop_shipping::reset_shipping();
    }
    private static function calculate_cart_total() {
        self::reset_totals();
        if (!count(self::$cart_contents)) :
            self::empty_cart(); /* no items, make sure applied coupons and session data reset, nothing to calculate */
            return;
        endif;
        foreach (self::$cart_contents as $cart_item_key => $values) :
            $_product = $values['data'];
            if ($_product->exists() && $values['quantity'] > 0) :
                self::$cart_contents_count = self::$cart_contents_count + $values['quantity'];
                // If product is downloadable don't apply to product
                if ($_product->product_type == 'downloadable') {
                    self::$cart_dl_count = self::$cart_dl_count + $values['quantity'];
                } else {
                    // If product is downloadable don't apply to weight
                    self::$cart_contents_weight = self::$cart_contents_weight + ($_product->get_weight() * $values['quantity']);
                }
                $total_item_price = $_product->get_price() * $values['quantity'] * 100; // Into pounds
                if (get_option('jigoshop_calc_taxes') == 'yes') :
                    if ($_product->is_taxable()) :
                        if (get_option('jigoshop_prices_include_tax') == 'yes' && jigoshop_customer::is_customer_shipping_outside_base() && (get_option('jigoshop_enable_shipping_calc')=='yes' ||  (defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT ))) :
                            $total_item_price = $_product->get_price_excluding_tax() * $values['quantity'] * 100;
                            self::$tax->calculate_tax_amounts($total_item_price, $_product->get_tax_classes(), false);
                            // now add customer taxes back into the total item price because customer is outside base
                            // and we asked to have prices include taxes
                            foreach (self::get_applied_tax_classes() as $tax_class) :
                                $total_item_price += self::get_tax_amount($tax_class, false) * 100; // keep tax with multiplier too
                            endforeach;
                        else :
                            self::$tax->calculate_tax_amounts($total_item_price, $_product->get_tax_classes(), get_option('jigoshop_prices_include_tax') == 'yes');
                        endif;
                    endif;
                endif;
                $total_item_price = $total_item_price / 100; // Back to pounds
                if (get_option('jigoshop_calc_taxes') == 'yes' && self::$tax->get_non_compounded_tax_amount()) :
                    if (get_option('jigoshop_prices_include_tax') == 'yes') :
                        self::$subtotal_inc_tax += $total_item_price - self::$tax->get_compound_tax_amount();
                    else :
                        self::$subtotal_inc_tax += self::$tax->get_non_compounded_tax_amount() + $total_item_price;
                    endif;
                endif;
                self::$cart_contents_total += $total_item_price;
                if (get_option('jigoshop_calc_taxes') == 'yes' && get_option('jigoshop_prices_include_tax') == 'yes' && !(get_option('jigoshop_display_totals_tax') == 'excluding' || ( defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT ))) :
                    self::$cart_contents_total = self::$subtotal_inc_tax;
                endif;
                if ($_product->product_type <> 'downloadable') {
                    self::$cart_contents_total_ex_dl = self::$cart_contents_total_ex_dl + $total_item_price;
                }
                self::$cart_contents_total_ex_tax = self::$cart_contents_total_ex_tax + ($_product->get_price_excluding_tax() * $values['quantity']);
                // Product Discounts for specific product ID's
                if (self::$applied_coupons) :
                    foreach (self::$applied_coupons as $code) :
                        $coupon = jigoshop_coupons::get_coupon($code);
                        if (jigoshop_coupons::is_valid_product($code, $values)) {
                            if ($coupon['type'] == 'fixed_product')
                                self::$discount_total += ( $coupon['amount'] * $values['quantity'] );
                            else if ($coupon['type'] == 'percent_product')
                                self::$discount_total += (( $values['data']->get_price() * $values['quantity'] / 100 ) * $coupon['amount']);
                        }
                    endforeach;
                endif;
            endif;
        endforeach;
    }
    /** calculate totals for the items in the cart */
    function calculate_totals() {
        // extracted cart totals so that the constructor can call it, rather than
        // this full method. Cart totals are needed for cart widget and themes.
        // Don't want to call shipping api's multiple times per page load
        self::calculate_cart_total();
        // Cart Shipping
        if (self::needs_shipping()) :
            jigoshop_shipping::calculate_shipping(self::$tax);
        else :
            jigoshop_shipping::reset_shipping();
        endif;
        self::$shipping_total = jigoshop_shipping::get_total();
        if (get_option('jigoshop_calc_taxes') == 'yes') :
            self::$shipping_tax_total = jigoshop_shipping::get_tax();
            self::$tax->update_tax_amount_with_shipping_tax(self::$shipping_tax_total * 100);
            if (self::$tax->is_shipping_tax_non_compounded() && get_option('jigoshop_display_totals_tax') == 'excluding' || ( defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT )) :
                self::$subtotal_inc_tax += self::$shipping_tax_total;
            endif;
        endif;
        // Subtotal
        self::$subtotal_ex_tax = self::$cart_contents_total_ex_tax;
        self::$subtotal = self::$cart_contents_total;
        // Cart Discounts
        if (self::$applied_coupons)
            foreach (self::$applied_coupons as $code) :
                if ($coupon = jigoshop_coupons::get_coupon($code)) :
                    if ($coupon['type'] == 'fixed_cart') :
                        self::$discount_total = self::$discount_total + $coupon['amount'];
                    elseif ($coupon['type'] == 'percent') :
                        self::$discount_total = self::$discount_total + ( self::$subtotal / 100 ) * $coupon['amount'];
                    elseif ($coupon['type'] == 'fixed_product' && sizeof($coupon['products']) == 0) :
                        // allow coupons for all products without specific product ID's entered
                        self::$discount_total = self::$discount_total + ($coupon['amount'] * self::$cart_contents_count);
                    endif;
                endif;
            endforeach;
        if (get_option('jigoshop_calc_taxes') == 'yes' && self::get_subtotal_inc_tax()) : // defines if there are mixed tax classes (with compounding taxes)
            foreach (self::get_applied_tax_classes() as $tax_class) :
                if (!self::is_not_compounded_tax($tax_class)) : //tax compounded
                    if (get_option('jigoshop_display_totals_tax') == 'excluding' || ( defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT )) :
                        self::$tax->update_tax_amount($tax_class, (self::$subtotal_inc_tax + self::$shipping_total) * 100);
                    else :
                        self::$tax->update_tax_amount($tax_class, (self::get_cart_subtotal(false) + self::get_cart_shipping_total(false)) * 100);
                    endif;
                endif;
            endforeach;
        endif;
        // Total
        self::$total = self::get_cart_subtotal(false) + self::get_cart_shipping_total(false) - self::$discount_total;
        if (get_option('jigoshop_calc_taxes') == 'yes') :
            if (get_option('jigoshop_display_totals_tax') == 'excluding' || ( defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT )) :
                self::$total += self::$tax->get_non_compounded_tax_amount() + self::$tax->get_compound_tax_amount();
            else :
                if (self::get_subtotal_inc_tax()) :
                    self::$total += self::$tax->get_compound_tax_amount();
                endif;
            endif;
        endif;
        if (self::$total < 0)
            self::$total = 0;
    }
    /** gets cart contents total excluding tax. Shipping methods use this, and the contents total are calculated ahead of shipping */
    public static function get_cart_contents_total_excluding_tax() {
        return self::$cart_contents_total_ex_tax;
    }
    /** gets the total (after calculation) */
    public static function get_total($for_display = true) {
        return ($for_display ? jigoshop_price(self::$total) : number_format(self::$total, 2, '.', ''));
    }
    /** gets the cart contens total (after calculation) */
    function get_cart_total() {
        return jigoshop_price(self::$cart_contents_total);
    }
    /**
     * gets the sub total (after calculation). For display means that the price and exc, inc tags will be returned. Otherwise
     * it will return the subtotal numeric value
     */
    public static function get_cart_subtotal($for_display = true) {
        // if shop isn't calculating taxes, return subtotal
        if (get_option('jigoshop_calc_taxes') == 'no') :
            $return = ($for_display ? jigoshop_price(self::$subtotal) : number_format(self::$subtotal, 2, '.', ''));
        else:
            // calculate taxes with subtotal
            if (get_option('jigoshop_display_totals_tax') == 'excluding' || ( defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT )) :
                if (get_option('jigoshop_prices_include_tax') == 'yes') :
                    $return = ($for_display ? jigoshop_price(self::$subtotal_ex_tax) : number_format(self::$subtotal_ex_tax, 2, '.', ''));
                else :
                    $return = ($for_display ? jigoshop_price(self::$subtotal) : number_format(self::$subtotal, 2, '.', ''));
                endif;
                if (self::$tax->has_tax() && $for_display) :
                    $return .= __(' (ex. tax)', 'jigoshop');
                endif;
            else :
                if (get_option('jigoshop_prices_include_tax') == 'yes') :
                    $return = ($for_display ? jigoshop_price(self::$subtotal) : number_format(self::$subtotal, 2, '.', ''));
                else :
                    //don't use accessor function here, as it may not be right
                    $return = ($for_display ? jigoshop_price(self::$subtotal_inc_tax) : number_format(self::$subtotal_inc_tax, 2, '.', ''));
                endif;
                // previous calc of subtotal_inc_tax - subtotal doesn't work for home base when user has tax included in totals
                // and show including. Therefore find out if there is tax on the product.
                if (self::$tax->has_tax() && $for_display) :
                    $return .= __(' (inc. tax)', 'jigoshop');
                endif;
            endif;
        endif;
        return $return;
    }
    /**
     * gets the cart subtotal including compound taxes (after calculation) if necessary.
     * Since the tax rates loop in order of compound tax last
     * if is_compound_tax is true, then we need to return subtotal with tax, otherwise
     * don't return it. If only non compounded tax is applied, this function will always return
     * false which is good.
     */
    public static function get_subtotal_inc_tax($use_price = true) {
        if (!self::$tax->is_compound_tax() || get_option('jigoshop_calc_taxes') == 'no') return false;
        if (get_option('jigoshop_display_totals_tax') == 'excluding' || ( defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT )) :
            $return = ($use_price ? jigoshop_price(self::get_cart_subtotal(false) + self::get_cart_shipping_total(false) + self::$tax->get_non_compounded_tax_amount()) : number_format(self::get_cart_subtotal(false) + self::get_cart_shipping_total(false) + self::$tax->get_non_compounded_tax_amount(), 2, '.', ''));
        else:
            $return = ($use_price ? jigoshop_price(self::get_cart_subtotal(false) + self::get_cart_shipping_total(false)) : number_format(self::get_cart_subtotal(false) + self::get_cart_shipping_total(false), 2, '.', ''));
        endif;
        return $return;
    }
    public static function get_tax_for_display($tax_class) {
        $return = '';
        if (jigoshop_cart::get_tax_amount($tax_class, false) > 0) :
            $return = self::$tax->get_tax_class_for_display($tax_class) . ' (' . (float) jigoshop_cart::get_tax_rate($tax_class) . '%): ';
            // only show estimated tag when customer is on the cart page and no shipping calculator is enabled to be able to change
            // country
            if (!jigoshop_shipping::show_shipping_calculator() && !( defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT )) :
                $return .= '' . sprintf(__('estimated for %s', 'jigoshop'), jigoshop_countries::estimated_for_prefix() . __(jigoshop_countries::$countries[jigoshop_countries::get_base_country()], 'jigoshop')) . '';
            endif;
        endif;
        return $return;
    }
    // after calculation. Used with admin pages only
    public static function get_total_tax_rate() {
        return self::$tax->get_total_tax_rate();
    }
    public static function get_taxes_as_array($taxes_as_string) {
        return self::$tax->get_taxes_as_array($taxes_as_string, 100);
    }
    public static function get_taxes_as_string() {
        return self::$tax->get_taxes_as_string();
    }
    public static function get_applied_tax_classes() {
        return self::$tax->get_applied_tax_classes();
    }
    public static function get_tax_rate($tax_class) {
        return self::$tax->get_tax_rate($tax_class);
    }
    public static function get_tax_amount($tax_class, $with_price = true) {
        if (self::$shipping_tax_total) :
            return ($with_price ? jigoshop_price(self::$tax->get_tax_amount($tax_class)) : number_format(self::$tax->get_tax_amount($tax_class), 2, '.', ''));
        else :
            return ($with_price ? jigoshop_price(self::$tax->get_tax_amount($tax_class, false)) : number_format(self::$tax->get_tax_amount($tax_class, false), 2, '.', ''));
        endif;
    }
    public static function get_tax_divisor() {
        return self::$tax->get_tax_divisor();
    }
    public static function is_not_compounded_tax($tax_class) {
        return self::$tax->is_tax_non_compounded($tax_class);
    }
    /** gets the shipping total (after calculation) */
    public static function get_cart_shipping_total($for_display = true) {
        if (jigoshop_shipping::get_label()) :
            if (jigoshop_shipping::get_total() > 0) :
                if (get_option('jigoshop_calc_taxes') == 'no') :
                    $return = ($for_display ? jigoshop_price(self::$shipping_total) : number_format(self::$shipping_total, 2, '.', ''));
                else :
                    if (get_option('jigoshop_display_totals_tax') == 'excluding'  || ( defined('JIGOSHOP_CHECKOUT') && JIGOSHOP_CHECKOUT )) :
                        $return = ($for_display ? jigoshop_price(self::$shipping_total) : number_format(self::$shipping_total, 2, '.', ''));
                        if (self::$shipping_tax_total > 0 && $for_display) :
                            $return .= __(' (ex. tax)', 'jigoshop');
                        endif;
                    else :
                        $return = ($for_display ? jigoshop_price(self::$shipping_total + self::$shipping_tax_total) : number_format(self::$shipping_total + self::$shipping_tax_total, 2, '.', ''));
                        if (self::$shipping_tax_total > 0 && $for_display) :
                            $return .= __(' (inc. tax)', 'jigoshop');
                        endif;
                    endif;
                endif;
            else :
                $return = ($for_display ? __('Free!', 'jigoshop') : 0);
            endif;
            return $return;
        endif;
    }
    /** gets title of the chosen shipping method */
    function get_cart_shipping_title() {
        if (jigoshop_shipping::get_label()) :
            return __('via ', 'jigoshop') . jigoshop_shipping::get_label();
        endif;
        return false;
    }
    /**
     * Applies a coupon code
     *
     * @param   string	code	The code to apply
     * @return   bool	True if the coupon is applied, false if it does not exist or cannot be applied
     */
    function add_discount($coupon_code) {
        if ($the_coupon = jigoshop_coupons::get_coupon($coupon_code)) :
            // Check if applied
            if (jigoshop_cart::has_discount($coupon_code)) :
                jigoshop::add_error(__('Discount code already applied!', 'jigoshop'));
                return false;
            endif;
            // Check it can be used with cart
            // get_coupon() checks for valid coupon. don't go any further without one
            if (!jigoshop_coupons::get_coupon($coupon_code)) :
                jigoshop::add_error(__('Invalid coupon!', 'jigoshop'));
                return false;
            endif;
            // Check if coupon products are in cart
            if ( ! jigoshop_cart::has_discounted_products_in_cart( $the_coupon ) ) {
                jigoshop::add_error(__('No products in your cart match that coupon!', 'jigoshop'));
                return false;
            }
            // if it's a percentage discount for products, make sure it's for a specific product, not all products
            if ($the_coupon['type'] == 'percent_product' && sizeof($the_coupon['products']) == 0) :
                jigoshop::add_error(__('Invalid coupon!', 'jigoshop'));
                return false;
            endif;
            // before adding this coupon, make sure no individual use coupons already exist
            foreach (self::$applied_coupons as $coupon) :
                $coupon = jigoshop_coupons::get_coupon($coupon);
                if ($coupon['individual_use'] == 'yes') :
                    self::$applied_coupons = array();
                endif;
            endforeach;
            // If its individual use then remove other coupons
            if ($the_coupon['individual_use'] == 'yes') :
                self::$applied_coupons = array();
            endif;
            self::$applied_coupons[] = $coupon_code;
            self::set_session();
            jigoshop::add_message(__('Discount code applied successfully.', 'jigoshop'));
            return true;
        else :
            jigoshop::add_error(__('Coupon does not exist or is no longer valid!', 'jigoshop'));
            return false;
        endif;
        return false;
    }
    function has_discounted_products_in_cart( $thecoupon ) {
        // Check if we have products associated
        foreach( self::$cart_contents as $product ) {
            $product_id = empty( $product['variation_id'] )
                ? $product['product_id']
                : $product['variation_id'];
            if ( in_array( $product_id, $thecoupon['products']) )
                return true;
			else if ( empty ( $thecoupon['products'] ) )
				return true;
        }
        return false;
    }
    /** returns whether or not a discount has been applied */
    function has_discount($code) {
        if (in_array($code, self::$applied_coupons))
            return true;
        return false;
    }
    /** gets the total discount amount */
    function get_total_discount() {
        if (self::$discount_total)
            return jigoshop_price(self::$discount_total); else
            return false;
    }
}