/*~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
	Copyright (c) 2012 Brett Wejrowski

	wojodesign.com
	simplecartjs.org
	http://github.com/wojodesign/simplecart-js

	VERSION 3.0.5

	Dual licensed under the MIT or GPL licenses.
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~*/
/*jslint browser: true, unparam: true, white: true, nomen: true, regexp: true, maxerr: 50, indent: 4 */



class IoAccDialogStateMachine {
    constructor() {
        this.current_state = null;
        this.state_stack = [];
        this.states = [];
        this.prev_states = [];
        this.rental_obj = null;
        this.confirm_screen_elements = [];
        this.main_item_qty = 1;
        this.acc_obj = {}
    }

    async build_rental_obj(acc_obj, skip_avail=false) {
        this.rental_obj = new IO_Rental(acc_obj.main_id, acc_obj.name, acc_obj.increment);
        for (const [acc_id, sub_acc_obj] of Object.entries(acc_obj.accessories)) {
            let sub_rental_obj = new IO_Rental(acc_id, sub_acc_obj.name, sub_acc_obj.increment);
            sub_rental_obj.overrideprice = sub_acc_obj.overrideprice;
            sub_rental_obj.required = sub_acc_obj.required;
            if (sub_acc_obj.accessories && Object.keys(sub_acc_obj.accessories).length > 0) {
                sub_rental_obj = this.build_acc_obj(sub_acc_obj, sub_rental_obj);
            }
            this.rental_obj.accessory = sub_rental_obj;
        }
        if (jQuery("input[name=timeStart]").val() && jQuery("input[name=timeEnd]").val() && !skip_avail) {
            this.rental_obj.start_time = jQuery("input[name=timeStart]").val();
            this.rental_obj.end_time = jQuery("input[name=timeEnd]").val();
            IoData.info = [this.rental_obj];
            IoData.last_api_call = Date.now();
            await this.getAccDialogAvail();
            //IoData.info_cache = rental_obj;
            return this.rental_obj;
        }
        return this.rental_obj;
    }

    setBusy() {
        jQuery('body').css('cursor', 'wait');
        jQuery('*').css('cursor', 'wait');
        if (!jQuery('#io-busy-overlay').length) {
            jQuery('body').append('<div id="io-busy-overlay" style="position:fixed;top:0;left:0;width:100%;height:100%;z-index:999999;background:rgba(0,0,0,0.1);cursor:wait !important;"></div>');
        }
    }

    clearBusy() {
        jQuery('body').css('cursor', '');
        jQuery('*').css('cursor', '');
        jQuery('#io-busy-overlay').remove();
    }

    async getAccDialogAvail() {
        this.setBusy();
        let url = io_rest_lead_url;
        let post_data = {guid: IoData.guid, lead: IoData, recalc: ["availability"], type: "info", action:"update"};
        try {
            const response = await fetch(url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(post_data)
            });
            const data = await response.json();
            this.rental_obj = IO_Rental.fromObject(data["lead"]["info"][0]);
            this.rental_obj.availability += this.rental_obj.qty;
            this.calcAccessoryAvailability(this.rental_obj.accessories);
            return data;
        } finally {
            this.clearBusy();
        }
    }

    calcAccessoryAvailability(accessories){
        accessories.forEach((acc)=> {
            acc.availability += parseInt(acc.qty);
            if(!acc.required_accessoires_are_avail()){
                acc.availability = -1;
            }
            if(acc.accessories.length > 0) this.calcAccessoryAvailability(acc.accessories);
        })
    }

    build_acc_obj(sub_acc_obj, sub_rental_obj) {
        for (const [acc_id, sub_sub_acc_obj] of Object.entries(sub_acc_obj.accessories)) {
            let sub_acc_rental_obj = new IO_Rental(acc_id, sub_sub_acc_obj.name, sub_sub_acc_obj.increment);
            sub_acc_rental_obj.overrideprice = sub_sub_acc_obj.overrideprice;
            sub_acc_rental_obj.required = sub_sub_acc_obj.required;
            if (sub_sub_acc_obj.accessories && Object.keys(sub_sub_acc_obj.accessories).length > 0) {
                sub_acc_rental_obj = this.build_acc_obj(sub_sub_acc_obj, sub_acc_rental_obj);
            }
            sub_rental_obj.accessory = sub_acc_rental_obj;
        }
        return sub_rental_obj;
    }

    set_acc_qty(target_id, path, qty, rental_obj) {
        if (path.includes("_")) {
            let this_level = path.split("_")[0];
            let next_level = path.split("_")[1];
            for (let i = 0; i < rental_obj.accessories.length; ++i) {
                if (rental_obj.accessories[i].rentalid == next_level) {
                    this.set_acc_qty(target_id, path.replace(this_level + "_", ""), qty, rental_obj.accessories[i]);
                    if (rental_obj.accessories[i].qty == 0) {
                        // If parent does not have qty we should at least set its qty to one.
                        rental_obj.accessories[i].qty = 1;
                    }
                }
            }
        } else {
            for (let i = 0; i < rental_obj.accessories.length; ++i) {
                if (rental_obj.accessories[i].rentalid == target_id) {
                    rental_obj.accessories[i].qty = qty;
                    if (rental_obj.qty == 0) {
                        // If parent does not have qty we should at least set its qty to one.
                        rental_obj.qty = 1;
                    }
                }
            }
        }
    }

    has_sub_state(rid) {
        return this.current_state.is_sub_state(rid);
    }

    get_sub_state(rid) {
        return this.current_state.get_sub_state(rid);
    }

    stack_state(state) {
        if (!this.state_stack.includes(state)) {
            this.state_stack.unshift(state);
        }
    }

    unstack_state(rid) {
        for (let i = 0; i < this.state_stack.length; ++i) {
            let state = this.state_stack[i];
            if (state.rid == rid) {
                this.state_stack.splice(i, 1);
            }
        }
    }

    load_next_state() {
        this.prev_states.push(this.current_state);
        this.current_state = this.state_stack.shift();
        return this.current_state.display;
    }

    previous() {
        this.state_stack.unshift(this.current_state);
        this.remove_current_state_sub_states();
        this.current_state = this.prev_states.pop();
        this.remove_current_state_sub_states();


        return this.current_state.display;
    }

    remove_current_state_sub_states() {
        for (let i = 0; i < this.current_state.sub_states.length; ++i) {
            let index_to_remove = this.state_stack.findIndex(function (state) {
                return state == this;
            }, this.current_state.sub_states[i]);
            if (index_to_remove >= 0) {
                this.state_stack.splice(index_to_remove, 1);
            }
            //Make sure to remove any leftover sub states under our current state from the stack.
            this.current_state.sub_states[i].sub_states.forEach(sub_state => {
                (function traverse(sub_sub_state) {
                    let index_to_remove = this.state_stack.findIndex(function (state) {
                        return state == this;
                    }, sub_sub_state);
                    if (index_to_remove >= 0) {
                        this.state_stack.splice(index_to_remove, 1);
                    }
                    if (sub_sub_state.sub_states.length > 0) {
                        sub_sub_state.sub_states.forEach(traverse.bind(this));
                    }
                }).call(this, sub_state);
            });
        }
    }

    load_main_states() {
        this.current_state = this.states[0];
        for (let i = this.states.length - 1; i > 0; --i) {
            this.stack_state(this.states[i]);
        }
    }

    add_state(state) {
        this.states.push(state);
    }

    first() {
        return this.states[0];
    }

    is_first_state() {
        return this.current_state == this.states[0];
    }

    add_sub_acc_required(path, rid, qty) {
        let full_path = path + "_" + rid;
        if (this.current_state.required_accessories[full_path]) {
            for (const [index, object] of Object.entries(this.current_state.required_accessories[full_path])) {
                let copy = JSON.parse(JSON.stringify(object));
                copy.qty = copy.qty * qty;
                simpleCart.add_confirm_screen_element(full_path, copy);
            }
        }
    }

    clear() {
        this.current_state = null;
        this.state_stack = [];
        this.states = [];
        this.prev_states = [];
        this.confirm_screen_elements = [];
        this.main_item_qty = 1;
        this.acc_obj = {}
    }

    main_required_accessories_avail() {
        return this.rental_obj.required_accessoires_are_avail();
    }

    get_current_state_index_path(states, path=[]) {
        for (let i = 0; i < states.length; i++) {
            let state = states[i];
            if (state === this.current_state) {
                return [...path, i];
            }
            if (state.sub_states?.length) {
                let result = this.get_current_state_index_path(state.sub_states, [...path, i]);
                if (result) return result;
            }
        }
        return null;
    }

    get_main_item_id(){
        return this.rental_obj.rentalid;
    }
}

class IOAccDialogState{
    constructor(rid) {
        this.rid = rid;
        this.display = "";
        this.sub_states = [];
        this.required_accessories = {};
        this.required_iterations = 0;
        //this.display_target = "#cart_acc_selected_display";
    }

    add_sub_state(sub_state) {
        this.sub_states.push(sub_state);
    }

    is_sub_state(rid){
        for(let i=0; i<this.sub_states.length; ++i){
            let sub_state = this.sub_states[i];
            if(sub_state.rid == rid) return true;
        }
        return false
    }

    get_sub_state(rid){
        for(let i=0; i<this.sub_states.length; ++i){
            let sub_state = this.sub_states[i];
            if(sub_state.rid == rid){
                return sub_state;
            }
        }
        return false;
    }

    add_required_acc(object, path) {
        if(this.required_accessories[path]){
            this.required_accessories[path].push(object);
        }else{
            this.required_accessories[path] = [];
            this.required_accessories[path].push(object);
        }
    }

    display_is_empty(){
        const parser = new DOMParser();
        const doc = parser.parseFromString(this.display, 'text/html');
        return Array.from(doc.querySelectorAll('.select_card_container')).some(div => div.textContent.trim() === '');
    }

    find_required_dropdown_states(){
        let found_states = [];
        for(let i = 0; i < this.sub_states.length; ++i){
            if(this.sub_states[i].required_iterations > 0){
                found_states.push(this.sub_states[i]);
            }
        }
        return found_states;
    }
}

(function (window, document) {
    /*global HTMLElement */

    var typeof_string			= typeof "",
        typeof_undefined		= typeof undefined,
        typeof_function			= typeof function () {},
        typeof_object			= typeof {},
        isTypeOf				= function (item, type) { return typeof item === type; },
        isString				= function (item) { return isTypeOf(item, typeof_string); },
        isUndefined				= function (item) { return isTypeOf(item, typeof_undefined); },
        isFunction				= function (item) { return isTypeOf(item, typeof_function); },

        isObject				= function (item) { return isTypeOf(item, typeof_object); },
        //Returns true if it is a DOM element
        isElement				= function (o) {
            return typeof HTMLElement === "object" ? o instanceof HTMLElement : typeof o === "object" && o.nodeType === 1 && typeof o.nodeName === "string";
        },



        generateSimpleCart = function (space) {
            // stealing this from selectivizr
            var selectorEngines = {
                    "MooTools"							: "$$",
                    "Prototype"							: "$$",
                    "jQuery"							: "*"
                },


                // local variables for internal use
                item_id					= 0,
                item_id_namespace		= "SCI-",
                sc_items				= {},
                namespace				= space || "simpleCart",
                selectorFunctions		= {},
                eventFunctions			= {},
                baseEvents				= {},

                acc_dialog_structure    = [],
                cart_acc_state          = new IoAccDialogStateMachine(),

                // local references
                localStorage			= window.localStorage,
                console					= window.console || { msgs: [], log: function (msg) { console.msgs.push(msg); } },

                // used in views
                _VALUE_		= 'value',
                _TEXT_		= 'text',
                _HTML_		= 'html',
                _CLICK_		= 'click',

                // Currencies
                currencies = {
                    "USD": { code: "USD", symbol: "&#36;", name: "US Dollar" },
                    "AUD": { code: "AUD", symbol: "&#36;", name: "Australian Dollar" },
                    "BRL": { code: "BRL", symbol: "R&#36;", name: "Brazilian Real" },
                    "CAD": { code: "CAD", symbol: "&#36;", name: "Canadian Dollar" },
                    "CZK": { code: "CZK", symbol: "&nbsp;&#75;&#269;", name: "Czech Koruna", after: true },
                    "DKK": { code: "DKK", symbol: "DKK&nbsp;", name: "Danish Krone" },
                    "EUR": { code: "EUR", symbol: "&euro;", name: "Euro" },
                    "HKD": { code: "HKD", symbol: "&#36;", name: "Hong Kong Dollar" },
                    "HUF": { code: "HUF", symbol: "&#70;&#116;", name: "Hungarian Forint" },
                    "ILS": { code: "ILS", symbol: "&#8362;", name: "Israeli New Sheqel" },
                    "JPY": { code: "JPY", symbol: "&yen;", name: "Japanese Yen", accuracy: 0 },
                    "MXN": { code: "MXN", symbol: "&#36;", name: "Mexican Peso" },
                    "NOK": { code: "NOK", symbol: "NOK&nbsp;", name: "Norwegian Krone" },
                    "NZD": { code: "NZD", symbol: "&#36;", name: "New Zealand Dollar" },
                    "PLN": { code: "PLN", symbol: "PLN&nbsp;", name: "Polish Zloty" },
                    "GBP": { code: "GBP", symbol: "&pound;", name: "Pound Sterling" },
                    "SGD": { code: "SGD", symbol: "&#36;", name: "Singapore Dollar" },
                    "SEK": { code: "SEK", symbol: "SEK&nbsp;", name: "Swedish Krona" },
                    "CHF": { code: "CHF", symbol: "CHF&nbsp;", name: "Swiss Franc" },
                    "THB": { code: "THB", symbol: "&#3647;", name: "Thai Baht" },
                    "ZAR": { code: "ZAR", symbol: "R", name: "Rand" },
                    "BTC": { code: "BTC", symbol: " BTC", name: "Bitcoin", accuracy: 4, after: true	}
                },

                // default options
                settings = {
                    checkout				: { type: "PayPal", email: "you@yours.com" },
                    currency				: "USD",
                    language				: "english-us",

                    cartStyle				: "div",
                    //This is implemented in shortcoder
                    cartColumns			: [
                        { attr: "accessories", label: false, view:'accessories' },
                        { view: "image",attr:"image", label: "Image" },
                        { attr: "name", label: "Name" },
                        { attr: "encoded", label: false },
                        { attr: "availability", label: false, view:"availability" },
                        { view: "decrement", label: false },
                        { view: "calculate_area", label:false},
                        { view: 'input', attr:'quantity', label: "Quantity" },
                        { attr: "qtyincrement", label: false },
                        { attr: "inputtype", label: false },
                        { attr: "qtytype", label: false },
                        { view: "increment", label: false },
                        { attr: "price", label: "Price", view: 'currency' },
                        { view: "remove", text: "", label: false },
                        { attr: "total", label: "SubTotal", view: 'currency' },
                        { attr: "timeslots", label: false },
                        { attr: "timeslots-orig", label: false },
                        { attr: "href", label: false }
                    ],

                    excludeFromCheckout	: ['thumb'],

                    shippingFlatRate		: 0,
                    shippingQuantityRate	: 0,
                    shippingTotalRate		: 0,
                    shippingCustom		: null,

                    taxRate				: 0,

                    taxShipping			: false,

                    data				: {}

                },


                // main simpleCart object, function call is used for setting options
                simpleCart = function (options) {
                    // shortcut for simpleCart.ready
                    if (isFunction(options)) {
                        return simpleCart.ready(options);
                    }

                    // set options
                    if (isObject(options)) {
                        return simpleCart.extend(settings, options);
                    }
                },

                // selector engine
                $engine,

                // built in cart views for item cells
                cartColumnViews;

            // function for extending objects
            simpleCart.extend = function (target, opts) {
                var next;

                if (isUndefined(opts)) {
                    opts = target;
                    target = simpleCart;
                }

                for (next in opts) {
                    if (Object.prototype.hasOwnProperty.call(opts, next)) {
                        target[next] = opts[next];
                    }
                }
                return target;
            };

            // create copy function
            simpleCart.extend({
                copy: function (n) {
                    var cp = generateSimpleCart(n);
                    cp.init();
                    return cp;
                }
            });

            // add in the core functionality
            simpleCart.extend({

                isReady: false,

                // this is where the magic happens, the add function
                add: function (values, opt_quiet) {
                    var info		= values || {},
                        newItem		= new simpleCart.Item(info),
                        addItem 	= true,
                        // optionally supress event triggers
                        quiet 		= opt_quiet === true ? opt_quiet : false,
                        oldItem;

                    // trigger before add event
                    if (!quiet) {
                        addItem = simpleCart.trigger('beforeAdd', [newItem]);
                        if (addItem === false) {
                            return false;
                        }
                    }

                    // if the new item already exists, increment the value

                    oldItem = simpleCart.has(newItem);
                    if (oldItem) {
                        //oldItem.increment(newItem.quantity());
                        newItem = oldItem;
                        // otherwise add the item
                    } else {
                        sc_items[newItem.id()] = newItem;
                    }
                    sc_items[newItem.id()] = newItem;

                    // update the cart
                    simpleCart.update();

                    if (!quiet) {
                        // trigger after add event
                        simpleCart.trigger('afterAdd', [newItem, isUndefined(oldItem)]);
                    }
                    if (!quiet && typeof window['fbq'] === "function") {
                        try {
                            //fbq('track', 'AddToCart');//fb track
                            fbq('track', 'AddToCart', {
                                content_name: newItem.get("name"),
                                content_ids: [newItem.get("rentalid")],
                                content_type: 'product',
                                value: newItem.total(),
                                currency: currency
                            });
                        }catch(e){
                            console.log(e);
                        }
                    }
                    if (!quiet && typeof window['gtag'] === "function") {
                        try {
                            gtag("event", "add_to_cart", {
                                currency: currency,
                                value: newItem.total(),
                                items: [
                                    {
                                        item_id: newItem.get("rentalid"),
                                        item_name: newItem.get("name")
                                    }
                                ]
                            });
                        }catch(e){
                            console.log(e);
                        }
                    }

                    // return a reference to the added item
                    return newItem;
                },


                // iteration function
                each: function (array, callback) {
                    var next,
                        x = 0,
                        result,
                        cb,
                        items;

                    if (isFunction(array)) {
                        cb = array;
                        items = sc_items;
                    } else if (isFunction(callback)) {
                        cb = callback;
                        items = array;
                    } else {
                        return;
                    }

                    for (next in items) {
                        if (Object.prototype.hasOwnProperty.call(items, next)) {
                            result = cb.call(simpleCart, items[next], x, next);
                            if (result === false) {
                                return;
                            }
                            x += 1;
                        }
                    }
                },

                find: function (id) {
                    var items = [];

                    // return object for id if it exists
                    if (isObject(sc_items[id])) {
                        return sc_items[id];
                    }
                    // search through items with the given criteria
                    if (isObject(id)) {
                        simpleCart.each(function (item) {
                            var match = true;
                            simpleCart.each(id, function (val, x, attr) {

                                if (isString(val)) {
                                    // less than or equal to
                                    if (val.match(/<=.*/)) {
                                        val = parseFloat(val.replace('<=', ''));
                                        if (!(item.get(attr) && parseFloat(item.get(attr)) <= val)) {
                                            match = false;
                                        }

                                        // less than
                                    } else if (val.match(/</)) {
                                        val = parseFloat(val.replace('<', ''));
                                        if (!(item.get(attr) && parseFloat(item.get(attr)) < val)) {
                                            match = false;
                                        }

                                        // greater than or equal to
                                    } else if (val.match(/>=/)) {
                                        val = parseFloat(val.replace('>=', ''));
                                        if (!(item.get(attr) && parseFloat(item.get(attr)) >= val)) {
                                            match = false;
                                        }

                                        // greater than
                                    } else if (val.match(/>/)) {
                                        val = parseFloat(val.replace('>', ''));
                                        if (!(item.get(attr) && parseFloat(item.get(attr)) > val)) {
                                            match = false;
                                        }

                                        // equal to
                                    } else if (!(item.get(attr) && item.get(attr) === val)) {
                                        match = false;
                                    }

                                    // equal to non string
                                } else if (!(item.get(attr) && item.get(attr) === val)) {
                                    match = false;
                                }

                                return match;
                            });

                            // add the item if it matches
                            if (match) {
                                items.push(item);
                            }
                        });
                        return items;
                    }

                    // if no criteria is given we return all items
                    if (isUndefined(id)) {

                        // use a new array so we don't give a reference to the
                        // cart's item array
                        simpleCart.each(function (item) {
                            items.push(item);
                        });
                        return items;
                    }

                    // return empty array as default
                    return items;
                },

                // return all items
                items: function () {
                    return this.find();
                },

                // check to see if item is in the cart already
                has: function (item) {
                    var match = false;
                    simpleCart.each(function (testItem) {
                        if (testItem.equals(item)) {
                            match = testItem;
                        }
                    });
                    return match;
                },

                // empty the cart
                empty: function () {
                    // remove each item individually so we see the remove events
                    var newItems = {};
                    simpleCart.each(function (item) {
                        // send a param of true to make sure it doesn't
                        // update after every removal
                        // keep the item if the function returns false,
                        // because we know it has been prevented
                        // from being removed
                        if (item.remove(true) === false) {
                            newItems[item.id()] = item
                        }
                    });
                    sc_items = newItems;
                    simpleCart.update();
                },


                // functions for accessing cart info
                quantity: function () {
                    var quantity = 0;
                    simpleCart.each(function (item) {
                        quantity += item.quantity();
                    });
                    return quantity;
                },

                total: function () {
                    var total = 0;
                    simpleCart.each(function (item) {
                        if(item.total() === "TBD"){
                            total = "TBD"
                            return false;
                        }
                        total += item.total();
                    });
                    return total;
                },

                grandTotal: function () {
                    return simpleCart.total() + simpleCart.tax() + simpleCart.shipping();
                },

                parse_html_and_add: function (html, quiet) {
                    var $button = simpleCart.$(html),
                        fields = {pagename: io_pagename};
                        acc_dialog = false;
                    $button.closest("." + namespace + "_ioShelfItem").descendants().each(function (x,item) {
                        var $item = simpleCart.$(item);
                        // check to see if the class matches the item_[fieldname] pattern
                        if ($item.attr("class") &&
                            $item.attr("class").match(/item_.+/) &&
                            !$item.attr('class').match(/item_add/)) {
                            // find the class name
                            simpleCart.each($item.attr('class').split(' '), function (klass) {
                                var attr,
                                    val,
                                    type;

                                // get the value or text depending on the tagName
                                if (klass.match(/item_.+/)) {
                                    attr = klass.split("_")[1];
                                    val = "";
                                    if(attr=="timeslots" || attr=="timeslots-orig"){
                                        val = $item.html();
                                    }else if(attr=="accobj"){
                                        if($item.text()){
                                            acc_dialog = true;
                                            let acc_obj = JSON.parse($item.text())
                                            var main_id = acc_obj.main_id;
                                            var acc_structure = {};
                                            acc_obj.structure = acc_structure;
                                            val = acc_obj;
                                        }
                                    }else {
                                        switch ($item.tag().toLowerCase()) {
                                            case "input":
                                            case "textarea":
                                            case "select":
                                                type = $item.attr("type");
                                                if (!type || ((type.toLowerCase() === "checkbox" || type.toLowerCase() === "radio") && $item.attr("checked")) || type.toLowerCase() === "text" || type.toLowerCase() === "number") {
                                                    val = $item.val();
                                                }
                                                break;
                                            case "img":
                                                val = $item.attr('data-src');
                                                if (!val) val = $item.attr('src');
                                                break;
                                            case "a":
                                                if(typeof fields[attr.toLowerCase()] !== 'undefined') {
                                                    break;
                                                }
                                                val = $item.attr('href')
                                                break;
                                            default:
                                                val = $item.text();
                                                break;
                                        }
                                    }

                                    if (val !== null && val !== "") {
                                        fields[attr.toLowerCase()] = fields[attr.toLowerCase()] ? fields[attr.toLowerCase()] + ", " +  val : val;
                                        if(attr=='qtyincrement') fields['quantity'] = val;
                                    }
                                }
                            });
                        }
                    });
                    if(IoData.event_time_set()){
                        if(acc_dialog) {
                            simpleCart.open_acc_dialog(fields);
                        }else{
                            fields["rental_obj"] = new IO_Rental(fields['rentalid'], fields['name'], fields['quantity']);
                            if(fields["rentalid"].includes(":")){
                                fields["rental_obj"] = add_included_accessories(fields["rental_obj"], fields['rentalid'], fields["name"]);
                            }
                            simpleCart.add(fields, quiet);
                        }
                    }else{
                        // No date set - open cart with calendar
                        checkAvailDateClick();
                    }

                },

                open_acc_dialog: async function (fields){
                    jQuery("#cart_acc_top_name").html(fields['name']);
                    jQuery(".cart_acc_main_qty").find("*").attr('data-rid', fields['rentalid']);
                    jQuery(".cart_acc_main_qty .cart_acc_quantity_input").attr('data-increment', fields['qtyincrement']);
                    jQuery(".cart_acc_main_qty .cart_acc_quantity_input").attr('min', fields['qtyincrement']);
                    jQuery(".cart_acc_main_qty .cart_acc_quantity_input").val(fields['qtyincrement']);
                    jQuery("#cart_fields").text(JSON.stringify(fields));
                    acc_obj = fields["accobj"];
                    cart_acc_state.acc_obj =  fields["accobj"];
                    await cart_acc_state.build_rental_obj(acc_obj);
                    let main_input = jQuery(".cart_acc_main_qty input");
                    main_input.attr('data-availability', cart_acc_state.rental_obj.availability)
                    main_input.attr('data-old', main_input.val());
                    let main_available = parseInt(main_input.attr('data-availability'));
                    let main_increment = parseInt(main_input.attr('data-increment'));
                    let main_selected = parseInt(main_input.val());
                    if(main_selected + main_increment > main_available){
                        jQuery(".cart_acc_main_qty .simpleCart_increment_acc").prop("disabled", true);
                    }
                    if(main_selected - main_increment <= 0){
                        jQuery(".cart_acc_main_qty .simpleCart_decrement_acc").prop("disabled", true);
                    }
                    if(cart_acc_state.main_required_accessories_avail()) {
                        simpleCart.build_acc_dialog_html(acc_obj);
                        first_state = cart_acc_state.first();
                        if(cart_acc_state.states.length > 1){
                            jQuery(".simpleCart_progress").show()
                        }
                        if (!first_state) {
                            // All accessories are required with no user choices needed; skip dialog and add directly.
                            let main_qty = parseInt(jQuery(".cart_acc_main_qty input").val()) || 1;
                            cart_acc_state.confirm_screen_elements[0].qty = main_qty;
                            // Multiply required accessory quantities by main qty when linkqty is enabled
                            let acc_data = acc_obj.accessories || {};
                            let confirm_accs = cart_acc_state.confirm_screen_elements[0].accessories || [];
                            for (let i = 0; i < confirm_accs.length; i++) {
                                let acc_info = acc_data[confirm_accs[i].rid];
                                if (acc_info && parseInt(acc_info.linkqty) === 1) {
                                    confirm_accs[i].qty = parseInt(confirm_accs[i].qty) * main_qty;
                                }
                            }
                            simpleCart.set_rental_obj_qty();
                            simpleCart.remove_zero_qty_accs(cart_acc_state.rental_obj);
                            fields.rental_obj = cart_acc_state.rental_obj;
                            fields.confirm_screen_elements = cart_acc_state.confirm_screen_elements;
                            simpleCart.add(fields);
                            cart_acc_state.clear();
                            return;
                        }
                        bottom_html = first_state.display;

                        setTimeout(function () {
                            jQuery("[data='" + acc_dialog_structure[0] + "']").parent().show();
                            jQuery("[data='" + acc_dialog_structure[0] + "']").show();
                        }, 200);
                        if (cart_acc_state.states.length == 1) {
                            jQuery(".simpleCart_add_acc_dialog").show();
                        } else {
                            jQuery(".simpleCart_next_acc_dialog").show();
                        }
                        jQuery("#cart_acc_select_bottom").html(bottom_html).removeAttr("data-editing");
                        jQuery(".simpleCart_add_acc_dialog").html('<i class="fas fa-cart-plus"></i>');
                        let container = jQuery(".select_card_container")
                        let required = container.attr("data-required");
                        let limit = container.attr("data-limit");
                        let linkqty = container.attr("data-linkqty");
                        //simpleCart.check_total_selected(limit, required);
                        if (required > 0) {
                            jQuery(".simpleCart_next_acc_dialog").addClass("disabled_next");
                            jQuery(".simpleCart_finish_acc_dialog").addClass("disabled_finish");
                            jQuery(".simpleCart_add_acc_dialog").addClass("disabled_add");
                            jQuery("#progress_message_add_more").show();
                            jQuery(".progress_message_qty").text(Math.max(required, limit*required) * cart_acc_state.main_item_qty);
                        }
                        if(linkqty){
                            let main_input = jQuery(".cart_acc_main_qty input");
                            if(container.attr("data-linkqty") == 1){
                                container.attr("data-parentqty", main_input.val());
                                jQuery(".select_card_container .simpleCart_select_card[data-linkqty='1']").each(function(){
                                    this.setAttribute("data-parentqty", main_input.val());
                                    if(this.classList.contains("selected")){
                                        const card_input = jQuery(this).find("input");
                                        card_input.val(parseInt(main_input.val() * parseInt(this.dataset.increment)));
                                    }
                                });
                            }
                        }
                        let top_div = jQuery("#cart_acc_dialog_top");
                        let text_class = getContrastClass(top_div.css("background-color"));
                        jQuery("#cart_acc_top_name,.simpleCart_cancel_acc_dialog").addClass(text_class);
                        jQuery.fancybox.open(jQuery("#cart_acc_select_dialog"), {
                            afterClose: function () {
                                cart_acc_state.clear();
                                //jQuery("#cart_acc_selected_display").empty();
                                //jQuery("#cart_acc_required_main").empty();
                                jQuery("#cart_acc_controls .io_button:not(.simpleCart_cancel_acc_dialog)").hide();
                                jQuery(".simpleCart_next_acc_dialog").removeClass("disabled_next");
                                jQuery(".simpleCart_finish_acc_dialog").removeClass("disabled_finish");
                                jQuery(".simpleCart_add_acc_dialog").removeClass("disabled_add").html('<i class="fas fa-cart-plus"></i>');
                                jQuery(".cart_acc_main_qty").show();
                                jQuery("#progress_message_all_added").hide();
                                jQuery("#progress_message_add_more").hide();
                                jQuery("#dialog_cart_id").empty();
                            },
                            closeBtn: false,
                            autoSize:false,
                            padding: 0,
                            height:800,
                            width:900,
                            helpers: {
                                overlay: {closeClick: false} // prevents closing when clicking OUTSIDE fancybox
                            }
                        });
                        simpleCart.update_progress();
                        let main_input = jQuery(".cart_acc_main_qty input");
                        simpleCart.check_main_input(main_input);
                        simpleCart.can_add_more();
                        simpleCart.update_parentqty_for_linkqty_choices();
                    }else{
                        // Do not open dialog. instead make sure item is shown unavailable.
                        jQuery(".add_cart_" + acc_obj.main_id.replace(":", "\\\:") + " .item_add").removeClass("item_add").addClass("item_add_off").trigger("classChange");
                        jQuery(".unavailable_message_" + acc_obj.main_id.replace(":", "\\\:")).show();
                    }
                },

                add_acc_to_selected: function (acc_id, path, qty = 1){
                    // First id of the path is main item. Always there. Check to see if the end of the path exits.
                    // If it does add the accessory to it. Else we need to add the end of the path first then add the acc_id.
                    let split_path = path.split("_");
                    let parent = split_path.pop();
                    let parent_path = split_path.join("_");
                    let index_path = cart_acc_state.get_current_state_index_path(cart_acc_state.states).join("_");
                    let parent_confirm_screen_element = simpleCart.find_confirm_screen_element(parent_path, parent)
                    if(parent_confirm_screen_element || !parent_path){
                        if(parent_confirm_screen_element?.index_path && parent_confirm_screen_element?.index_path == index_path){
                            simpleCart.add_confirm_screen_element(path, {rid:acc_id, qty:qty, accessories:[]});
                        }else{
                            simpleCart.add_confirm_screen_element(path, {rid:acc_id, qty:qty, accessories:[], index_path:index_path});
                        }

                    }else{
                        simpleCart.add_confirm_screen_element(parent_path, {rid:parent, qty:qty, accessories:[], index_path:index_path});
                        simpleCart.add_confirm_screen_element(path, {rid:acc_id, qty:qty, accessories:[]});
                    }
                },

                remove_acc_from_selected: function (path, main_target=null){
                    if(main_target){
                        let element = cart_acc_state.confirm_screen_elements[0];
                        const index = element.accessories.findIndex(e => e.rid === main_target);
                        if(index !== -1){
                            element.accessories.splice(index, 1);
                            return true;
                        }
                        return false;
                    }else{
                        let split_path = path.split('_');
                        let target = split_path.pop();

                        let element = cart_acc_state.confirm_screen_elements;
                        for (const rid of split_path){
                            const found = element.find(e => e.rid === rid);
                            if(!found){
                                console.log("Failed to remove any selected elements. Element not found")
                                return false;
                            }
                            element = found.accessories;
                        }

                        const index = element.findIndex(e => e.rid === target);
                        if(index !== -1){
                            element.splice(index, 1);
                            return true;
                        }
                        console.log("Failed to remove any selected elements. Index not found")
                        return false;
                    }
                },

                add_main_required_accessory(acc_id, path, qty = 1){
                    //In this case path is always the main item. So just add it to its accessories here.
                    simpleCart.add_confirm_screen_element(path, {rid:acc_id, qty:qty, accessories:[]});
                },

                find_confirm_screen_element: function (path, target){
                    // If path is empty, return the main item
                    if(path === "") return cart_acc_state.confirm_screen_elements[0];

                    const split_path = path.split('_');
                    let element = cart_acc_state.confirm_screen_elements;

                    for(const rid of split_path){
                        const found = element.find(e => e.rid === rid);
                        if(!found) return null;
                        element = found.accessories;
                    }

                    return element.find(e => e.rid === target) || null;
                },

                add_confirm_screen_element: function (path, element_to_add, editable=false){
                    const split_path = path.split('_');
                    let element = cart_acc_state.confirm_screen_elements;

                    for(const rid of split_path){
                        const found = element.find(e => e.rid === rid);
                        if(!found) return null;
                        element = found.accessories;
                    }

                    return element.push(element_to_add);
                },

                build_acc_dialog_html: function (acc_obj) {
                    simpleCart.build_acc_state(acc_obj, acc_obj.accessory_images);
                    cart_acc_state.load_main_states();
                },

                build_acc_dialog_confirm_screen(acc_obj){
                    jQuery(".simpleCart_back_acc_dialog").hide();
                    jQuery(".simpleCart_progress").hide();
                    jQuery(".simpleCart_finish_acc_dialog").hide();
                    jQuery(".simpleCart_add_acc_dialog").show();
                    cart_acc_state.prev_states = [];
                    let selected_elements  = cart_acc_state.confirm_screen_elements[0];
                    let confirm_screen_html_sections = {main_required:[],
                        main_level_selection_items:[],
                        main_level_normal_accessories:[],
                        main_level_selection_indices:[]
                    };
                    if(selected_elements.accessories.length){
                        simpleCart.iterate_confirm_screen_selections(selected_elements.accessories, acc_obj, confirm_screen_html_sections);
                    }else{
                        // No need to confirm as there were no selections. Just add the item.
                        return false;
                    }
                    let confirm_screen_html = '<div id="io_acc_dialog_confirm_screen">'
                    if(confirm_screen_html_sections.main_required.length){
                        confirm_screen_html += '<br><div class="confirm_screen_included_container">';
                        confirm_screen_html += '<div class="io_cs_editable_group"><div class="io_cs_required_section">';
                        for(const required_accessory of confirm_screen_html_sections.main_required){
                            confirm_screen_html += required_accessory;
                        }
                        confirm_screen_html += "</div></div>";
                        confirm_screen_html += "</div>";
                    }
                    if(confirm_screen_html_sections.main_level_selection_items.length){
                        for(const selected_accessory of confirm_screen_html_sections.main_level_selection_items){
                            confirm_screen_html += selected_accessory;
                        }
                    }
                    if(confirm_screen_html_sections.main_level_normal_accessories.length){
                        confirm_screen_html += '<br><div class="io_cs_editable_group"><div class="edit_button_header">';
                        let selected_main_accessories_indices = confirm_screen_html_sections.main_level_selection_indices.join("_");
                        confirm_screen_html += '<i class="simpleCart_confirm_screen_edit fa fa-pencil-square-o" data-state="'+(cart_acc_state.states.length-1)+'" data-selection="0" data-main-accessories="'+selected_main_accessories_indices+'"></i>&nbsp';
                        confirm_screen_html += '</div>';
                        confirm_screen_html += '<div class="io_cs_section io_cs_editable">';
                        for(const selected_accessory of confirm_screen_html_sections.main_level_normal_accessories){
                            confirm_screen_html += selected_accessory;
                        }
                        confirm_screen_html += '</div></div>';
                    }else {
                        const hasMainLevelNormal = Object.values(acc_obj.accessories).some(a => {
                            try {
                                return Number(a.dropdown) === 0 && Number(a.required) === 0;
                            } catch (e) {
                                return false;
                            }
                        });
                        if (hasMainLevelNormal) {
                            confirm_screen_html += '<br><div class="io_cs_editable_group">';
                            confirm_screen_html += '  <div class="edit_button_header">';
                            // Use data-main-accessories="-1" to indicate "navigate to default main-level normal state"
                            confirm_screen_html += '  </div>';
                            confirm_screen_html += '  <div class="cs_add_missing_accs">'
                            confirm_screen_html += '    <i class="simpleCart_confirm_screen_edit fa fa-plus-square" data-state="' + (cart_acc_state.states.length - 1) + '" data-selection="none" data-main-accessories="none"></i>&nbsp';
                            confirm_screen_html += '    <span class="io_cs_add_more_text">Add accessories</span>';
                            confirm_screen_html += '   </div>';
                            confirm_screen_html += '</div>';
                        }
                    }
                    confirm_screen_html += "</div></br>"
                    return confirm_screen_html
                },

                iterate_confirm_screen_selections(selected_elements, acc_data, html_sections){
                    for(const [index, rental] of selected_elements.entries()){
                        const {rid, qty, accessories} = rental
                        if(acc_data?.accessories){
                            const current_acc_data = acc_data.accessories[rid];
                            if(current_acc_data.dropdown == 0 && current_acc_data.required > 0){
                                group_html = simpleCart.build_confirm_screen_html_row(current_acc_data, rental,[0,index], "");
                                html_sections.main_required.push(group_html);
                            }else if(current_acc_data.dropdown > 0){
                                const isChoice = /\b(choose|choice|select|pick|option)\b/i.test(current_acc_data.name || "");
                                if(isChoice){
                                    // Keep the container wrappers and edit icon so users can edit, but do not render a container row/title.
                                    let group_html = '<br><div class="io_cs_editable_group"><div class="edit_button_header">';
                                    if (rental?.index_path) {
                                        group_html += '<i class="simpleCart_confirm_screen_edit fa fa-pencil-square-o" data-state="' + rental.index_path + '" data-selection="0_' + index + '" data-edit-mode="clear"></i>&nbsp';
                                    }
                                    group_html += '</div>';
                                    if (accessories.length) {
                                        group_html += '<div class="io_cs_section io_cs_editable">';
                                        group_html = simpleCart.iterate_confirmed_selection_sub_accessories(
                                            current_acc_data,
                                            accessories,
                                            [0, index],
                                            group_html,
                                            1,
                                            rental?.index_path || null,
                                            false
                                        );
                                        group_html += "<hr></div>";
                                    }
                                    group_html += '</div>';
                                    html_sections.main_level_selection_items.push(group_html);
                                }else{
                                    // Non-choice dropdowns: render the container with edit icon and its children inside
                                    let group_html = '<br><div class="io_cs_editable_group"><div class="edit_button_header">';
                                    if (rental?.index_path) {
                                        group_html += '<i class="simpleCart_confirm_screen_edit fa fa-pencil-square-o" data-state="' + rental.index_path + '" data-selection="0_' + index + '"></i>&nbsp';
                                    }
                                    group_html += '</div>';
                                    if (accessories.length) {
                                        group_html += '<div class="io_cs_section io_cs_editable">';
                                        group_html = simpleCart.iterate_confirmed_selection_sub_accessories(current_acc_data, accessories, [0, index], group_html);
                                        group_html += "<hr></div>";
                                    }
                                    group_html += '</div>';
                                    html_sections.main_level_selection_items.push(group_html);
                                }
                            }else if(current_acc_data.dropdown == 0 ){
                                html_sections.main_level_selection_indices.push(index);
                                delete rental.index_path;
                                let row = simpleCart.build_confirm_screen_html_row(current_acc_data, rental,[0,index], "");
                                html_sections.main_level_normal_accessories.push(row);
                            }
                        }else{
                        }
                    }
                },

                iterate_confirmed_selection_sub_accessories(acc_data, selections, path, group_html, layer=1, edit_override=null, show_child_edit=true){
                    for(const [index, selection] of selections.entries()){
                        let selected_data = acc_data.accessories[selection.rid];
                        group_html = simpleCart.build_confirm_screen_html_row(selected_data, selection, [...path, index], group_html, layer, "editable", edit_override, show_child_edit);
                    }
                    return group_html;
                },

                build_confirm_screen_html_row(acc_data, selection, path, group_html, layer=1, type="editable", edit_override=null, show_edit=true) {
                    const {rid, qty, accessories} = selection;
                    if ((acc_data?.dropdown > 0) && /\b(choose|choice|select|pick|option)\b/i.test(acc_data?.name || "")) {
                        let html = group_html;
                        if (accessories.length) {
                            const pass_edit = selection.index_path || edit_override || null;
                            html = simpleCart.iterate_confirmed_selection_sub_accessories(acc_data, accessories, path, html, layer, pass_edit, true);
                        }
                        return html;
                    }

                    let layer_style = "";
                    if (layer > 1) {
                        layer_style = 'style="padding-left: ' + layer + '%"';
                    }
                    let html = '<div class="io_cs_content_row row_layer_' + layer + '" ' + layer_style + '>';
                    /* if(image){
                            html += '<img class="io_cs_section_image" src="https://jumpinjamboree.com/wp-content/uploads/2024/02/Why-Jumping-Bounce-House-Events-Are-The-Perfect-Party-Experience-for-Kids-Image-2-600x600.jpg""/>';
                        }
                     */
                    let editable = show_edit ? (selection.index_path || edit_override) : null;
                    html += '<div style="display:flex"> <p class="io_cs_editable_title">' + acc_data.name + '</p>';
                    if (editable) {
                        html += '<i class="simpleCart_confirm_screen_edit fa fa-pencil-square-o" style="margin-left: 10px;" data-state="' + editable + '" data-selection="' + path.join("_") + '" data-edit-mode="clear-parent"></i>&nbsp'
                    }
                    html += '</div>';
                    html += '<div class="io_cs_qty">'+qty+'</div>';
                    html += '</div>';
                    if (accessories.length) {
                        html = simpleCart.iterate_confirmed_selection_sub_accessories(acc_data, accessories, path, html, layer + 1)
                    }
                    group_html += html;
                    return group_html;
                },

                handle_confirm_screen_sub_selections(sub_acc_data, sub_selections, selection_index, sub_accessories_storage){
                    sub_accessories_storage.push({data:sub_acc_data, selection:sub_selections, selection_index:selection_index});
                },

                /**
                 * Helper: Build HTML for a single accessory card
                 */
                build_accessory_card_html: function(acc_id, accessory, path, acc_images, avail) {
                    let card_html = '<div class="dialog_acc_selectable_card simpleCart_select_card" data-availability="'+avail+'" data-linkqty="'+accessory.linkqty+'" data-required="' + accessory.required + '" data-increment="' + accessory.increment + '" data-dropdown="' + accessory.dropdown + '" data-path="' + path + '" data="' + acc_id + '">';
                    card_html += '<i class="fa fa-check selected_check"></i>';
                    let acc_img = "";
                    if (acc_images[acc_id]) {
                        acc_img = 'style="background-image: url('+acc_images[acc_id]+')"';
                    }
                    card_html += '<div class="acc_dialog_container" '+acc_img+'></div>';
                    card_html += '<div class="acc_name">' + accessory.name + '</div>';
                    card_html += `<div class="cart_acc_quantity">
                                    <button disabled class="cart_acc_quantity_control simpleCart_decrement_acc" data-rid="`+acc_id+`" style="float: left;">&#8722;</button>
                                    <input ${(parseInt(accessory.linkqty) > 0 ? "readonly" : "")} disabled type="number" data-rid="`+acc_id+`" data-increment="`+accessory.increment+`" min="`+accessory.increment+`" value="0" class="cart_acc_quantity_input simpleCart_input_acc"/>
                                    <button class="cart_acc_quantity_control simpleCart_increment_acc" data-rid="`+acc_id+`" style="float: right;">&#43;</button>
                                </div></div>`;
                    return card_html;
                },

                /**
                 * Helper: Check if an accessory is available, considering required child accessories
                 */
                check_accessory_availability: function(acc_id, accessory) {
                    let avail = cart_acc_state.rental_obj.get_acc_property(acc_id, "availability");
                    
                    // Check child accessories if they exist
                    if (accessory.accessories) {
                        for (const [child_id, child_accessory] of Object.entries(accessory.accessories)) {
                            let child_avail = cart_acc_state.rental_obj.get_acc_property(child_id, "availability");
                            if (child_avail < 0 && child_accessory.required > 0) {
                                avail = child_avail;
                                break;
                            }
                        }
                    }
                    
                    return avail;
                },

                /**
                 * Helper: Build display HTML for accessories (works for both dropdown and normal types)
                 */
                build_accessory_display_html: function(parent, path, acc_images) {
                    let display_html = "<h3>"+parent.name.replace(/(\s)(\d)(?=\s)/g, '$1<span class="progress_message_qty">$2</span>')+"</h3>";
                    display_html += '<div class="select_card_container"';
                    display_html += ' data-required="'+(parent.required || 0)+'"';
                    display_html += ' data-limit="'+(parent.limit || '')+'"';
                    display_html += ' data-increment="'+(parent.increment || '')+'"';
                    display_html += ' data-linkqty="'+(parent.linkqty || '')+'"';
                    display_html += ' data-path="'+path+'"';
                    display_html += ' data="'+parent.id+'"';
                    display_html += '>';
                    
                    let cards_html = "";
                    for (const [acc_id, accessory] of Object.entries(parent.accessories)) {
                        let avail = simpleCart.check_accessory_availability(acc_id, accessory);
                        if ((avail >= 0 || avail == "TBD") && accessory.required == 0) {
                            let card_path = path+"_"+parent.id;
                            cards_html += simpleCart.build_accessory_card_html(acc_id, accessory, card_path, acc_images, avail);
                        }
                    }
                    
                    display_html += cards_html + "</div>";
                    return display_html;
                },

                /**
                 * Helper: Recursively process child accessories and build sub-states
                 */
                process_child_accessories: function(parent_accessory, parent_path, acc_images, parent_state) {
                    if (!parent_accessory.accessories) {
                        return;
                    }

                    for (const [child_id, child_accessory] of Object.entries(parent_accessory.accessories)) {
                        if (!child_accessory.accessories) {
                            continue;
                        }

                        let child_avail = cart_acc_state.rental_obj.get_acc_property(child_id, "availability");
                        if (child_avail < 0 && child_avail != "TBD") {
                            continue;
                        }

                        let child_state = simpleCart.build_accessory_state_recursive(child_accessory, parent_path, acc_images);
                        if (child_state) {
                            parent_state.add_sub_state(child_state);
                        }

                        simpleCart.collect_required_accessories(child_accessory, parent_path + "_" + child_id, parent_state);
                    }
                },

                /**
                 * Helper: Collect required accessories recursively
                 */
                collect_required_accessories: function(parent_accessory, parent_path, target_state) {
                    if (!parent_accessory.accessories) {
                        return;
                    }

                    for (const [child_id, child_accessory] of Object.entries(parent_accessory.accessories)) {
                        if (child_accessory.required > 0 && !child_accessory.dropdown) {
                            target_state.add_required_acc(
                                {rid: child_id, qty: child_accessory.required, accessories:[]}, 
                                parent_path
                            );
                        }
                        
                        // Recurse to deeper levels
                        if (child_accessory.accessories) {
                            simpleCart.collect_required_accessories(child_accessory, parent_path + "_" + child_id, target_state);
                        }
                    }
                },

                /**
                 * Recursive function: Build state for any accessory at any level
                 */
                build_accessory_state_recursive: function(accessory, parent_path, acc_images) {
                    let acc_id = accessory.id;
                    let avail = cart_acc_state.rental_obj.get_acc_property(acc_id, "availability");
                    
                    if (avail < 0 && avail != "TBD") {
                        return null;
                    }

                    let state = new IOAccDialogState(acc_id);
                    let path = parent_path + "_" + acc_id;

                    // Build display HTML
                    state.display = simpleCart.build_accessory_display_html(accessory, parent_path, acc_images);

                    if (accessory.required > 0) {
                        state.required_iterations = parseInt(accessory.required);
                    }

                    simpleCart.process_child_accessories(accessory, path, acc_images, state);

                    return state;
                },

                /**
                 * Main function: Build the complete accessory state tree
                 */
                build_acc_state: function(parent, acc_images){
                    cart_acc_state.confirm_screen_elements.push({rid:parent.main_id, qty:1, accessories:[]});
                    
                    let main_id = parent.main_id;
                    let main_level_states = [];
                    let optional_state = new IOAccDialogState(main_id);
                    let optional_cards_html = "";

                    // Process each main-level accessory
                    for (const [acc_id, accessory] of Object.entries(parent.accessories)){
                        let acc_avail = cart_acc_state.rental_obj.get_acc_property(acc_id, "availability");
                        if (acc_avail < 0 && acc_avail != "TBD") {
                            continue;
                        }
                        if (accessory.accessories) {
                            // Required accessories with children get their own state
                            if (accessory.required > 0) {
                                if(accessory.dropdown == 1){
                                    let acc_state = new IOAccDialogState(acc_id);
                                    acc_state.display = simpleCart.build_accessory_display_html(accessory, main_id, acc_images, accessory.dropdown == 1);

                                    if (!acc_state.display_is_empty()) {
                                        acc_state.required_iterations = parseInt(accessory.required);
                                        simpleCart.process_child_accessories(accessory, main_id+"_"+accessory.id, acc_images, acc_state);
                                        main_level_states.push(acc_state);
                                    }
                                }else {
                                    simpleCart.add_main_required_accessory(acc_id, main_id, accessory.required);
                                    // Parent is required but dropdown=0, check what children it has
                                    let has_displayable_content = false;
                                    let required_dropdown_children = [];

                                    for (const [sub_acc_id, sub_accessory] of Object.entries(accessory.accessories)) {
                                        let sub_avail = cart_acc_state.rental_obj.get_acc_property(sub_acc_id, "availability");
                                        if (sub_avail < 0 && sub_avail != "TBD") {
                                            continue;
                                        }

                                        if (sub_accessory.required == 0) {
                                            has_displayable_content = true;
                                        }

                                        if (sub_accessory.required > 0 && sub_accessory.dropdown == 1 && sub_accessory.accessories) {
                                            required_dropdown_children.push({id: sub_acc_id, data: sub_accessory});
                                        }
                                    }
                                    if (has_displayable_content) {
                                        // Make sure we add any required dropdown sub accessories here.
                                        for (let i = 0; i < required_dropdown_children.length; i++) {
                                            let child = required_dropdown_children[i];
                                            let child_state = new IOAccDialogState(child.id);
                                            let child_path = main_id + "_" + acc_id;
                                            child_state.display = simpleCart.build_accessory_display_html(child.data, child_path, acc_images);

                                            if (!child_state.display_is_empty()) {
                                                child_state.required_iterations = parseInt(child.data.required);
                                                simpleCart.process_child_accessories(child.data, child_path+"_"+child.id, acc_images, child_state);
                                                main_level_states.push(child_state);
                                            }
                                        }
                                        // Build select screen for the options of a required accessory
                                        // NOTE: These options will not be required and should be skippable.
                                        // Since the buttons key off the required amount for the select_card_container,
                                        // make the accessory non-required when building display html.
                                        let acc_state = new IOAccDialogState(acc_id);
                                        let required_amt = accessory.required
                                        accessory.required = 0;
                                        acc_state.display = simpleCart.build_accessory_display_html(accessory, main_id, acc_images);
                                        accessory.required = required_amt;

                                        if (!acc_state.display_is_empty()) {
                                            acc_state.required_iterations = parseInt(accessory.required);
                                            simpleCart.process_child_accessories(accessory, main_id+"_"+accessory.id, acc_images, acc_state);
                                            main_level_states.push(acc_state);
                                        }
                                    } else if (required_dropdown_children.length > 0) {
                                        for (let i = 0; i < required_dropdown_children.length; i++) {
                                            let child = required_dropdown_children[i];
                                            let child_state = new IOAccDialogState(child.id);
                                            let child_path = main_id + "_" + acc_id;
                                            child_state.display = simpleCart.build_accessory_display_html(child.data, child_path, acc_images);

                                            if (!child_state.display_is_empty()) {
                                                child_state.required_iterations = parseInt(child.data.required);
                                                simpleCart.process_child_accessories(child.data, child_path+"_"+child.id, acc_images, child_state);
                                                main_level_states.push(child_state);
                                            }
                                        }

                                        // Still need to track the parent's required non-dropdown accessories
                                        simpleCart.collect_required_accessories(accessory, main_id + "_" + acc_id, cart_acc_state);
                                    } else {
                                        // Parent has no displayable content and no required dropdown children
                                        // Just collect its required accessories
                                        simpleCart.collect_required_accessories(accessory, main_id + "_" + acc_id, cart_acc_state);
                                    }
                                }
                            } else {
                                // Optional accessories with children
                                let avail = simpleCart.check_accessory_availability(acc_id, accessory);
                                optional_cards_html += simpleCart.build_accessory_card_html(acc_id, accessory, main_id, acc_images, avail);
                                if(accessory.accessories){
                                    const accessory_state_html = simpleCart.build_accessory_display_html(accessory, main_id, acc_images);
                                    let accessory_state = new IOAccDialogState(acc_id);
                                    accessory_state.display = accessory_state_html;
                                    simpleCart.process_child_accessories(accessory, main_id, acc_images, accessory_state);
                                    optional_state.add_sub_state(accessory_state);
                                }
                            }
                        } else {
                            if (accessory.required == 0) {
                                let avail = simpleCart.check_accessory_availability(acc_id, accessory);
                                optional_cards_html += simpleCart.build_accessory_card_html(acc_id, accessory, main_id, acc_images, avail);
                            } else if (accessory.required > 0) {
                                simpleCart.add_main_required_accessory(acc_id, main_id, accessory.required);
                            }
                        }
                    }

                    // Add all required states
                    for (let i = 0; i < main_level_states.length; ++i) {
                        cart_acc_state.add_state(main_level_states[i]);
                    }

                    // Add optional accessories state if there are any
                    if (optional_cards_html) {
                        let display_html = "<h3>"+parent.name.replace(/(\s)(\d)(?=\s)/g, '$1<span class="progress_message_qty">$2</span>')+" options:</h3>";
                        display_html += "<div class='select_card_container' data-limit='"+parent.limit+"' data-increment='"+parent.increment+"' data-linkqty='"+parent.linkqty+"' data-required='0' data-path='"+main_id+"' data='"+parent.main_id+"'>" + optional_cards_html + "</div>";
                        optional_state.display = display_html;
                        cart_acc_state.add_state(optional_state);
                    }
                },


                can_add_more: function(){
                    const selected = simpleCart.get_total_selected();
                    const allowed = simpleCart.get_total_allowed();
                    if(allowed === "Unlimited"){
                        jQuery(".select_card_container").find(".simpleCart_increment_acc").prop("disabled", false);
                    }
                    else {
                        const total_allowed = allowed - selected;
                        jQuery(".dialog_acc_selectable_card.selected").each(function () {
                            simpleCart.check_accessory_increment(this, total_allowed);
                            simpleCart.check_accessory_decrement(this);
                        });
                        jQuery(".dialog_acc_selectable_card:not(.selected)").each(function () {
                            simpleCart.check_select_card(this, total_allowed);
                        });
                    }
                },

                check_accessory_increment: function(card, total_allowed){
                    // If parentqty is set, then this is linkqty == 1.
                    // Need to make sure that we have enough for the amount needed by the parent.
                    if(card.dataset.parentqty){
                        /*
                        const parent_qty = parseInt(card.dataset.parentqty);
                        const avail = parseInt(card.dataset.availability);
                        if(total_allowed <= 0 || parent_qty > avail){
                            jQuery(card).find(".simpleCart_increment_acc").prop("disabled", false);
                        }else{
                            jQuery(card).find(".simpleCart_increment_acc").prop("disabled", true);
                        }
                        */
                        jQuery(card).find(".simpleCart_increment_acc").prop("disabled", true);
                    }else{
                        if(total_allowed <= 0){
                            jQuery(card).find(".simpleCart_increment_acc").prop("disabled", true);
                        }else{
                            jQuery(card).find(".simpleCart_increment_acc").prop("disabled", false);
                        }
                    }

                },

                check_accessory_decrement: function(card){
                    // If parentqty is set, then this is linkqty == 1.
                    const input_value = jQuery(card).find("input").val();
                    if(card.dataset.parentqty){
                        jQuery(card).find("input,.simpleCart_decrement_acc").prop("disabled", true)
                    }else{
                        if(input_value > 0){
                            jQuery(card).find("input,.simpleCart_decrement_acc").prop("disabled", false)
                        }else{
                            jQuery(card).find("input,.simpleCart_decrement_acc").prop("disabled", true)
                        }
                    }

                },

                check_select_card: function(card, total_allowed){
                    // If parentqty is set, then this is linkqty == 1.
                    // Need to make sure that we have enough for the amount needed by the parent.
                    if(card.dataset.parentqty){
                        const parent_qty = parseInt(card.dataset.parentqty);
                        const avail = parseInt(card.dataset.availability);
                        if(total_allowed <= 0|| parent_qty > avail){
                            jQuery(card).addClass("disabled_select_card");
                        }else{
                            jQuery(card).removeClass("disabled_select_card");
                        }
                    }else{
                        if(total_allowed <= 0){
                            jQuery(card).addClass("disabled_select_card");
                        }else{
                            jQuery(card).removeClass("disabled_select_card");
                        }
                    }
                },

                check_main_input: function(main_input){
                    //TODO Check ahead for lowest avail required accessory and use that as available amount.
                    let main_available = parseInt(main_input.attr('data-availability'));
                    let main_increment = parseInt(main_input.attr('data-increment'));
                    let main_selected = parseInt(main_input.val());
                    let cards_selected = jQuery(".simpleCart_select_card.selected").length;
                    if(main_selected + main_increment > main_available || cards_selected > 0){
                        jQuery(".cart_acc_main_qty .simpleCart_increment_acc").prop("disabled", true);
                    }else{
                        jQuery(".cart_acc_main_qty .simpleCart_increment_acc").prop("disabled", false);
                    }
                    if(main_selected - main_increment <= 0 || cards_selected > 0){
                        jQuery(".cart_acc_main_qty .simpleCart_decrement_acc").prop("disabled", true);
                    }else{
                        jQuery(".cart_acc_main_qty .simpleCart_decrement_acc").prop("disabled", false);
                    }
                },

                get_confirm_screen_qty: function(parent_qty, target_id){
                    /*
                    x = required > 0 ? required : increment;
                    y = link_qty == 1  || required > 0 ? x*parentqty : x;
                     */
                    const acc_obj = cart_acc_state.acc_obj.accessories[target_id];
                    const required = parseInt(acc_obj.required);
                    const increment = parseInt(acc_obj.increment)
                    const linkqty = parseInt(acc_obj.linkqty);
                    const base_qty = required > 0 ? parseInt(acc_obj.required) : increment;
                    return linkqty == 1 || required > 0 ? base_qty*parent_qty : base_qty;

                },

                update_main_required_qty: function(input){
                    const value =  input.val();
                    for(const element of cart_acc_state.confirm_screen_elements[0].accessories){
                        element.qty = simpleCart.get_confirm_screen_qty(value, element.rid);
                    }
                },

                get_total_selected: function(){
                    let total_selected = 0;
                    jQuery(".select_card_container").find(".selected").each(function(){
                        let value = parseInt(jQuery(this).find("input").val());
                        if(!value){
                            value = parseInt(this.dataset.increment);
                        }
                        total_selected += value / parseInt(this.dataset.increment);
                    });
                    return total_selected;
                },

                get_total_allowed: function(){
                    const container = jQuery(".select_card_container");
                    const link_qty = parseInt(container.attr("data-linkqty"));
                    const limit = parseInt(container.attr("data-limit"));
                    const required = parseInt(container.attr("data-required"));
                    /*
                    x = required > 0 ? required : increment;
                    y = link_qty == 1  || required > 0 ? x*parentqty : x;
                     */

                    if(limit == 0 && required == 0){
                        return "Unlimited";
                    }

                    let parent_qty_multiplier = link_qty == 0 ? 1 : parseInt(container.attr("data-parentqty"));

                    return (Math.max(1, limit, limit * required)) * parent_qty_multiplier;
                },

                update_message: function(){
                    const container = jQuery(".select_card_container");
                    const limit = parseInt(container.attr("data-limit"));
                    const required = parseInt(container.attr("data-required"));
                    const total_selected = simpleCart.get_total_selected()
                    const total_allowed = simpleCart.get_total_allowed();
                    if(total_allowed === "Unlimited"){
                        jQuery(".simpleCart_progress_message").hide();
                        jQuery(".simpleCart_next_acc_dialog").removeClass("disabled_next");
                        jQuery(".simpleCart_finish_acc_dialog").removeClass("disabled_finish");
                        jQuery(".simpleCart_add_acc_dialog").removeClass("disabled_add");
                    }else {
                        const remaining = total_allowed - total_selected;
                        if (limit > 0 || required > 0) {
                            jQuery(".simpleCart_progress_message").show();
                            if (remaining <= 0 && total_selected != 0) {
                                if (required > 0) {
                                    jQuery(".simpleCart_next_acc_dialog").removeClass("disabled_next");
                                    jQuery(".simpleCart_finish_acc_dialog").removeClass("disabled_finish");
                                    jQuery(".simpleCart_add_acc_dialog").removeClass("disabled_add");
                                }
                            } else if (remaining > 0 || total_selected == 0) {
                                if (required > 0) {
                                    jQuery(".simpleCart_next_acc_dialog").addClass("disabled_next");
                                    jQuery(".simpleCart_finish_acc_dialog").addClass("disabled_finish");
                                    jQuery(".simpleCart_add_acc_dialog").addClass("disabled_add");
                                }
                            }
                            if (remaining > 0) {
                                jQuery(".simpleCart_progress_message .progress_message_qty").text(remaining);
                                jQuery("#progress_message_add_more").show();
                                jQuery("#progress_message_all_added").hide();
                            } else if (remaining <= 0) {
                                jQuery("#progress_message_add_more").hide();
                                jQuery("#progress_message_all_added").show();
                            }
                        } else {
                            jQuery(".simpleCart_progress_message").hide();
                        }
                    }
                },

                update_buttons : function (){
                    if(cart_acc_state.state_stack.length == 0){
                        jQuery(".dialog_acc_selectable_card.selected").each(function(){
                            let acc_id = this.getAttribute("data");
                            if(cart_acc_state.has_sub_state(acc_id)){
                                let sub_state = cart_acc_state.get_sub_state(acc_id);
                                let required_dropdown_states = sub_state.find_required_dropdown_states()
                                if(!sub_state.display_is_empty() || required_dropdown_states.length>0){
                                    jQuery(".simpleCart_next_acc_dialog").show();
                                    jQuery(".simpleCart_finish_acc_dialog").hide();
                                    jQuery(".simpleCart_add_acc_dialog").hide();
                                    jQuery(".simpleCart_progress").show();
                                }else{
                                    jQuery(".simpleCart_next_acc_dialog").hide();
                                    if(cart_acc_state.prev_states.length > 0){
                                        jQuery(".simpleCart_finish_acc_dialog").show();
                                        jQuery(".simpleCart_add_acc_dialog").hide();
                                    }else{
                                        jQuery(".simpleCart_finish_acc_dialog").hide();
                                        jQuery(".simpleCart_add_acc_dialog").show();
                                    }
                                }
                            }else{
                                jQuery(".simpleCart_next_acc_dialog").hide();
                                if(cart_acc_state.prev_states.length > 0 || jQuery("#cart_acc_select_bottom").is("[data-editing]")){
                                    jQuery(".simpleCart_finish_acc_dialog").show();
                                    jQuery(".simpleCart_add_acc_dialog").hide();
                                }else{
                                    jQuery(".simpleCart_finish_acc_dialog").hide();
                                    jQuery(".simpleCart_add_acc_dialog").show();
                                }
                            }
                        });
                        if(jQuery("#cart_acc_select_bottom").is("[data-editing]")){
                            jQuery(".simpleCart_add_acc_dialog").html('<span class="io_acc_done">Done Editing</span>');
                        }else{
                            jQuery(".simpleCart_add_acc_dialog").html('<i class="fas fa-cart-plus"></i>');
                        }
                    }
                },

                update_progress: function(){
                    let total_states = cart_acc_state.state_stack.length + cart_acc_state.prev_states.length + 1; // Current state
                    let completed = cart_acc_state.prev_states.length;

                    if(total_states > 1){
                        let percentage = (completed / total_states) * 100;
                        jQuery(".simpleCart_progress_inner").width(percentage+"%");
                        jQuery(".simpleCart_progress_outer").show();
                    }else{
                        jQuery(".simpleCart_progress_inner").width("0%");
                        jQuery(".simpleCart_progress_outer").hide();
                    }
                },

                update_parentqty_for_linkqty_choices: function(){
                    const container = jQuery(".select_card_container")
                    let container_path = container.attr("data-path");
                    const split_container_path = container_path.split("_");
                    const container_target = split_container_path.pop();
                    container_path = split_container_path.join("_");
                    const container_parent = simpleCart.find_confirm_screen_element(container_path, container_target);
                    const container_increment = parseInt(container.attr("data-increment"));
                    const container_required = parseInt(container.attr("data-required"));
                    const qty_multiplier = Math.max(1, container_increment, container_increment*container_required);
                    const container_parent_qty = container_parent.qty * qty_multiplier;

                    if(container.attr("data-linkqty") == 1) {
                        container.attr("data-parentqty", container_parent_qty);
                    }
                    jQuery(".dialog_acc_selectable_card[data-linkqty='1']").each(function (){
                        const card_increment = parseInt(this.dataset.increment);
                        const card_required = parseInt(this.dataset.required);
                        const card_qty_multiplier = Math.max(1, card_increment, card_increment*card_required);
                        const card_parent_qty = qty_multiplier * card_qty_multiplier;
                        this.setAttribute("data-parentqty", card_parent_qty);
                    });
                },

                set_rental_obj_qty: function(){
                    // Helper function to reset all quantities to 0 recursively
                    function reset_quantities(rental_obj) {
                        rental_obj.qty = 0;
                        if (rental_obj.accessories && rental_obj.accessories.length > 0) {
                            for (let i = 0; i < rental_obj.accessories.length; i++) {
                                reset_quantities(rental_obj.accessories[i]);
                            }
                        }
                    }

                    // Helper function to set quantities from confirm_screen_elements
                    function set_quantities_from_elements(rental_obj, elements) {
                        for (let i = 0; i < elements.length; i++) {
                            let element = elements[i];
                            
                            // Find matching accessory in rental_obj
                            if (rental_obj.rentalid == element.rid) {
                                rental_obj.qty = element.qty;
                                // Process nested accessories if they exist
                                if (element.accessories && element.accessories.length > 0) {
                                    for (let j = 0; j < element.accessories.length; j++) {
                                        set_quantities_in_accessories(rental_obj.accessories, element.accessories[j]);
                                    }
                                }
                            }
                        }
                    }

                    // Helper function to recursively set quantities in accessories
                    function set_quantities_in_accessories(accessories_array, element) {
                        // Try to find existing accessory match first
                        for (let i = 0; i < accessories_array.length; i++) {
                            if (accessories_array[i].rentalid == element.rid) {
                                accessories_array[i].qty = element.qty;
                                // Process nested accessories recursively
                                if (element.accessories && element.accessories.length > 0) {
                                    // Ensure nested accessories array exists
                                    if (!accessories_array[i].accessories) accessories_array[i].accessories = [];
                                    for (let j = 0; j < element.accessories.length; j++) {
                                        set_quantities_in_accessories(accessories_array[i].accessories, element.accessories[j]);
                                    }
                                }
                                return; // done updating existing
                            }
                        }

                        let newAcc = new IO_Rental(element.rid, (element.name || ''), element.qty || 0);
                        // Ensure sub-accessories are processed
                        newAcc.accessories = [];
                        accessories_array.push(newAcc);
                        if (element.accessories && element.accessories.length > 0) {
                            for (let j = 0; j < element.accessories.length; j++) {
                                set_quantities_in_accessories(newAcc.accessories, element.accessories[j]);
                            }
                        }
                    }

                    // First, reset all quantities to 0
                    reset_quantities(cart_acc_state.rental_obj);

                    // Then, set quantities based on confirm_screen_elements
                    if (cart_acc_state.confirm_screen_elements && cart_acc_state.confirm_screen_elements.length > 0) {
                        set_quantities_from_elements(cart_acc_state.rental_obj, cart_acc_state.confirm_screen_elements);
                    }
                },

                remove_zero_qty_accs: function (rental_obj){
                    rental_obj.accessories = rental_obj.accessories.filter(function(acc_obj){
                        if(acc_obj.qty > 0){
                            if(acc_obj.accessories.length > 0){
                                simpleCart.remove_zero_qty_accs(acc_obj);
                            }
                            return true;
                        }else{
                            return false;
                        }
                    });
                },

                // updating functions
                update: function () {
                    simpleCart.save();
                    simpleCart.trigger("update");
                },

                init: function () {
                    simpleCart.load();
                    simpleCart.update();
                    simpleCart.ready();
                },

                // view management
                $: function (selector) {
                    return new simpleCart.ELEMENT(selector);
                },

                $create: function (tag) {
                    return simpleCart.$(document.createElement(tag));
                },

                setupViewTool: function () {
                    var members, member, context = window, engine;

                    // Determine the "best fit" selector engine
                    for (engine in selectorEngines) {
                        if (Object.prototype.hasOwnProperty.call(selectorEngines, engine) && window[engine]) {
                            members = selectorEngines[engine].replace("*", engine).split(".");
                            member = members.shift();
                            if (member) {
                                context = context[member];
                            }
                            if (typeof context === "function") {
                                // set the selector engine and extend the prototype of our
                                // element wrapper class
                                $engine = context;
                                simpleCart.extend(simpleCart.ELEMENT._, selectorFunctions[engine]);
                                return;
                            }
                        }
                    }
                },

                // return a list of id's in the cart
                ids: function () {
                    var ids = [];
                    simpleCart.each(function (item) {
                        ids.push(item.id());
                    });
                    return ids;

                },


                // storage
                save: function () {
                    simpleCart.trigger('beforeSave');

                    var items = {};

                    // save all the items
                    simpleCart.each(function (item) {
                        items[item.id()] = simpleCart.extend(item.fields(), item.options());
                    });

                    localStorage.setItem(namespace + "_items", JSON.stringify(items));

                    simpleCart.trigger('afterSave');
                },

                load: function () {

                    // empty without the update
                    sc_items = {};

                    var items = localStorage.getItem(namespace + "_items");

                    if (!items) {
                        return;
                    }

                    // we wrap this in a try statement so we can catch
                    // any json parsing errors. no more stick and we
                    // have a playing card pluckin the spokes now...
                    // soundin like a harley.
                    try {
                        simpleCart.each(JSON.parse(items), function (item) {
                            simpleCart.add(item, true);
                        });
                    } catch (e){
                        simpleCart.error( "Error Loading data: " + e );
                    }


                    simpleCart.trigger('load');
                },

                // ready function used as a shortcut for bind('ready',fn)
                ready: function (fn) {

                    if (isFunction(fn)) {
                        // call function if already ready already
                        if (simpleCart.isReady) {
                            fn.call(simpleCart);

                            // bind if not ready
                        } else {
                            simpleCart.bind('ready', fn);
                        }

                        // trigger ready event
                    } else if (isUndefined(fn) && !simpleCart.isReady) {
                        simpleCart.trigger('ready');
                        simpleCart.isReady = true;
                    }
                },


                error: function (message) {
                    var msg = "";
                    if (isString(message)) {
                        msg = message;
                    } else if (isObject(message) && isString(message.message)) {
                        msg = message.message;
                    }
                    try { console.log("simpleCart(js) Error: " + msg); } catch (e) {}
                    simpleCart.trigger('error', [message]);
                }
            });


            /*******************************************************************
             *	TAX AND SHIPPING
             *******************************************************************/
            simpleCart.extend({


                tax: function () {
                    var totalToTax = settings.taxShipping ? simpleCart.total() + simpleCart.shipping() : simpleCart.total(),
                        cost = simpleCart.taxRate() * totalToTax;

                    simpleCart.each(function (item) {
                        if (item.get('tax')) {
                            cost += item.get('tax');
                        } else if (item.get('taxRate')) {
                            cost += item.get('taxRate') * item.total();
                        }
                    });
                    return parseFloat(cost);
                },

                taxRate: function () {
                    return settings.taxRate || 0;
                },

                shipping: function (opt_custom_function) {

                    // shortcut to extend options with custom shipping
                    if (isFunction(opt_custom_function)) {
                        simpleCart({
                            shippingCustom: opt_custom_function
                        });
                        return;
                    }

                    var cost = settings.shippingQuantityRate * simpleCart.quantity() +
                        settings.shippingTotalRate * simpleCart.total() +
                        settings.shippingFlatRate;

                    if (isFunction(settings.shippingCustom)) {
                        cost += settings.shippingCustom.call(simpleCart);
                    }

                    simpleCart.each(function (item) {
                        cost += parseFloat(item.get('shipping') || 0);
                    });
                    return parseFloat(cost);
                }

            });

            /*******************************************************************
             *	CART VIEWS
             *******************************************************************/

            // built in cart views for item cells
            cartColumnViews = {
                attr: function (item, column) {
                    return item.get(column.attr) || "";
                },

                currency: function (item, column) {
                    return simpleCart.toCurrency(item.get(column.attr) || 0);
                },

                link: function (item, column) {
                    return "<a href='" + item.get(column.attr) + "'>" + column.text + "</a>";
                },

                decrement: function (item, column) {
                    // Check if this is a separate unit (rental_id contains ":" but not "_")
                    let rental_id = item.get("rentalid") || "";
                    let is_separate_unit = rental_id.includes(":") && !rental_id.includes("_");
                    let rental_obj = IO_Rental.fromObject(item.get("rental_obj"));
                    let accessory_conditions = (!is_separate_unit && item.get("rental_obj").accessories.length > 0
                        && io_accessory_data[rental_id]?.accessories)
                    
                    if(item.get("inputtype") == "Hidden" || item.get("inputtype") == "Map" || item.get("linkqty") == 1
                        || accessory_conditions) return "";
                    return "<a href='javascript:;' class='" + namespace + "_decrement'>" + (column.text || "-") + "</a>";
                },

                increment: function (item, column) {
                    let item_qty = item.get("quantity");
                    let item_qtyincrement = parseInt(item.get("qtyincrement"));
                    let item_avail = item.get("availability");
                    let rental_obj = IO_Rental.fromObject(item.get("rental_obj"));
                    let rental_id = item.get("rentalid") || "";
                    // Check if this is a separate unit (rental_id contains ":" but not "_")
                    let is_separate_unit = rental_id.includes(":") && !rental_id.includes("_");
                    let accessory_conditions = (!is_separate_unit && rental_obj.accessories.length > 0
                        && io_accessory_data[rental_id]?.accessories)


                    if(item.get("inputtype") == "Hidden" || item.get("inputtype") == "Map" || item.get("linkqty") == 1
                        || accessory_conditions) return "";
                    else if((typeof item_qty !== "undefined" && typeof item_avail !== "undefined"
                        && item_qty+item_qtyincrement > item_qty+item_avail) || !rental_obj.required_accessoires_are_avail()) {
                        return "<a href='javascript:;' class='" + namespace + "_increment disabled_cart_increment'>" + (column.text || "+") + "</a>";
                    }
                    return "<a href='javascript:;' class='" + namespace + "_increment'>" + (column.text || "+") + "</a>";
                },

                image: function (item, column) {
                    if(item.get(column.attr) === undefined){
                        return "<img src='" + item.get(column.attr) + "' class='item-image-thumb' style='display: none'/>";
                    }
                    let href = item.get('href');
                    if(isUndefined(href)){
                        href = window.location.href;
                        item.set('href',href);
                    }
                    return "<a href='" + href + "'> <img src='" + item.get(column.attr) + "' class='item-image-thumb' /> </a>";
                },

                calculate_area: function(item, column) {
                    if(item.get("inputtype") == "Map") {
                        if(item.get("quantity") > 1){
                            if(item.get("rentalid").includes("_")){
                                return "<p class='simpleCart_map'>"+item.get("quantity")+" "+item.get("units")+"</p>"
                            }else{
                                return "<p class='simpleCart_map elementor-animation-grow' onClick='openMap(this)'>"+item.get("quantity")+" "+item.get("units")+"</p>"
                            }

                        }else{
                            if(item.get("rentalid").includes("_")){
                                return "";
                            }else{
                                return "<p class='simpleCart_map elementor-animation-grow' onClick='openMap(this)'>Calculate</p>"
                            }

                        }
                    }
                },
                accessories: function(item, column){
                    let rental_id = item.get("rentalid") || "";
                    let is_separate_unit = rental_id.includes(":") && !rental_id.includes("_");
                    if(item.get("rental_obj")){
                        rental_obj = item.get("rental_obj");
                        let acc_data = io_accessory_data[rental_id]?.accessories;
                        if(rental_obj.accessories.length > 0 && !is_separate_unit && acc_data){
                            let has_editable = Object.values(acc_data).some(a =>
                                Number(a.dropdown) > 0 || Number(a.required) === 0
                            );
                            if(has_editable){
                                return "<p class='simpleCart_open_item_acc'>Edit Package</p>";
                            }
                        }
                        return "";
                    }
                },

                input: function (item, column) {
                    // Check if this is a separate unit (rental_id contains ":" but not "_")
                    let rental_id = item.get("rentalid") || "";
                    let is_separate_unit = rental_id.includes(":") && !rental_id.includes("_");
                    let rental_obj = IO_Rental.fromObject(item.get("rental_obj"));
                    let accessory_conditions = (!is_separate_unit && item.get("rental_obj").accessories.length > 0
                        && io_accessory_data[rental_id]?.accessories)
                    
                    if(accessory_conditions) return "";
                    if(item.get("inputtype") == "Map") return "<input type='text' maxlength='4' style='display:none' disabled value='" + item.get(column.attr) + "' class='simpleCart_input'/>";
                    if(item.get("inputtype") == "Hidden") return "<input type='text' maxlength='4' value='" + item.get(column.attr) + "' class='simpleCart_input' readonly />";
                    return "<input type='text' autocomplete='off' maxlength='4' value='" + item.get(column.attr) + "' class='simpleCart_input'/>";
                },

                remove: function (item, column) {
                    return "<a href='javascript:;' class='" + namespace + "_remove'>" + (column.text || "") + "</a>";
                },

                availability: function(item, column){
                    if(item.get(column.attr) >= 0){
                        return ""
                    }else{
                        return "<p style='color:red; margin:0'>Not Available</p>"
                    }
                }
            };

            // cart column wrapper class and functions
            function cartColumn(opts) {
                var options = opts || {};
                return simpleCart.extend({
                    attr			: "",
                    label			: "",
                    view			: "attr",
                    text			: "",
                    className		: "",
                    hide			: false
                }, options);
            }

            function cartCellView(item, column) {
                var viewFunc = isFunction(column.view) ? column.view : isString(column.view) && isFunction(cartColumnViews[column.view]) ? cartColumnViews[column.view] : cartColumnViews.attr;

                return viewFunc.call(simpleCart, item, column);
            }


            simpleCart.extend({

                // write out cart
                writeCart: function (selector) {
                    var TABLE = settings.cartStyle.toLowerCase(),
                        isTable = TABLE === 'table',
                        TR = isTable ? "tr" : "div",
                        TH = isTable ? 'th' : 'div',
                        TD = isTable ? 'td' : 'div',
                        THEAD = isTable ? 'thead' : 'div',
                        cart_container = simpleCart.$create(TABLE),
                        thead_container = simpleCart.$create(THEAD),
                        header_container = simpleCart.$create(TR).addClass('headerRow'),
                        container = simpleCart.$(selector),
                        column,
                        klass,
                        label,
                        x,
                        xlen;

                    container.html(' ').append(cart_container);

                    cart_container.append(thead_container);

                    thead_container.append(header_container);


                    // create header
                    for (x = 0, xlen = settings.cartColumns.length; x < xlen; x += 1) {
                        column	= cartColumn(settings.cartColumns[x]);
                        klass	=  "item-" + (column.attr || column.view || column.label || column.text || "cell") + " " + column.className;
                        label	= column.label || "";

                        // append the header cell
                        header_container.append(
                            simpleCart.$create(TH).addClass(klass).html(label)
                        );
                    }

                    // cycle through the items
                    simpleCart.each(function (item, y) {
                        simpleCart.createCartRow(item, y, TR, TD, cart_container);
                    });

                    return cart_container;
                },

                // generate a cart row from an item
                createCartRow: function (item, y, TR, TD, container) {
                    if(!item.get("rental_obj")){
                        item.remove();
                        return null;
                    }
                    var row = simpleCart.$create(TR)
                            .addClass('itemRow row-' + y + " " + (y % 2 ? "even" : "odd"))
                            .attr('id', "cartItem_" + item.id()),
                        j,
                        jlen,
                        column,
                        klass,
                        content,
                        cell;

                    // Preserve io-checking-availability class if item is being checked
                    if (item.get('checking_availability')) {
                        row.addClass('io-checking-availability');
                    }

                    container.append(row);

                    // cycle through the columns to create each cell for the item
                    for (j = 0, jlen = settings.cartColumns.length; j < jlen; j += 1) {
                        column	= cartColumn(settings.cartColumns[j]);
                        klass	= "item-" + (column.attr || (isString(column.view) ? column.view : column.label || column.text || "cell")) + " " + column.className;
                        content = cartCellView(item, column);
                        cell	= simpleCart.$create(TD).addClass(klass).html(content);

                        row.append(cell);
                    }
                    
                    // Disable quantity input if item is being checked
                    if (item.get('checking_availability')) {
                        row.find('.item-quantity input').attr('disabled', 'disabled');
                    }
                    
                    return row;
                }

            });

            /*******************************************************************
             *	CART ITEM CLASS MANAGEMENT
             *******************************************************************/

            simpleCart.Item = function (info) {
                // we use the data object to track values for the item
                var _data = {},
                    me = this;

                // cycle through given attributes and set them to the data object
                if (isObject(info)) {
                    simpleCart.extend(_data, info);
                }

                // set the item id
                item_id += 1;
                _data.id = _data.id || item_id_namespace + item_id;
                while (!isUndefined(sc_items[_data.id])) {
                    item_id += 1;
                    _data.id = item_id_namespace + item_id;
                }

                function checkQuantityAndPrice() {

                    // check to make sure price is valid
                    if (isString(_data.price)) {
                        // trying to remove all chars that aren't numbers or '.'
                        if(_data.price != "TBD"){
                            _data.price = parseFloat(_data.price.replace(simpleCart.currency().decimal, ".").replace(/[^0-9\.]+/ig, ""));
                        }
                    }
                    if (isNaN(_data.price)) {
                        if(_data.price != "TBD"){
                            _data.price = 0;
                        }
                    }
                    if (_data.price < 0) {
                        _data.price = 0;
                    }

                    // check to make sure quantity is valid
                    if (isString(_data.quantity)) {
                        _data.quantity = parseInt(_data.quantity.replace(simpleCart.currency().delimiter, ""), 10);
                    }
                    if (isNaN(_data.quantity)) {
                        _data.quantity = 1;
                    }
                    if (_data.quantity <= 0) {
                        me.remove();
                    }

                    simpleCart.items().forEach(function (item, index){
                        if(item.get("rentalid").match(new RegExp("^"+me.get("rentalid")+"_"))){
                            if(item.get("linkqty") > 0){
                                let required = parseInt(item.get("required"));
                                if(!required){
                                    required = parseInt(item.get('qtyincrement'));
                                }
                                if(!required){
                                    required = 1;
                                }
                                if(me.get("inputtype")  == "Map" && item.get("inputtype")  == "Map") {
                                    item.set("units", me.get("units"));
                                }
                                item.set("quantity", me.get("quantity") * required)
                            }
                        }
                    })
                }

                // getter and setter methods to access private variables
                me.get = function (name, skipPrototypes) {

                    var usePrototypes = !skipPrototypes;

                    if (isUndefined(name)) {
                        return name;
                    }

                    // return the value in order of the data object and then the prototype
                    return isFunction(_data[name])	? _data[name].call(me) :
                        !isUndefined(_data[name]) ? _data[name] :

                            isFunction(me[name]) && usePrototypes		? me[name].call(me) :
                                !isUndefined(me[name]) && usePrototypes	? me[name] :
                                    _data[name];
                };
                me.set = function (name, value) {
                    if (!isUndefined(name)) {
                        _data[name.toLowerCase()] = value;
                        if (name.toLowerCase() === 'price' || name.toLowerCase() === 'quantity') {
                            checkQuantityAndPrice();
                        }
                    }
                    return me;
                };
                me.equals = function (item) {
                    for( var label in _data ){
                        if (Object.prototype.hasOwnProperty.call(_data, label)) {
                            //if (label !== 'quantity' && label !== 'id' && label !== 'price' && label !== 'availability' && label !== 'image') {
                            if(item.get("accobj")){
                                return false;
                            }else{
                                if(label == 'rentalid'){
                                    if (item.get(label).replace(/[\u2032\u2019]+/ig, "'") !== _data[label].replace(/[\u2032\u2019]+/ig, "'")) {
                                        return false;
                                    }
                                }
                            }
                        }
                    }
                    return true;
                };
                me.options = function () {
                    var data = {};
                    simpleCart.each(_data,function (val, x, label) {
                        var add = true;
                        simpleCart.each(me.reservedFields(), function (field) {
                            if (field === label) {
                                add = false;
                            }
                            return add;
                        });
                        if (add) {
                            data[label] = me.get(label);
                        }
                    });
                    return data;
                };


                checkQuantityAndPrice();
            };

            simpleCart.Item._ = simpleCart.Item.prototype = {

                // editing the item quantity
                increment: function (amount) {
                    amount = amount || this.get('qtyincrement');
                    var diff = amount || 1;
                    diff = parseInt(diff, 10);

                    this.quantity(this.quantity() + diff);
                    if (this.quantity() < 1) {
                        this.remove();
                        return null;
                    }
                    let rental_obj = this.get("rental_obj");
                    rental_obj.qty = this.quantity();
                    // Update accessory quantities for separate units
                    if (rental_obj.accessories && rental_obj.accessories.length > 0) {
                        for (let i = 0; i < rental_obj.accessories.length; i++) {
                            rental_obj.accessories[i].qty = this.quantity();
                        }
                    }
                    this.set("rental_obj", rental_obj);
                    return this;

                },
                decrement: function (amount) {
                    amount = amount || this.get('qtyincrement');
                    var diff = amount || 1;
                    return this.increment(-parseInt(diff, 10));
                },
                remove: function (skipUpdate, quiet=false) {
                    var removed_item = Object.assign({}, sc_items[this.id()]);
                    var removeItemBool = simpleCart.trigger("beforeRemove", [removed_item]);
                    if (removeItemBool === false ) {
                        return false;
                    }
                    delete sc_items[this.id()];
                    if (!skipUpdate) {
                        simpleCart.update();
                    }
                    if(!quiet){
                        simpleCart.trigger("afterRemove", [removed_item]);
                    }
                    return null;
                },

                // special fields for items
                reservedFields: function () {
                    return ['rentalid', 'inputtype', 'quantity', 'qtyincrement', 'qtytype', 'id', 'item_number', 'name','encoded', 'availability','shipping', 'tax', 'taxRate','price','timeslots','timeslots-orig', 'href', 'accobj', 'rental_obj'];
                },

                // return values for all reserved fields if they exist
                fields: function () {
                    var data = {},
                        me = this;
                    simpleCart.each(me.reservedFields(), function (field) {
                        if (me.get(field)) {
                            data[field] = me.get(field);
                        }
                    });
                    return data;
                },


                // shortcuts for getter/setters. can
                // be overwritten for customization
                // btw, we are hiring at wojo design, and could
                // use a great web designer. if thats you, you can
                // get more info at http://wojodesign.com/now-hiring/
                // or email me directly: brett@wojodesign.com
                quantity: function (val) {
                    return isUndefined(val) ? parseInt(this.get("quantity", true) || 1, 10) : this.set("quantity", val);
                },
                price: function (val) {
                    if(isUndefined(val)){
                        let price = this.get("price",true);
                        if(price !== "TBD"){
                            parseFloat((price.toString()).replace(simpleCart.currency().symbol,"").replace(simpleCart.currency().delimiter,"") || 1);
                        }
                        return price;
                    }else{
                        this.set("price", parseFloat((val).toString().replace(simpleCart.currency().symbol,"").replace(simpleCart.currency().delimiter,"")));
                    }
                },
                href: function(val){
                    return isUndefined(val) ? this.get("href", true) : this.set('href', val);
                },
                id: function () {
                    return this.get('id',false);
                },
                total:function () {
                    let price = this.price();
                    if(price !== "TBD"){
                        price = this.quantity()*price;
                    }
                    return price;
                }

            };




            /*******************************************************************
             *	CHECKOUT MANAGEMENT
             *******************************************************************/

            simpleCart.extend({
                checkout: function () {
                    try{
                        if (typeof window['fbq'] === "function") {
                            fbq('track', 'InitiateCheckout');//fb track
                        }
                    }catch(e){
                        console.log(e);
                    }
                    try{
                        if (typeof window['gtag'] === "function") {
                            var gtag_items = Array();
                            simpleCart.each(function (item,x) {
                                let gtag_item = {}
                                gtag_item.item_id = item.get("rentalid");
                                gtag_item.item_name = item.get("name");
                                gtag_item.price = item.price();
                                gtag_item.quantity = item.quantity();
                                gtag_items.push(gtag_item);
                            });
                            gtag("event", "begin_checkout", {
                                currency: currency,
                                value: simpleCart.grandTotal(),
                                items: gtag_items
                            });
                        }
                    }catch(e){
                        console.log(e);
                    }
                    if (settings.checkout.type.toLowerCase() === 'custom' && isFunction(settings.checkout.fn)) {
                        settings.checkout.fn.call(simpleCart,settings.checkout);
                    } else if (isFunction(simpleCart.checkout[settings.checkout.type])) {
                        var checkoutData = simpleCart.checkout[settings.checkout.type].call(simpleCart,settings.checkout);

                        // if the checkout method returns data, try to send the form
                        if( checkoutData.data && checkoutData.action && checkoutData.method ){
                            // if no one has any objections, send the checkout form
                            if( false !== simpleCart.trigger('beforeCheckout', [checkoutData.data]) ){
                                simpleCart.generateAndSendForm( checkoutData );
                            }
                        }

                    } else {
                        //simpleCart.error("No Valid Checkout Method Specified");
                        //path = "//rental.software/quotes/quoteme.php";
                        path = io_wp_local_path+"/io_quoteform/";
                        settings.checkout=
                            {
                                type: "SendForm",
                                method: "GET",
                                //url: "//rental.software/quotes/quoteme.php",
                                url: path,
                                extra_data: {
                                    //name: decodeURIComponent("%%page%%".replace(/[+]/gi, " ")),
                                    //clear_rentals: "1",
                                    selected_only: "1",
                                    wp_checkout: "1"
                                }
                            };
                        var checkoutData = simpleCart.checkout['SendForm'].call(simpleCart,settings.checkout);

                        // if the checkout method returns data, try to send the form
                        if( checkoutData.data && checkoutData.action && checkoutData.method ){
                            // if no one has any objections, send the checkout form
                            if( false !== simpleCart.trigger('beforeCheckout', [checkoutData.data]) ){
                                simpleCart.generateAndSendForm( checkoutData );
                            }
                        }


                    }
                },
                extendCheckout: function (methods) {
                    return simpleCart.extend(simpleCart.checkout, methods);
                },
                generateAndSendForm: function (opts) {
                    var form = simpleCart.$create("form");
                    form.attr('style', 'display:none;');
                    form.attr('action', opts.action);
                    form.attr('method', opts.method);
                    simpleCart.each(opts.data, function (val, x, name) {
                        form.append(
                            simpleCart.$create("input").attr("type","hidden").attr("name",name).val(val)
                        );
                    });
                    simpleCart.$("body").append(form);
                    form.el.submit();
                }
            });

            simpleCart.extendCheckout({

                SendForm: function (opts) {
                    // url required
                    if (!opts.url) {
                        return simpleCart.error('URL required for SendForm Checkout');
                    }

                    // build basic form options
                    var data = {},
                        action = opts.url,
                        method = opts.method === "GET" ? "GET" : "POST";


                    // add items to data
                    // Use uid instead of these qid and cid. we get uid back from api6.
                    data['uid'] = IoData.uid;

                    // check for return and success URLs in the options
                    if (opts.success) {
                        data['return'] = opts.success;
                    }
                    if (opts.cancel) {
                        data.cancel_return = opts.cancel;
                    }

                    if (opts.extra_data) {
                        data = simpleCart.extend(data,opts.extra_data);
                    }

                    // return the data for the checkout form
                    return {
                        action	: action
                        , method	: method
                        , data		: data
                    };
                }


            });


            /*******************************************************************
             *	EVENT MANAGEMENT
             *******************************************************************/
            eventFunctions = {

                // bind a callback to an event
                bind: function (name, callback) {
                    if (!isFunction(callback)) {
                        return this;
                    }

                    if (!this._events) {
                        this._events = {};
                    }

                    // split by spaces to allow for multiple event bindings at once
                    var eventNameList = name.split(/ +/);

                    // iterate through and bind each event
                    simpleCart.each( eventNameList , function( eventName ){
                        if (this._events[eventName] === true) {
                            callback.apply(this);
                        } else if (!isUndefined(this._events[eventName])) {
                            this._events[eventName].push(callback);
                        } else {
                            this._events[eventName] = [callback];
                        }
                    });


                    return this;
                },

                // trigger event
                trigger: function (name, options) {
                    var returnval = true,
                        x,
                        xlen;

                    if (!this._events) {
                        this._events = {};
                    }
                    if (!isUndefined(this._events[name]) && isFunction(this._events[name][0])) {
                        for (x = 0, xlen = this._events[name].length; x < xlen; x += 1) {
                            returnval = this._events[name][x].apply(this, (options || []));
                        }
                    }
                    if (returnval === false) {
                        return false;
                    }
                    return true;
                }

            };
            // alias for bind
            eventFunctions.on = eventFunctions.bind;
            simpleCart.extend(eventFunctions);
            simpleCart.extend(simpleCart.Item._, eventFunctions);


            // base simpleCart events in options
            baseEvents = {
                beforeAdd				: null
                , afterAdd				: null
                , load					: null
                , beforeSave			: null
                , afterSave				: null
                , update				: null
                , ready					: null
                , checkoutSuccess		: null
                , checkoutFail			: null
                , beforeCheckout		: null
                , beforeRemove			: null
                , afterRemove			: null
                , afterQtyChange		: null
            };

            // extend with base events
            simpleCart(baseEvents);

            // bind settings to events
            simpleCart.each(baseEvents, function (val, x, name) {
                simpleCart.bind(name, function () {
                    if (isFunction(settings[name])) {
                        settings[name].apply(this, arguments);
                    }
                });
            });

            /*******************************************************************
             *	FORMATTING FUNCTIONS
             *******************************************************************/
            simpleCart.extend({
                toCurrency: function (number,opts) {
                    if(number !== "TBD"){
                        var num = parseFloat(number),
                            opt_input = opts || {},
                            _opts = simpleCart.extend(simpleCart.extend({
                                symbol:		"$"
                                , decimal:		"."
                                , delimiter:	","
                                , accuracy:		2
                                , after: false
                            }, simpleCart.currency()), opt_input),

                            numParts = num.toFixed(_opts.accuracy).split("."),
                            dec = numParts[1],
                            ints = numParts[0];

                        ints = simpleCart.chunk(ints.reverse(), 3).join(_opts.delimiter.reverse()).reverse();

                        return	(!_opts.after ? _opts.symbol : "") +
                            ints +
                            (dec ? _opts.decimal + dec : "") +
                            (_opts.after ? _opts.symbol : "");
                    }else{
                        return number;
                    }
                },


                // break a string in blocks of size n
                chunk: function (str, n) {
                    if (typeof n==='undefined') {
                        n=2;
                    }
                    var result = str.match(new RegExp('.{1,' + n + '}','g'));
                    return result || [];
                }

            });


            // reverse string function
            String.prototype.reverse = function () {
                return this.split("").reverse().join("");
            };


            // currency functions
            simpleCart.extend({
                currency: function (currency) {
                    if (isString(currency) && !isUndefined(currencies[currency])) {
                        settings.currency = currency;
                    } else if (isObject(currency)) {
                        currencies[currency.code] = currency;
                        settings.currency = currency.code;
                    } else {
                        return currencies[settings.currency];
                    }
                }
            });


            /*******************************************************************
             *	VIEW MANAGEMENT
             *******************************************************************/

            simpleCart.extend({
                // bind outlets to function
                bindOutlets: function (outlets) {
                    simpleCart.each(outlets, function (callback, x, selector) {

                        simpleCart.bind('update', function () {
                            simpleCart.setOutlet("." + namespace + "_" + selector, callback);
                        });
                    });
                },

                // set function return to outlet
                setOutlet: function (selector, func) {
                    var val = func.call(simpleCart, selector);
                    if (isObject(val) && val.el) {
                        simpleCart.$(selector).html(' ').append(val);
                    } else if (!isUndefined(val)) {
                        simpleCart.$(selector).html(val);
                    }
                },

                // bind click events on inputs
                bindInputs: function (inputs) {
                    simpleCart.each(inputs, function (info) {
                        simpleCart.setInput("." + namespace + "_" + info.selector, info.event, info.callback);
                    });
                },

                // attach events to inputs
                setInput: function (selector, event, func) {
                    simpleCart.$(selector).live(event, func);
                }
            });


            // class for wrapping DOM selector shit
            simpleCart.ELEMENT = function (selector) {

                this.create(selector);
                this.selector = selector || null; // "#" + this.attr('id');
            };

            simpleCart.extend(selectorFunctions, {

                "MooTools"		: {
                    text: function (text) {
                        return this.attr(_TEXT_, text);
                    },
                    html: function (html) {
                        return this.attr(_HTML_, html);
                    },
                    val: function (val) {
                        return this.attr(_VALUE_, val);
                    },
                    attr: function (attr, val) {
                        if (isUndefined(val)) {
                            return this.el[0] && this.el[0].get(attr);
                        }

                        this.el.set(attr, val);
                        return this;
                    },
                    remove: function () {
                        this.el.dispose();
                        return null;
                    },
                    addClass: function (klass) {
                        this.el.addClass(klass);
                        return this;
                    },
                    removeClass: function (klass) {
                        this.el.removeClass(klass);
                        return this;
                    },
                    append: function (item) {
                        this.el.adopt(item.el);
                        return this;
                    },
                    each: function (callback) {
                        if (isFunction(callback)) {
                            simpleCart.each(this.el, function( e, i, c) {
                                callback.call( i, i, e, c );
                            });
                        }
                        return this;
                    },
                    click: function (callback) {
                        if (isFunction(callback)) {
                            this.each(function (e) {
                                e.addEvent(_CLICK_, function (ev) {
                                    callback.call(e,ev);
                                });
                            });
                        } else if (isUndefined(callback)) {
                            this.el.fireEvent(_CLICK_);
                        }

                        return this;
                    },
                    live: function (	event,callback) {
                        var selector = this.selector;
                        if (isFunction(callback)) {
                            simpleCart.$("body").el.addEvent(event + ":relay(" + selector + ")", function (e, el) {
                                callback.call(el, e);
                            });
                        }
                    },
                    match: function (selector) {
                        return this.el.match(selector);
                    },
                    parent: function () {
                        return simpleCart.$(this.el.getParent());
                    },
                    find: function (selector) {
                        return simpleCart.$(this.el.getElements(selector));
                    },
                    closest: function (selector) {
                        return simpleCart.$(this.el.getParent(selector));
                    },
                    descendants: function () {
                        return this.find("*");
                    },
                    tag: function () {
                        return this.el[0].tagName;
                    },
                    submit: function (){
                        this.el[0].submit();
                        return this;
                    },
                    create: function (selector) {
                        this.el = $engine(selector);
                    }


                },

                "Prototype"		: {
                    text: function (text) {
                        if (isUndefined(text)) {
                            return this.el[0].innerHTML;
                        }
                        this.each(function (i,e) {
                            $(e).update(text);
                        });
                        return this;
                    },
                    html: function (html) {
                        return this.text(html);
                    },
                    val: function (val) {
                        return this.attr(_VALUE_, val);
                    },
                    attr: function (attr, val) {
                        if (isUndefined(val)) {
                            return this.el[0].readAttribute(attr);
                        }
                        this.each(function (i,e) {
                            $(e).writeAttribute(attr, val);
                        });
                        return this;
                    },
                    append: function (item) {
                        this.each(function (i,e) {
                            if (item.el) {
                                item.each(function (i2,e2) {
                                    $(e).appendChild(e2);
                                });
                            } else if (isElement(item)) {
                                $(e).appendChild(item);
                            }
                        });
                        return this;
                    },
                    remove: function () {
                        this.each(function (i, e) {
                            $(e).remove();
                        });
                        return this;
                    },
                    addClass: function (klass) {
                        this.each(function (i, e) {
                            $(e).addClassName(klass);
                        });
                        return this;
                    },
                    removeClass: function (klass) {
                        this.each(function (i, e) {
                            $(e).removeClassName(klass);
                        });
                        return this;
                    },
                    each: function (callback) {
                        if (isFunction(callback)) {
                            simpleCart.each(this.el, function( e, i, c) {
                                callback.call( i, i, e, c );
                            });
                        }
                        return this;
                    },
                    click: function (callback) {
                        if (isFunction(callback)) {
                            this.each(function (i, e) {
                                $(e).observe(_CLICK_, function (ev) {
                                    callback.call(e,ev);
                                });
                            });
                        } else if (isUndefined(callback)) {
                            this.each(function (i, e) {
                                $(e).fire(_CLICK_);
                            });
                        }
                        return this;
                    },
                    live: function (event,callback) {
                        if (isFunction(callback)) {
                            var selector = this.selector;
                            document.observe(event, function (e, el) {
                                if (el === $engine(e).findElement(selector)) {
                                    callback.call(el, e);
                                }
                            });
                        }
                    },
                    parent: function () {
                        return simpleCart.$(this.el.up());
                    },
                    find: function (selector) {
                        return simpleCart.$(this.el.getElementsBySelector(selector));
                    },
                    closest: function (selector) {
                        return simpleCart.$(this.el.up(selector));
                    },
                    descendants: function () {
                        return simpleCart.$(this.el.descendants());
                    },
                    tag: function () {
                        return this.el.tagName;
                    },
                    submit: function() {
                        this.el[0].submit();
                    },

                    create: function (selector) {
                        if (isString(selector)) {
                            this.el = $engine(selector);
                        } else if (isElement(selector)) {
                            this.el = [selector];
                        }
                    }



                },

                "jQuery": {
                    passthrough: function (action, val) {
                        if (isUndefined(val)) {
                            return this.el[action]();
                        }

                        this.el[action](val);
                        return this;
                    },
                    text: function (text) {
                        return this.passthrough(_TEXT_, text);
                    },
                    html: function (html) {
                        return this.passthrough(_HTML_, html);
                    },
                    val: function (val) {
                        return this.passthrough("val", val);
                    },
                    append: function (item) {
                        var target = item.el || item;
                        this.el.append(target);
                        return this;
                    },
                    attr: function (attr, val) {
                        if (isUndefined(val)) {
                            return this.el.attr(attr);
                        }
                        this.el.attr(attr, val);
                        return this;
                    },
                    remove: function () {
                        this.el.remove();
                        return this;
                    },
                    addClass: function (klass) {
                        this.el.addClass(klass);
                        return this;
                    },
                    removeClass: function (klass) {
                        this.el.removeClass(klass);
                        return this;
                    },
                    each: function (callback) {
                        return this.passthrough('each', callback);
                    },
                    click: function (callback) {
                        return this.passthrough(_CLICK_, callback);
                    },
                    live: function (event, callback) {
                        $engine(document).delegate(this.selector, event, callback);
                        return this;
                    },
                    parent: function () {
                        return simpleCart.$(this.el.parent());
                    },
                    find: function (selector) {
                        return simpleCart.$(this.el.find(selector));
                    },
                    closest: function (selector) {
                        return simpleCart.$(this.el.closest(selector));
                    },
                    tag: function () {
                        return this.el[0].tagName;
                    },
                    descendants: function () {
                        return simpleCart.$(this.el.find("*"));
                    },
                    submit: function() {
                        return this.el.submit();
                    },

                    create: function (selector) {
                        this.el = $engine(selector);
                    }
                }
            });
            simpleCart.ELEMENT._ = simpleCart.ELEMENT.prototype;

            // bind the DOM setup to the ready event
            simpleCart.ready(simpleCart.setupViewTool);

            // bind the input and output events
            simpleCart.ready(function () {
                simpleCart.bindOutlets({
                    total: function () {
                        return simpleCart.toCurrency(simpleCart.total());
                    }
                    , quantity: function () {
                        return simpleCart.quantity();
                    }
                    , items: function (selector) {
                        simpleCart.writeCart(selector);
                    }
                    , tax: function () {
                        return simpleCart.toCurrency(simpleCart.tax());
                    }
                    , taxRate: function () {
                        return simpleCart.taxRate().toFixed();
                    }
                    , shipping: function () {
                        return simpleCart.toCurrency(simpleCart.shipping());
                    }
                    , grandTotal: function () {
                        return simpleCart.toCurrency(simpleCart.grandTotal());
                    }
                });
                simpleCart.bindInputs([
                    {	  selector: 'checkout'
                        , event: 'click'
                        , callback: function () {
                            simpleCart.checkout();
                        }
                    }
                    , {	  selector: 'empty'
                        , event: 'click'
                        , callback: function () {
                            simpleCart.empty();
                        }
                    }
                    , {	  selector: 'increment'
                        , event: 'click'
                        , callback: function () {
                            // Prevent increment if availability is being checked
                            if(jQuery(this).closest('.itemRow').hasClass('io-checking-availability')) {
                                return false;
                            }
                            if(!jQuery(this).hasClass("disabled_cart_increment")) {
                                item = simpleCart.find(simpleCart.$(this).closest('.itemRow').attr('id').split("_")[1])
                                item.increment();
                                simpleCart.trigger("afterQtyChange", [item]);
                                simpleCart.update();
                            }
                        }
                    }
                    , {	  selector: 'decrement'
                        , event: 'click'
                        , callback: function () {
                            // Prevent decrement if availability is being checked
                            if(jQuery(this).closest('.itemRow').hasClass('io-checking-availability')) {
                                return false;
                            }
                            item = simpleCart.find(simpleCart.$(this).closest('.itemRow').attr('id').split("_")[1])
                            item.decrement();
                            simpleCart.trigger("afterQtyChange", [item]);
                            simpleCart.update();
                        }
                    }
                    , {	  selector: 'increment_acc'
                        , event: 'click'
                        , callback: function () {
                            let acc_id = jQuery(this).attr("data-rid");
                            let input = jQuery('.cart_acc_quantity_input[data-rid="'+acc_id+'"]');
                            let current_qty = parseInt(input.val());
                            let next_qty = current_qty + parseInt(input.attr("data-increment"));
                            input.val(next_qty).change();
                            if(!jQuery(this).closest(".dialog_acc_selectable_card").hasClass("selected")){
                                jQuery(this).closest(".dialog_acc_selectable_card").click();
                            }
                        }
                    }
                    , {	  selector: 'input_acc'
                        , event: 'change'
                        , callback: function () {
                            let min = parseInt(this.min);
                            let value = parseInt(this.value);
                            let increment = this.dataset.increment == 0 ? 1 :parseInt(this.dataset.increment);
                            let main_id = cart_acc_state.get_main_item_id();
                            let container = jQuery(".select_card_container");
                            let limit = container.data().limit;
                            let selected = simpleCart.get_total_selected();
                            let allowed = simpleCart.get_total_allowed();
                            let available = this.parentElement.parentElement.dataset.availability;
                            if(value > 0) {
                                if (this.dataset.rid == main_id) {
                                    available = this.dataset.availability;
                                    if (value % increment != 0 || value > available){
                                        this.value = this.dataset.old;
                                    } else if (value < min) {
                                        cart_acc_state.main_item_qty = min;
                                        this.value = min;
                                    } else {
                                        cart_acc_state.main_item_qty = value;
                                    }
                                } else if(allowed === "Unlimited"){
                                    if (value % increment != 0 || value > available) {
                                        this.value = this.dataset.old;
                                    } else if (value < min) {
                                        this.value = 0;
                                        jQuery(this).closest(".selected").toggleClass("selected");
                                    }
                                } else if (value % increment == 0 && limit > 0 && value / increment <= (allowed - selected)) {
                                    if (value < min) {
                                        this.value = 0;
                                        jQuery(this).closest(".selected").toggleClass("selected");
                                        //jQuery(this).parent().find("button,input").prop("disabled", true)
                                    }
                                } else if (value % increment != 0 || value > available) {
                                    this.value = this.dataset.old;
                                }
                            }else{
                                if (this.dataset.rid == main_id){
                                    this.value = min;
                                }else{
                                    jQuery(this).closest(".selected").toggleClass("selected");
                                    jQuery(this).parent().find("input,.simpleCart_decrement_acc").prop("disabled", true)
                                    this.value = 0;
                                }

                            }
                            jQuery(this).attr("data-old", this.value);
                            if(this.parentElement.classList.contains("cart_acc_main_qty")){
                                let main_input = jQuery(".cart_acc_main_qty input");
                                simpleCart.check_main_input(main_input);
                                // Update required accessories
                                simpleCart.update_main_required_qty(main_input);
                                let container = jQuery(".select_card_container")
                                if(container.attr("data-linkqty") == 1){
                                    container.attr("data-parentqty", main_input.val());
                                    jQuery(".select_card_container .simpleCart_select_card[data-linkqty='1']").each(function(){
                                        this.setAttribute("data-parentqty", main_input.val());
                                        if(this.classList.contains("selected")){
                                            const card_input = jQuery(this).find("input");
                                            card_input.val(parseInt(main_input.val() * parseInt(this.dataset.increment)));
                                        }
                                    });
                                }
                            }
                            simpleCart.can_add_more();
                            simpleCart.update_message();
                            simpleCart.update_buttons();
                        },
                    }
                    , {	  selector: 'decrement_acc'
                        , event: 'click'
                        , callback: function () {
                            let acc_id = jQuery(this).attr("data-rid");
                            let input = jQuery('.cart_acc_quantity_input[data-rid="'+acc_id+'"]');
                            let current_qty = parseInt(input.val());
                            let next_qty = current_qty - parseInt(input.attr("data-increment"));
                            input.val(next_qty).change();
                        }
                    }
                    , {	  selector: 'cancel_acc_dialog'
                        , event: 'click'
                        , callback: function () {
                            jQuery.fancybox.close();
                        }
                    }
                    , {	  selector: 'select_card'
                        , event: 'click'
                        , callback: function (e) {
                            if(!jQuery(this).hasClass("disabled_select_card")) {
                                // Only check hovered element if this is a real mouse event (not programmatic)
                                if (e.originalEvent && e.originalEvent.clientX !== undefined && e.originalEvent.clientY !== undefined) {
                                    let hovered_element = document.elementFromPoint(e.originalEvent.clientX, e.originalEvent.clientY);
                                    if (jQuery(hovered_element).is(".cart_acc_quantity_input, .cart_acc_quantity_control")) {
                                        return false;
                                    }
                                }
                                jQuery(this).toggleClass("selected");
                                let main_input = jQuery(".cart_acc_main_qty input");
                                if(cart_acc_state.is_first_state()) {
                                    simpleCart.check_main_input(main_input);
                                }
                                let selected_input = jQuery(this).find("input").first();
                                if (jQuery(this).hasClass("selected")) {
                                    if(this.dataset.linkqty == 1 && this.dataset.parentqty){
                                        let parent_qty = parseInt(this.dataset.parentqty);
                                        let increment = this.dataset.increment == 0 ? 1 : parseInt(this.dataset.increment);
                                        selected_input.val(parent_qty * increment).change();
                                    }else{
                                        let increment = selected_input.attr("data-increment") == 0 ? 1 : selected_input.attr("data-increment");
                                        selected_input.val(increment).change();
                                    }
                                } else {
                                    selected_input.val(0).change();
                                    jQuery(this).find("input,.simpleCart_decrement_acc").prop("disabled", true)
                                }

                            }
                        }
                    }
                    , {	  selector: 'back_acc_dialog'
                        , event: 'click'
                        , callback: function () {
                            const new_display = cart_acc_state.previous();

                            jQuery("#cart_acc_select_bottom").html(new_display);
                            simpleCart.update_parentqty_for_linkqty_choices();

                            if(cart_acc_state.is_first_state()){
                                jQuery(".simpleCart_back_acc_dialog").hide();
                                jQuery(".cart_acc_main_qty").show();
                                simpleCart.check_main_input(jQuery(".cart_acc_main_qty input"));
                            }
                            if(cart_acc_state.state_stack.length == 0){
                                jQuery(".simpleCart_next_acc_dialog").hide();
                                if(cart_acc_state.prev_states.length > 0){
                                    jQuery(".simpleCart_finish_acc_dialog").show();
                                    jQuery(".simpleCart_add_acc_dialog").hide();
                                }else{
                                    jQuery(".simpleCart_finish_acc_dialog").hide();
                                    jQuery(".simpleCart_add_acc_dialog").show();
                                }
                            }else{
                                jQuery(".simpleCart_next_acc_dialog").show();
                                jQuery(".simpleCart_finish_acc_dialog").hide();
                                jQuery(".simpleCart_add_acc_dialog").hide();
                            }

                            let required = parseInt(jQuery(".select_card_container").attr("data-required"));
                            if(required > 0){
                                jQuery(".simpleCart_next_acc_dialog").addClass("disabled_next");
                                jQuery(".simpleCart_finish_acc_dialog").addClass("disabled_finish");
                                jQuery(".simpleCart_add_acc_dialog").addClass("disabled_add");
                            }else{
                                jQuery(".simpleCart_next_acc_dialog").removeClass("disabled_next");
                                jQuery(".simpleCart_finish_acc_dialog").removeClass("disabled_finish");
                                jQuery(".simpleCart_add_acc_dialog").removeClass("disabled_add");
                            }
                            previous_path = jQuery(".select_card_container").attr("data-path");
                            simpleCart.remove_acc_from_selected(previous_path, jQuery(".select_card_container").attr("data"));
                            //simpleCart.check_total_selected(limit, required);
                            simpleCart.can_add_more();
                            simpleCart.update_progress();
                            simpleCart.update_message();
                        }
                    }
                    , {	  selector: 'next_acc_dialog'
                        , event: 'click'
                        , callback: function () {
                            if(!jQuery(this).hasClass("disabled_next")) {
                                //jQuery(".cart_acc_main_qty").hide()
                                jQuery(".cart_acc_main_qty .simpleCart_increment_acc").prop("disabled", true);
                                jQuery(".cart_acc_main_qty .simpleCart_decrement_acc").prop("disabled", true);
                                jQuery(".cart_acc_main_qty input").prop("disabled", true);
                                if(cart_acc_state.is_first_state()){
                                    cart_acc_state.confirm_screen_elements[0].qty = jQuery(".cart_acc_main_qty input").val();
                                }
                                jQuery(".select_card_container .selected").each(function(){
                                    let selected_rid = this.getAttribute("data");
                                    let selected_qty = parseInt(jQuery(this).find("input").val());
                                    simpleCart.add_acc_to_selected(
                                        this.getAttribute("data"),
                                        this.getAttribute("data-path"),
                                        selected_qty
                                    );
                                    cart_acc_state.add_sub_acc_required(this.parentElement.getAttribute("data-path"),this.getAttribute("data"), selected_qty);

                                    if(cart_acc_state.has_sub_state(selected_rid)){
                                        let sub_state = cart_acc_state.get_sub_state(selected_rid);
                                        if(sub_state.display_is_empty()){
                                            // Go through sub states and check if any are required. If they are add them.
                                            required_dropdown_states = sub_state.find_required_dropdown_states();
                                            for(let i = 0; i < required_dropdown_states.length; ++ i){
                                                cart_acc_state.stack_state(required_dropdown_states[i]);
                                            }
                                        }else{
                                            cart_acc_state.stack_state(sub_state);
                                            required_dropdown_states = sub_state.find_required_dropdown_states();
                                            for(let i = 0; i < required_dropdown_states.length; ++ i){
                                                cart_acc_state.stack_state(required_dropdown_states[i]);
                                            }
                                        }

                                    }
                                });
                                let new_display = cart_acc_state.load_next_state();

                                if(cart_acc_state.state_stack.length == 0){
                                    jQuery(".simpleCart_next_acc_dialog").hide();
                                    if(cart_acc_state.prev_states.length > 0){
                                        jQuery(".simpleCart_finish_acc_dialog").show();
                                        jQuery(".simpleCart_add_acc_dialog").hide();
                                    }else{
                                        jQuery(".simpleCart_finish_acc_dialog").hide();
                                        jQuery(".simpleCart_add_acc_dialog").show();
                                    }
                                }else{
                                    jQuery(".simpleCart_next_acc_dialog").show();
                                    jQuery(".simpleCart_finish_acc_dialog").hide();
                                    jQuery(".simpleCart_add_acc_dialog").hide();
                                }

                                jQuery(".simpleCart_back_acc_dialog").show();
                                jQuery("#cart_acc_select_bottom").html(new_display);
                                const container = jQuery(".select_card_container");
                                simpleCart.update_parentqty_for_linkqty_choices();
                                /*
                                if(cart_acc_state.current_state.required_iterations > 0){
                                    let split_path = container.attr("data-path").split("_");
                                    const parent = split_path.pop();
                                    const parent_path = split_path.join("_");
                                    const required_qty = container.attr("data-parentqty") ? parseInt(container.attr("data-parentqty")) * parseInt(container.attr("data-increment")) : parseInt(container.attr("data-increment"));
                                    simpleCart.add_acc_to_selected(
                                        parent,
                                        parent_path,
                                        Math.max(1, required_qty * parseInt(container.attr("data-required")))
                                    );
                                }
                                */

                                let required = parseInt(container.attr("data-required"));
                                if(required > 0){
                                    jQuery(".simpleCart_next_acc_dialog").addClass("disabled_next");
                                    jQuery(".simpleCart_finish_acc_dialog").addClass("disabled_finish");
                                    jQuery(".simpleCart_add_acc_dialog").addClass("disabled_add");
                                }else{
                                    jQuery(".simpleCart_next_acc_dialog").removeClass("disabled_next");
                                    jQuery(".simpleCart_finish_acc_dialog").removeClass("disabled_finish");
                                    jQuery(".simpleCart_add_acc_dialog").removeClass("disabled_add");
                                }
                                //simpleCart.check_total_selected(limit, required);
                                simpleCart.can_add_more();
                                simpleCart.update_progress();
                                simpleCart.update_message();
                            }
                        }
                    }
                    , {	  selector: 'finish_acc_dialog'
                        , event: 'click'
                        , callback: function () {
                            if(!jQuery(this).hasClass("disabled_finish")) {
                                //jQuery(".cart_acc_main_qty").hide();
                                jQuery(".cart_acc_main_qty .simpleCart_increment_acc").prop("disabled", true);
                                jQuery(".cart_acc_main_qty .simpleCart_decrement_acc").prop("disabled", true);
                                jQuery(".cart_acc_main_qty input").prop("disabled", true);
                                let fields = JSON.parse(jQuery("#cart_fields").text());
                                jQuery(".select_card_container .selected").each(function(){
                                    let selected_rid = this.getAttribute("data");
                                    if(this.getAttribute("data-dropdown") == 0) {
                                        let acc_image = jQuery(this).find(".acc_dialog_image")[0] ? jQuery(this).find(".acc_dialog_image")[0].src : "";
                                        let qty = parseInt(jQuery(this).find("input").val());
                                        simpleCart.add_acc_to_selected(
                                            this.getAttribute("data"),
                                            this.getAttribute("data-path"),
                                            qty
                                        );
                                        cart_acc_state.add_sub_acc_required(this.parentElement.getAttribute("data-path"), this.getAttribute("data"), qty);
                                    }
                                });
                                let confirm_screen_html = simpleCart.build_acc_dialog_confirm_screen(fields['accobj']);
                                //jQuery(".simpleCart_back_acc_dialog").addClass("hidden_back_button");
                                jQuery("#cart_acc_select_bottom").html(confirm_screen_html);
                            }
                        }
                    }
                    ,{	  selector: 'add_acc_dialog'
                        , event: 'click'
                        , callback: function () {
                            if(!jQuery(this).hasClass("disabled_add")) {
                                let fields = JSON.parse(jQuery("#cart_fields").text());
                                jQuery(".select_card_container .selected").each(function(){
                                    let selected_rid = this.getAttribute("data");
                                    if(this.getAttribute("data-dropdown") == 0) {
                                        let acc_image = jQuery(this).find(".acc_dialog_image")[0] ? jQuery(this).find(".acc_dialog_image")[0].src : "";
                                        let qty = parseInt(jQuery(this).find("input").val());
                                        simpleCart.add_acc_to_selected(
                                            this.getAttribute("data"),
                                            this.getAttribute("data-path"),
                                            qty
                                        );
                                        cart_acc_state.add_sub_acc_required(this.parentElement.getAttribute("data-path"), this.getAttribute("data"), qty);
                                    }
                                });
                                cart_acc_state.confirm_screen_elements[0].qty = jQuery(".cart_acc_main_qty input").val();
                                simpleCart.set_rental_obj_qty();
                                simpleCart.remove_zero_qty_accs(cart_acc_state.rental_obj);
                                fields.rental_obj = cart_acc_state.rental_obj;
                                fields.confirm_screen_elements = cart_acc_state.confirm_screen_elements;
                                if(jQuery("#dialog_cart_id").text()){
                                    let cart_item_id = jQuery("#dialog_cart_id").text();
                                    let item = simpleCart.find(cart_item_id);
                                    item.set("rental_obj", fields.rental_obj);
                                    item.set("confirm_screen_elements", fields.confirm_screen_elements);
                                    IoData.refresh_cached_item(cart_item_id, "cart");
                                    cartShow();
                                }else{
                                    simpleCart.add(fields);
                                }
                                jQuery.fancybox.close();
                            }
                        }
                    }
                    , {	  selector: 'open_item_acc'
                        , event: 'click'
                        , callback: function () {
                            if(!jQuery(this).hasClass("disabled_finish")) {
                                // TODO: Have this open confirm screen rather than new dialog.
                                // then make confirm_screen_elements.
                                cart_acc_state.clear();
                                const item = simpleCart.find(this.parentElement.parentElement.id.replace("cartItem_", ""));
                                const item_acc_obj = item.get("accobj");
                                cart_acc_state.rental_obj = IO_Rental.fromObject(item.get("rental_obj"));
                                simpleCart.build_acc_state(item_acc_obj, item_acc_obj.accessory_images);
                                cart_acc_state.confirm_screen_elements = item.get("confirm_screen_elements");
                                const confirm_screen_html = simpleCart.build_acc_dialog_confirm_screen(item_acc_obj);
                                //jQuery(".simpleCart_back_acc_dialog").addClass("hidden_back_button");
                                jQuery("#dialog_cart_id").text(item.id());
                                jQuery(".cart_acc_main_qty .simpleCart_increment_acc").prop("disabled", true);
                                jQuery(".cart_acc_main_qty .simpleCart_decrement_acc").prop("disabled", true);
                                jQuery(".cart_acc_main_qty input").prop("disabled", true);
                                jQuery("#cart_fields").text(JSON.stringify(item.fields()));
                                jQuery(".simpleCart_add_acc_dialog").html('<span class="io_acc_done">Done Editing</span>');
                                if(confirm_screen_html){
                                    jQuery("#cart_acc_select_bottom").html(confirm_screen_html);
                                    //jQuery(".cart_acc_main_qty").hide();
                                }else{
                                    cart_acc_state.load_main_states();
                                    let first_state = cart_acc_state.first();
                                    if (first_state) {
                                        jQuery("#cart_acc_select_bottom").html(first_state.display);
                                        let container = jQuery(".select_card_container")
                                        if(container.attr("data-linkqty") == 1){
                                            container.attr("data-parentqty", cart_acc_state.rental_obj.qty);
                                        }
                                    }
                                }

                                cartHide();
                                jQuery.fancybox.open(jQuery("#cart_acc_select_dialog"), {
                                    afterClose: function () {
                                        cart_acc_state.clear();
                                        //jQuery("#cart_acc_selected_display").empty();
                                        //jQuery("#cart_acc_required_main").empty();
                                        jQuery("#cart_acc_controls .io_button:not(.simpleCart_cancel_acc_dialog)").hide();
                                        jQuery(".simpleCart_next_acc_dialog").removeClass("disabled_next");
                                        jQuery(".simpleCart_finish_acc_dialog").removeClass("disabled_finish");
                                        jQuery(".simpleCart_add_acc_dialog").removeClass("disabled_add");
                                        jQuery(".cart_acc_main_qty").show();
                                        jQuery("#progress_message_all_added").hide();
                                        jQuery("#progress_message_add_more").hide();
                                        jQuery("#dialog_cart_id").empty();
                                    },
                                    closeBtn: false,
                                    autoSize:false,
                                    padding: 0,
                                    height:800,
                                    width:900,
                                    helpers: {
                                        overlay: {closeClick: false} // prevents closing when clicking OUTSIDE fancybox
                                    }
                                });
                            }
                        }
                    }
                    , {	  selector: 'confirm_screen_edit'
                        , event: 'click'
                        , callback: function () {
                            let state_index_path = this.dataset.state.split("_").map(Number);
                            let selection_index_path = this.dataset.selection.split("_").map(Number);
                            let editing_state = state_index_path.reduce((state, index) => state?.sub_states?.[index], { sub_states: cart_acc_state.states });
                            jQuery(".simpleCart_next_acc_dialog").show();
                            jQuery(".simpleCart_finish_acc_dialog").hide();
                            jQuery(".simpleCart_add_acc_dialog").hide();
                            jQuery(".simpleCart_progress").show();
                            simpleCart.update_progress();
                            simpleCart.update_message();
                            jQuery(".simpleCart_progress_outer").show();
                            cart_acc_state.current_state = editing_state;
                            jQuery("#cart_acc_select_bottom").html(editing_state.display).attr("data-editing", "1");
                            simpleCart.update_parentqty_for_linkqty_choices();
                            if(jQuery(".select_card_container").attr("data-required") > 0){
                                jQuery(".simpleCart_next_acc_dialog").addClass("disabled_next");
                                jQuery(".simpleCart_finish_acc_dialog").addClass("disabled_finish");
                                jQuery(".simpleCart_add_acc_dialog").addClass("disabled_add");
                            }

                            let current_selection = cart_acc_state.confirm_screen_elements;
                            let edit_mode = this.dataset.editMode || 'remove';
                            if(this.dataset.selection == "0"){
                                let selected_main_accessories_indices = this.dataset.mainAccessories.split("_").map(Number);
                                current_selection = current_selection[0].accessories;
                                // Sort indices descending so splicing doesn't shift later indices
                                selected_main_accessories_indices.sort((a, b) => b - a);
                                for(let i = 0; i < selected_main_accessories_indices.length; ++i){
                                    current_selection.splice(selected_main_accessories_indices[i], 1);
                                }
                            }else if(this.dataset.selection !== "none"){
                                let target_index = selection_index_path.pop();
                                for(let i = 0; i < selection_index_path.length; ++i){
                                    current_selection = current_selection[selection_index_path[i]].accessories;
                                }
                                if(edit_mode === 'clear'){
                                    // Clear the target element's children (e.g., re-picking choices in a group)
                                    current_selection[target_index].accessories = [];
                                }else if(edit_mode === 'clear-parent'){
                                    // Clear all siblings in the parent (e.g., editing one choice clears all choices in the group)
                                    current_selection.length = 0;
                                }else{
                                    // Default: remove the element entirely (e.g., removing an optional group)
                                    current_selection.splice(target_index, 1);
                                }
                            }
                            simpleCart.can_add_more();
                            simpleCart.update_message();
                            simpleCart.update_progress();
                        }
                    }
                    , {	  selector: 'duplicate_item'
                        , event: 'click'
                        , callback: function () {
                            let item = simpleCart.find(this.parentElement.parentElement.parentElement.id.replace("cartItem_", ""));
                            let duplicate = simpleCart.add(item.get("fields"));
                            let rental_obj = item.get("rental_obj");
                            rental_obj.cart_id = duplicate.get("id");
                            duplicate.set("rental_obj", rental_obj);
                        }
                    }
                    , {	  selector: 'remove_acc'
                        , event: 'click'
                        , callback: function () {
                            let rid = this.parentElement.parentElement.parentElement.className.replace("io_acc_selected_row row_", "");
                            cart_acc_state.unstack_state(rid);
                            jQuery('[data-required-parent="'+rid+'"]').remove();
                            // To remove required accessories as well
                            jQuery(this).parent().parent().parent().remove();
                        }
                    }
                    /* remove from cart */
                    , {	  selector: 'remove'
                        , event: 'click'
                        , callback: function () {
                            // Prevent remove if availability is being checked
                            if(jQuery(this).closest('.itemRow').hasClass('io-checking-availability')) {
                                return false;
                            }
                            simpleCart.find(simpleCart.$(this).closest('.itemRow').attr('id').split("_")[1]).remove();
                        }
                    }
                    /* cart timeslots */
                    , {	  selector: 'timeslots'
                        , event: 'change'
                        , callback: function(){
                            item_row = jQuery(this).closest(".itemRow");
                            item = simpleCart.find(item_row.attr("id").replace("cartItem_", ""));
                            IoData.timeslot_change(item);
                            rental_obj = item.get("rental_obj");
                            timeslot_name =getTimeslotName(item.get("timeslots"));
                            if(this.name.includes("start_timeslot")){
                                rental_obj.start_time = this.value;
                                setTimePicker(item, timeslot_name);
                            }else if(this.name.includes("end_timeslot")){
                                rental_obj.end_time = this.value;
                                setTimePicker(item, timeslot_name);
                            }else{
                                // Timeslot dropdown.
                                var [start_time, end_time] = break_timeslot_sel_range(this.value);
                                rental_obj.start_time = start_time;
                                rental_obj.end_time = end_time;
                                setTimeslotSelected(item, timeslot_name);
                            }
                            timeslotChange();
                        }
                    }
                    /* cart inputs */
                    , {	  selector: 'input'
                        , event: 'change'
                        , callback: function () {
                            // Prevent input change if availability is being checked
                            if(jQuery(this).closest('.itemRow').hasClass('io-checking-availability')) {
                                return false;
                            }
                            var $input = simpleCart.$(this),
                                $parent = $input.parent(),
                                classList = $parent.attr('class').split(" ");
                            simpleCart.each(classList, function (klass) {
                                if (klass.match(/item-.+/i)) {
                                    var field = klass.split("-")[1];
                                    var item = simpleCart.find($parent.closest('.itemRow').attr('id').split("_")[1]);
                                    // Trigger availability check if quantity changed
                                    if (field === 'quantity') {
                                        item.set(field, $input.val());
                                        let rental_obj = item.get("rental_obj");
                                        rental_obj.qty = item.quantity();
                                        // Update accessory quantities for separate units
                                        if (rental_obj.accessories && rental_obj.accessories.length > 0) {
                                            for (let i = 0; i < rental_obj.accessories.length; i++) {
                                                rental_obj.accessories[i].qty = item.quantity();
                                            }
                                        }
                                        item.set("rental_obj", rental_obj);
                                        simpleCart.trigger("afterQtyChange", [item]);
                                    }
                                    simpleCart.update();
                                    return;
                                }
                            });
                        }
                    }

                    /* here is our ioShelfItem add to cart button listener */
                    , { selector: 'ioShelfItem .item_add'
                        , event: 'click'
                        , callback:function() {
                            // Prevent adding to cart if availability is being checked
                            if(jQuery(this).closest('.io-checking-availability').length > 0) {
                                return false;
                            }
                            simpleCart.parse_html_and_add(this, false);
                        }
                    }/*
                    , { selector: 'accessories'
                        , event: 'click'
                        , callback:function() {
                            var $input = simpleCart.$(this),
                                $parent = $input.parent();
                            let item = simpleCart.find($parent.closest('.itemRow').attr('id').split("_")[1])
                            simpleCart.open_accessory_form(item)

                        }
                    }*/
                ]);
            });


            /*******************************************************************
             *	DOM READY
             *******************************************************************/
            // Cleanup functions for the document ready method
            // used from jQuery
            /*global DOMContentLoaded */
            if (document.addEventListener) {
                window.DOMContentLoaded = function () {
                    document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
                    simpleCart.init();
                };

            } else if (document.attachEvent) {
                window.DOMContentLoaded = function () {
                    // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                    if (document.readyState === "complete") {
                        document.detachEvent("onreadystatechange", DOMContentLoaded);
                        simpleCart.init();
                    }
                };
            }
            // The DOM ready check for Internet Explorer
            // used from jQuery
            function doScrollCheck() {
                if (simpleCart.isReady) {
                    return;
                }

                try {
                    // If IE is used, use the trick by Diego Perini
                    // http://javascript.nwbox.com/IEContentLoaded/
                    document.documentElement.doScroll("left");
                } catch (e) {
                    setTimeout(doScrollCheck, 1);
                    return;
                }

                // and execute any waiting functions
                simpleCart.init();
            }

            // bind ready event used from jquery
            function sc_BindReady () {

                // Catch cases where $(document).ready() is called after the
                // browser event has already occurred.
                if (document.readyState === "complete") {
                    // Handle it asynchronously to allow scripts the opportunity to delay ready
                    return setTimeout(simpleCart.init, 1);
                }else{
                    return setTimeout(simpleCart.init, 5);
                }

                // Mozilla, Opera and webkit nightlies currently support this event
                if (document.addEventListener) {
                    // Use the handy event callback
                    document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);

                    // A fallback to window.onload, that will always work
                    window.addEventListener("load", simpleCart.init, false);

                    // If IE event model is used
                } else if (document.attachEvent) {
                    // ensure firing before onload,
                    // maybe late but safe also for iframes
                    document.attachEvent("onreadystatechange", DOMContentLoaded);

                    // A fallback to window.onload, that will always work
                    window.attachEvent("onload", simpleCart.init);

                    // If IE and not a frame
                    // continually check to see if the document is ready
                    var toplevel = false;

                    try {
                        toplevel = window.frameElement === null;
                    } catch (e) {}

                    if (document.documentElement.doScroll && toplevel) {
                        doScrollCheck();
                    }
                }
            }

            // bind the ready event
            sc_BindReady();

            return simpleCart;
        };


    window.simpleCart = generateSimpleCart();

}(window, document));

/************ JSON *************/
var JSON;JSON||(JSON={});
(function () {function k(a) {return a<10?"0"+a:a}function o(a) {p.lastIndex=0;return p.test(a)?'"'+a.replace(p,function (a) {var c=r[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function l(a,j) {var c,d,h,m,g=e,f,b=j[a];b&&typeof b==="object"&&typeof b.toJSON==="function"&&(b=b.toJSON(a));typeof i==="function"&&(b=i.call(j,a,b));switch(typeof b) {case "string":return o(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);case "object":if (!b)return"null";
    e += n;f=[];if (Object.prototype.toString.apply(b)==="[object Array]") {m=b.length;for (c=0;c<m;c += 1)f[c]=l(c,b)||"null";h=f.length===0?"[]":e?"[\n"+e+f.join(",\n"+e)+"\n"+g+"]":"["+f.join(",")+"]";e=g;return h}if (i&&typeof i==="object") {m=i.length;for (c=0;c<m;c += 1)typeof i[c]==="string"&&(d=i[c],(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h))}else for (d in b)Object.prototype.hasOwnProperty.call(b,d)&&(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h);h=f.length===0?"{}":e?"{\n"+e+f.join(",\n"+e)+"\n"+g+"}":"{"+f.join(",")+
        "}";e=g;return h}}if (typeof Date.prototype.toJSON!=="function")Date.prototype.toJSON=function () {return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+k(this.getUTCMonth()+1)+"-"+k(this.getUTCDate())+"T"+k(this.getUTCHours())+":"+k(this.getUTCMinutes())+":"+k(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function () {return this.valueOf()};var q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
    p=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e,n,r={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},i;if (typeof JSON.stringify!=="function")JSON.stringify=function (a,j,c) {var d;n=e="";if (typeof c==="number")for (d=0;d<c;d += 1)n += " ";else typeof c==="string"&&(n=c);if ((i=j)&&typeof j!=="function"&&(typeof j!=="object"||typeof j.length!=="number"))throw Error("JSON.stringify");return l("",
    {"":a})};if (typeof JSON.parse!=="function")JSON.parse=function (a,e) {function c(a,d) {var g,f,b=a[d];if (b&&typeof b==="object")for (g in b)Object.prototype.hasOwnProperty.call(b,g)&&(f=c(b,g),f!==void 0?b[g]=f:delete b[g]);return e.call(a,d,b)}var d,a=String(a);q.lastIndex=0;q.test(a)&&(a=a.replace(q,function (a) {return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if (/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
    "]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return d=eval("("+a+")"),typeof e==="function"?c({"":d},""):d;throw new SyntaxError("JSON.parse");}})();


/************ HTML5 Local Storage Support *************/
(function () {if (!this.localStorage)if (this.globalStorage)try {this.localStorage=this.globalStorage}catch(e) {}else{var a=document.createElement("div");a.style.display="none";document.getElementsByTagName("head")[0].appendChild(a);if (a.addBehavior) {a.addBehavior("#default#userdata");var d=this.localStorage={length:0,setItem:function (b,d) {a.load("localStorage");b=c(b);a.getAttribute(b)||this.length++;a.setAttribute(b,d);a.save("localStorage")},getItem:function (b) {a.load("localStorage");b=c(b);return a.getAttribute(b)},
    removeItem:function (b) {a.load("localStorage");b=c(b);a.removeAttribute(b);a.save("localStorage");this.length=0},clear:function () {a.load("localStorage");for (var b=0;attr=a.XMLDocument.documentElement.attributes[b++];)a.removeAttribute(attr.name);a.save("localStorage");this.length=0},key:function (b) {a.load("localStorage");return a.XMLDocument.documentElement.attributes[b]}},c=function (a) {return a.replace(/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g,
    "-")};a.load("localStorage");d.length=a.XMLDocument.documentElement.attributes.length}}})();

function getContrastClass(rgbcolor) {
    let result = rgbcolor.match(/\d+/g);
    let hexcolor = "#" + result
        .map(x => ("0" + parseInt(x).toString(16)).slice(-2))
        .join("");
    hexcolor = hexcolor.replace('#','');
    let r = parseInt(hexcolor.substr(0,2),16);
    let g = parseInt(hexcolor.substr(2,2),16);
    let b = parseInt(hexcolor.substr(4,2),16);
    let yiq = ((r*299)+(g*587)+(b*114))/1000;
    return (yiq >= 128) ? 'top_text_dark' : 'top_text_light';
}

function open_date_select_alert_modal(){
    checkAvailDateClick();
}