$(document).ready(function() {
    // The Webinfuse namespace is initialized in the document header

    // Helper methods //
    Webinfuse.add_to_cart_listener = function() {
        $("#cartSubmit").unbind('click.inStockAddToCart').bind('click.inStockAddToCart', function(event) {
            var selected_options = Webinfuse.get_selected_option_values(single_variant_with_options);
            // make sure there are genuine selections for all of the option selectors
            var abort = false;
            for (var k = 0; k < selected_options.length; k++) {
                var ov_id = selected_options[k];
                //  console.log(ov_id);
                if (ov_id == "-") {
                    abort = true;
                    var option_type = ordered_options[k][1];
                    alert("Please select a " + option_type);
                    event.preventDefault();
                }
            }

            // find the variant and get its url
            if (!abort) {
                var variant_array = Webinfuse.get_variants_with_options(Webinfuse.depvals, selected_options);
                if (variant_array.length == 0) {
                    event.preventDefault();
                    alert("There is no product matching your selection. Please try another combination of options.");
                }
            }
        });
    };

    // On page load, if the variant being displayed is out of stock, the following deactivates the add-to-cart form
    // and messages the user. Subsequent calls of the method will re-activate/deactivate as appropriate.
    Webinfuse.cartQuantityListener = function() {
        var q = $("input[name^='variant']");
        if (out_of_stock) {
            q.val("");
            q.attr('disabled', true);
            $("#cartSubmit").bind('click.addToCart', function(event) {
                event.preventDefault();
                alert("We're sorry, but this item is out of stock.");
            });
        } else {
            q.attr('disabled', '');
            $("#cartSubmit").unbind('click.addToCart');
            Webinfuse.add_to_cart_listener();
        }
    };

    // Called by the listener on the option selectors when all the selectors for the current product have values.
    Webinfuse.variant_selector_listener = function() {
        var selected_options = Webinfuse.get_selected_option_values(single_variant_with_options);
        // make sure there are genuine selections for all of the option selectors. If there isn't, message the user
        // to make the appropriate selector choice, and reset the product details to the default view.
        var abort = false;
        for (var k = 0; k < selected_options.length; k++) {
            var ov_id = selected_options[k];
            if (ov_id == "-") {
                Webinfuse.reset_product_view();
                abort = true;
                var option_type = ordered_options[k][1];
                alert("Please select a " + option_type);

            }
        }
        // find the variant and update the view
        if (!abort) {
            var variant_array = Webinfuse.get_variants_with_options(Webinfuse.depvals, selected_options);
            if (variant_array.length == 0) {
                Webinfuse.reset_product_view();
                alert("There is no product matching your selection. Please try another combination of options.");
                Webinfuse.update_view(Webinfuse.depvals[0]);
            } else {
                Webinfuse.update_view(variant_array[0]);
            }
        }
    };


    Webinfuse.update_view = function(variant, reset_flag) {
        if(!reset_flag){
            var reset_flag = false;
        }
        var default_variant = Webinfuse.depvals[0];
        var raw_price;
        var formatted_price;

        if(!reset_flag){
            if (variant["price"] != null) {
                $(".price").html("");
                raw_price = $("<p>" + variant["price"] + "</p>");
                formatted_price = raw_price.formatNumber({format:"$###.00", locale:"us"});
                $(".price").html("<span>Price: </span>" + formatted_price.text());
            } else {
                $(".price").html("");
                raw_price = $("<p>" + default_variant["price"] + "</p>");
                formatted_price = raw_price.formatNumber({format:"$###.00", locale:"us"});
                $(".price").html("<span>Price: </span>" + formatted_price.text());
            }

            if (variant["sku"] != null) {
                $(".sku").html("");
                $(".sku").html("<span>SKU: </span>" + variant["sku"]);
            } else {
                $(".sku").html("");
                $(".sku").html("<span>SKU: </span>" + default_variant["sku"]);
            }

        } else {
           $(".price").html("");
           $(".sku").html("");
        }

        if (variant["desc"] != null) {
            $("#mainProdDesc").html("");
            $("#mainProdDesc").html(variant["desc"]);
        } else {
            $("#mainProdDesc").html("");
            $("#mainProdDesc").html(default_variant["desc"]);
        }


        if (variant["main_image"] != null) {
            $("#prodMainImage").attr("src", "/data/catalog/" + variant["main_image"]);
        } else {
            $("#prodMainImage").attr("src", "/data/catalog/" + default_variant["main_image"]);
        }
        if (variant["thickbox_image"] != null) {
            $("#mainProdThickbox").attr("href", "/data/catalog/" + variant["thickbox_image"]);
        } else {
            $("#mainProdThickbox").attr("href", "/data/catalog/" + default_variant["thickbox_image"]);
        }

        if(Webinfuse.item_edit_mode){
            // start with the requested variant
            // determine if the variant is a line-item in the current cart
            //      if yes, load it qua line item
            //      if no, load it as a new item to add to cart, and change submit button

            //var quantity_input = $("input[name^='line_item']").length > 0 ? $("input[name^='line_item']") : $("input[name^='variant']");
            var quantity_input = $("input[class*='productViewInput']");
            // li_id will be undefined if there isn't a line item for the variant in teh line_items collection.break
            var li_id = Webinfuse.line_items["line_item_id_" +variant["id"]];
            if(typeof(li_id) != "undefined"){
                var li_quant = Webinfuse.line_items["line_item_quantity_" + variant["id"]];
                var li_name = "line_item[" + li_id + "][quantity]";
                var li_id_for_input = "variant[" +variant["id"] + "][quantity]";
                quantity_input.attr("id", li_id_for_input);
                quantity_input.attr("name", li_name);
                quantity_input.val(li_quant);
                $("#cartSubmit").val("update cart");
            } else {
                 var v_id = "variant[" + variant["id"] + "][quantity]";
                var v_name = "variant[" + variant["id"] + "][quantity]";
                quantity_input.attr("id", v_id);
                quantity_input.attr("name", v_name);
                quantity_input.val("");
                $("#cartSubmit").val("add to cart");
            }
        } else {
            var q = $("input[name^='variant']");
            if(q.length > 0){
                var v_id = "variant[" + variant["id"] + "][quantity]";
                var v_name = "variant[" + variant["id"] + "][quantity]";
                q.attr("id", v_id);
                q.attr("name", v_name);
                q.val("");
            }
        }

        // additional views
        $("#prodMoreViews3").html("");
        var cloned_scene_views = $("#av_variant_" + variant["id"]).clone(true);
        $("#prodMoreViews3").append(cloned_scene_views);
        // swap classes on tbox links: TBOX=>thickbox
        $("#prodMoreViews3 a.TBOX").each(function(i){
            $(this).removeClass("TBOX").addClass("thickbox");
            var t_rel = $(this).attr("rel");
            // chop off trailing -TBOX of rel attribute and reattach
            var pruned_rel = t_rel.substring(0, t_rel.length-5);
            $(this).attr("rel", pruned_rel);
        });
        // re-apply the thickbox function but ONLY to the additional views swapped in
        tb_init('#prodMoreViews3 a.thickbox');

        // complimentary items
        $("#complimentaryItems").html("");
        var cloned_comp_items = $("#rav_variant_" + variant["id"]).clone(true);
        $("#complimentaryItems").append(cloned_comp_items);

        // cross sells
        $("#prodCrossSells").html("");
        var cloned_ci_items = $("#cav_variant_" + variant["id"]).clone(true);
        $("#prodCrossSells").append(cloned_ci_items);

        Webinfuse.stock_manager(variant);
        $("#add-to-cart-message").fadeOut();
        $("#update-cart-message").fadeOut();
    };

    // Handles the activation/de-activation of the add to cart form based on the stock quantity of the current variant.
    Webinfuse.stock_manager = function(vrnt) {
        var v;
        if (vrnt) {
            v = vrnt;
        } else {
            v = Webinfuse.depvals[0];
        }

        var add_to_cart_input = $("input[class*='quantity productViewInput']");
        if (!v["in_stock"]) {
            $("#outOfStock").show();
            $("#callForPricing").hide();
            add_to_cart_input.hide();
            $("#quantitySpan").hide();
            $("#cartSubmit").attr("disabled", true);
            $("#cartSubmit").hide();
        } else if (v["in_stock"] && v["price"] == 0.0) {
            $("#outOfStock").hide();
            $("#callForPricing").show();
            add_to_cart_input.hide();
            $("#cartSubmit").attr("disabled", true);
             $("#cartSubmit").hide();
        } else {
            $("#callForPricing").hide();
            $("#outOfStock").hide();
            $("#quantitySpan").show();
            add_to_cart_input.show();
            $("#cartSubmit").show();
            $("#cartSubmit").attr("disabled", false);
        }
    };

    Webinfuse.reset_product_view = function() {
        var default_variant = Webinfuse.depvals[0];
        Webinfuse.update_view(default_variant, true);
    };

    // Removes the active class and sets the selector to disabled for all selectors to the right
    // of the selector specified by the 1-based index of changed_selector_number. Specify a boolean
    // as the last param to have the function also disable the *next* selector and not just remove its
    // active class (the get_selected_option_values() function only looks at active selectors).
    Webinfuse.reset_trailing_selectors = function(changed_selector_number, total_no_of_selectors, disable) {
        var counter_from_current = changed_selector_number;
        while (counter_from_current <= total_no_of_selectors) {
            var selector_to_deactivate = $("#option_priority_" + (counter_from_current + 1));
            if (selector_to_deactivate.length > 0) {
                selector_to_deactivate.removeClass("active");
                selector_to_deactivate.removeOption(/./);
                selector_to_deactivate.addOption("-", "please select");
                selector_to_deactivate.selectOptions("-", true);
                if (!disable && counter_from_current == changed_selector_number) {
                    selector_to_deactivate.attr("disabled", "");
                } else {
                    selector_to_deactivate.attr("disabled", true);
                }
            }
            counter_from_current++;
        }
    };

    // Builds the options array for a selector. The selector that it is built for is determined by the number of
    // selected_options passed in. E.g., if there are 5 option selectors, and selected_options.length == 2, the option
    // values for the 3rd option selector will be built. In more detail: selected_options contains an array of all of the selected
    // option_values from the active selectors, ordered in terms of their corresponding option-priority. So
    // if the product has 3 options ordered as Size, Colour, Fabric, and the user has selected two criteria
    // to search for at this point (say, medium-Size and red-Colour), then the selected_options will look like
    // [3, 19], and corresponds to option_value medium.id and option_value red.id.
    Webinfuse.build_options_for_variants_and_selected = function(variants, selected_options, total_options_size) {

        // debug notes: variants is the set of variants corresponding to the set of selected selectors

        // for each variant, pull the option values from its option at options[selected_options.length],
        // and build an options array from them. The variant's option-values are ordered in terms of the parent option
        // priority, allowing this type of simple look-up.
        var options_hash = {};
        // With the updated code, a selection/edit could be made that matches value in the currently active selectors. If
        // so, need to check if the selected_opts length is the same as the total opt size to prevent scanning beyond the
        // end of the options array.
        var sel_opt_len = selected_options.length == total_options_size ? selected_options.length - 1 : selected_options.length;

        // all this is doing is building is grabbing a single option-value per variant
        for (var i = 0; i < variants.length; i++) {
            var op_id = variants[i]["options"][sel_opt_len][1];
            var op_name = variants[i]["options"][sel_opt_len][2];
            options_hash[op_id] = op_name;
        }
        return options_hash;
    };

    Webinfuse.get_selected_option_values = function(is_single_variant_select) {
        var selected_options = $("select[class*='dynamicOptionSelectors active']");
        var selected_ids = new Array(selected_options.length);
        selected_options.each(function(i) {
            var sel_el = $(this);
            var s_val = sel_el.val();

            // need to find a way to allow add to cart for single variant option combos
            if (!is_single_variant_select) {
                if (this.options.length > 1) {
                    if (s_val) {
                        selected_ids[i] = s_val;
                    }
                }
            } else {
                if (this.options.length > 0) {
                    if (s_val) {
                        selected_ids[i] = s_val;
                    }
                }
            }
        });
        return selected_ids;
    };

    Webinfuse.get_variants_with_options = function(variants, array_of_selected_ids) {
        var matched_variants = [];

        // Loop through the array of selected ids, on the first pass get all that match the first ov.id.
        // On subsequent passes, filter the results of the first pass by the second ov.id, etc.
        var counter = 0;
        while (counter < array_of_selected_ids.length) {
            // if it is first pass, collect all matching variants by the first selected ov.id
            if (counter == 0) {
                for (var inner_counter = 0; inner_counter < variants.length; inner_counter++) {
                    var current_variant = variants[inner_counter];
                    if (Webinfuse.variant_has_option_value(current_variant.options, array_of_selected_ids[counter], counter)) {
                        matched_variants.push(current_variant);
                    }
                }
            } else {
                // filter passes
                var matched_var_initial_size = matched_variants.length;

                for (var c = 0; c < matched_var_initial_size; c++) {
                    if (Webinfuse.variant_has_option_value(matched_variants[c].options, array_of_selected_ids[counter], counter)) {
                        // keep it
                    } else {
                        matched_variants[c]["to_remove"] = true;
                    }
                }
            }
            counter++;
        }

        var mvs = [];
        for (var b = 0; b < matched_variants.length; b++) {
            if (matched_variants[b]["to_remove"]) {
                // do nothing
            } else {
                mvs.push(matched_variants[b]);
            }
        }

        // since the variants are objects, and they are passed by ref, have to remove the
        // temp to_remove flag added above or else the next time they are operated on most
        // will be flagged as to_remove....
        for (var p = 0; p < variants.length; p++) {
            if (variants[p]["to_remove"]) {
                variants[p]["to_remove"] = false;
            }
        }

        // return matched_variants
        return mvs;
    };

    Webinfuse.variant_has_option_value = function(variant_options, selected_id, option_to_query) {
        var i = variant_options.length;
        while (i--) {
            if (variant_options[option_to_query][1] == parseInt(selected_id)) {
                return true;
            }
        }
        return false;
    };

    Webinfuse.populate_selector = function(slctr_to_fetch_number, selected_id, slctd_opt_vals, vrnts_with_opts) {
        // set the id up seperately as this is re-used below
        var selector_id = "#option_priority_" + slctr_to_fetch_number;
        var selector_to_populate = $(selector_id);
        // clean it out in case there are values already there from previous variants/option-combos
        selector_to_populate.removeOption(/.*/);

        var options_for_select = Webinfuse.build_options_for_variants_and_selected(vrnts_with_opts, slctd_opt_vals, ordered_options.length);
        selector_to_populate.addOption("-", "please select");
        selector_to_populate.addOption(options_for_select);

        if (selected_id == "-") {
            selector_to_populate.selectOptions("-", true);
        } else {
            var target_option = $(selector_id + " option[value=" + selected_id + "]");
            // Webkit will delete all of the selector's options below if the option being queried
            // doesn't exist, so we need a guard against that
            if( target_option.length != 0 )  {
                selector_to_populate.selectOptions(selected_id, true);
            }
        }
        selector_to_populate.addClass("active");
        selector_to_populate.attr("disabled", "");
    };

    // ################################### main begins here, so to speak ########################################### //

    Webinfuse.stock_manager();
    Webinfuse.cartQuantityListener();

    $(".dynamicOptionSelectors").change(function(event) {
        var selector_id = event.target.id;
        var opt_priority = parseInt(selector_id.split("_")[2]);

        // Determine if all the selectors have legit selections.
        var selected_options = Webinfuse.get_selected_option_values();
        var sel_opt_all_numeric = true;

        for(var i = 0; i < selected_options.length; i++){
            if( isNaN( parseInt(selected_options[i] )) ){
                sel_opt_all_numeric = false;
            }
        }
        // If all the selectors for the options have been used, get the variant that has the selected combination of
        // opt-vals and update the view with its details
        if ( (opt_priority == ordered_options.length) || (sel_opt_all_numeric && selected_options.length == ordered_options.length) ) {
            Webinfuse.variant_selector_listener();
        } else {
            // if the current selector's value == "-", then the next selector and all following it need to be reset and deactivated
            var current_selector = $("#" + selector_id);
            if (current_selector.length > 0) {
                if (current_selector.val() == "-") {
                    Webinfuse.reset_trailing_selectors(opt_priority, ordered_options.length, true);
                    Webinfuse.reset_product_view();
                } else {

                    //  At this point, the code should first try to retrieve a variant based on the values of the active selectors
                    // - if no variants are found, then all selectors after the toggled one must be reset, and the next one will
                    //  be populated with the values for the given variants with option values for the selectors up to and
                    // including the toggled one.

                    var selected_option_values = Webinfuse.get_selected_option_values(single_variant_with_options);

                    // This should really return the variants that have the option-values of the lower priority selectors.
                    // Ergo, if we pop off the last value contained in selected_option_values....
                    var sel_opt_of_toggled_selector;
                    if(selected_option_values.length > 1){
                        sel_opt_of_toggled_selector = selected_option_values.pop();
                    } else {
                        sel_opt_of_toggled_selector = selected_option_values[0];
                    }

                    // now get the variants who possess values for all the options except for the one just toggled (unless it is
                    // the first one)
                    var variants_with_selected_options = Webinfuse.get_variants_with_options(Webinfuse.depvals, selected_option_values);

                    // now put back the toggled one so that when populate_selector is called below it will be able to
                    // reselect the value present in the toggled selector after it was toggled.
                    selected_option_values.push(sel_opt_of_toggled_selector);

                    // if variants_with_selected_options is empty here, then get_variants_with_options should be called
                    // again but with only the selected_option_values of the changed selector and those prior to it (otherwise
                    // the code will likely try to find options for which there are no variants). The rest must be reset & deactivated.
                    if (variants_with_selected_options.length == 0) {
                        // set all the selectors after the current one as inactive in order to fullfil the requirement that
                        // get_variants_with_options should be called again but with only the selected_option_values of the
                        // changed selector and those prior to it.
                        Webinfuse.reset_trailing_selectors(opt_priority, ordered_options.length, true);
                        selected_option_values = Webinfuse.get_selected_option_values(single_variant_with_options);
                        variants_with_selected_options = Webinfuse.get_variants_with_options(Webinfuse.depvals, selected_option_values);
                        Webinfuse.reset_product_view();
                    } else {
                        // At this point, the selector that was toggeled and all those following it need to have their
                        // values constrained by the matching variants. So if there are two options - color and size -
                        // and size was just changed, then the size options should be reset to whatever size values are
                        // present on the variants matching the options for the currently selected color. BUT, that is
                        // not currently happening. What seems to be taking place is that only the value for size for
                        // the first variant that matches is being used.

                        // need to store the value of the selectors *after* the current one as we need to set them back to
                        // their current values after their option-values are rebuilt from matching variants. To do this,
                        // re-use the selected_option_values array from above, but shift off the values for the selectors
                        // prior to and including the currently active one. Also need to make a deep copy of the selected_ids
                        // array so that it doesn't get borked here by the shift operation.
                        var remainder_cloned_selected_ids = selected_option_values.slice();
                        var number_to_shift = opt_priority;
                        while (number_to_shift > 0) {
                            remainder_cloned_selected_ids.shift();
                            number_to_shift--;
                        }
                    }

                    // if cloned_selected_ids exists we want to repopulate the following selectors with those values.
                    // if it doesn't, just populate the next one and leave the rest (since they've been turned off already).
                    if (remainder_cloned_selected_ids && remainder_cloned_selected_ids.length > 0) {
                        var remainder_cloned_selected_ids_length = remainder_cloned_selected_ids.length;
                        var opt_priority_counter = opt_priority;
                        while (remainder_cloned_selected_ids_length > 0) {
                            var next_opt_priority_number = opt_priority + 1;
                            Webinfuse.populate_selector(next_opt_priority_number, remainder_cloned_selected_ids.shift(), selected_option_values, variants_with_selected_options);
                            opt_priority_counter++;
                            remainder_cloned_selected_ids_length--;
                        }
                        // and now update the product details with the matched variant's details
                        Webinfuse.variant_selector_listener();
                    } else {
                        var next_opt_pri_num = opt_priority + 1;
                        Webinfuse.populate_selector(next_opt_pri_num, "-", selected_option_values, variants_with_selected_options);
                    }
                }
            }
        }
    });

    // Filter the options after the first by the default variant's option for the first selector
    $(".dynamicOptionSelectors.first").each(function(){
        $(this).trigger('change');
    });
});
