﻿/***********************************************************************************************************
  TITLE:      MHD Product Selector Plugin
  
  AUTHOR:     Nathan Koch
  
  VERSION:    1.0
  
  REQUIRES:   jQuery v1.4
  
  OPTIONS:
  
  root: site root
  wsPath: path to web service
  wsMethodSelectAll: web service method that returns all products
  wsMethodSelectFiltered: web service method that returns products filtered by questions
  wsMethodSelectFilteredAndSorted: web service method that returns products both filtered and reordered
  productTemplateSource: textarea where the mustache template markup is stored
  resultsDiv: where the search results are populated via ajax
  propertyType: This is .NET metadata needed to be passed in on ws request
  sortHeader: contains the radio buttons used for sorting
  startOverButton: selector for button to go back to step 1
  resetButton: selector for button to reset selector back to initial state  
  
***********************************************************************************************************/

(function($) {
    $.fn.extend({
        productSelector: function(options) {
            // DEFAULTS
            // for descriptions see above
            var defaults = {
                root: "/",
                wsPath: "ws/ProductSearchEngine.asmx/",
                wsMethodSelectAll: "SelectAllAppliance",
                wsMethodSelectFiltered: "SelectApplianceWithFilter",
                wsMethodSelectFilteredAndSorted: "SelectApplianceWithFilter1",
                productTemplateSource: "textarea.product-template-source",
                resultsDiv: "div.results",
                propertyType: "MaytagHD.Domain.ApplianceProperty",
                sortHeader: ".product-results-header",
                startOverButton: ".startOver a",
                resetButton: "span.reset",
                onPopulate: function(results) { },
                onIterateProduct: function(element) { },
                onPopulateComplete: function(element) { }
            };
            options = $.extend(defaults, options);

            return this.each(function() {

                // VARIABLES

                // build the paths out of the root, path to web service, and method 
                var selectAllPath = options.root + options.wsPath + options.wsMethodSelectAll;
                var selectFilteredPath = options.root + options.wsPath + options.wsMethodSelectFiltered;
                var selectFilteredAndSortedPath = options.root + options.wsPath + options.wsMethodSelectFilteredAndSorted;
                var currentCategory = $(this).parent().attr("data-category").replace(/_/g, " ");

                // the value of the textare is mustache templated markup
                var productTemplate = $(options.productTemplateSource).val();

                // question inputs
                var $inputs = $(this).find("input");

                // div that is populated with material from web service
                var $results = $(options.resultsDiv);

                // radio buttons for sorting
                var $sortInputs = $(options.sortHeader).find("input");

                // restarts selector on step 1
                var $startOverButton = $(options.startOverButton);

                // resets selector to initial state
                var $resetButton = $(options.resetButton);

                var $tabs = $('.question-list').find('li');

                // initial sort status
                var activeSort = $sortInputs.filter(":checked").val();
                console.info("initial active sort is: ", activeSort);


                // FUNCTIONS

                // criteria is obtained from input name and values in the markup. 
                // input names are sourced directly from MaytagHD.Domain
                // category is provided via 
                var getCriteria = function() {
                    var inputArray = serializeInputs();
                    inputArray.push(assembleApplianceProperty("Category", currentCategory));
                    return inputArray;
                };

                // assemble an object that fits .NET's expectations on the back end
                var assembleApplianceProperty = function(name, value) {
                    var obj = {};
                    obj.Name = name;
                    obj.Value = value;
                    obj.__type = options.propertyType;
                    return obj;
                };

                // serialize radio buttons and checkboxes and reformat for ajax call
                var serializeInputs = function() {
                    var fields = $inputs.serializeArray();
                    var output = [];
                    _(fields).each(function(element, index, list) {
                        var property = assembleApplianceProperty(element.name, element.value.replace(/_/g, " "));
                        output.push(property);
                    });
                    return output;
                };

                // ajax call to web service - populates results div
                // using data that returns from web service processed through
                // mustache templating
                var populate = function(criteria) {
                    // if no criteria, override and return all
                    var criteriaData = criteria || []; // if criteria use it, otherwise empty array

                    // back-end expects JSON - attributes property of an output object
                    var output = {};

                    // if there is criteria, and it is not just an empty array
                    // use the filter & sort web service

                    methodType = selectFilteredAndSortedPath;
                    criteriaData = criteria;
                    output.compareType = activeSort;

                    output.attributes = criteriaData;
                    console.log("output sent to server: ", output);

                    var json = JSON.stringify(output);

                    $.ajax({
                        type: "POST",
                        url: methodType,
                        data: json,
                        contentType: "application/json; charset=utf-8",
                        dataType: "json",
                        success: function(result) {
                            clearResults();
                            iterateResults(result.d);
                            options.onPopulate.call(this, result.d);
                        }
                    });
                };

                // each time we populate the results div we need to clear it out
                var clearResults = function() {
                    // nuke the contents of the results div
                    // and replace with an <ol></ol>
                    $results.html("<ol></ol>");
                };

                // all iteration through results array from ws is done here
                var iterateResults = function(products) {
                    console.log("Number of products returned: ", products.length);
                    var $ol = $results.find("ol");
                    _(products).each(function(element, index, list) {
                        options.onIterateProduct.call(this, element);
                        var output = templatize(element);
                        $ol.append(output);
                    });
                    options.onPopulateComplete.call(this, $ol);
                };

                // renders a product object into a chunk of markup via mustache
                var templatize = function(product) {
                    var output = Mustache.to_html(productTemplate, product);
                    return output;
                };

                // we need to mark tabs as completed as the user clicks radio buttons
                var markCompleted = function(el) {
                    var getTab = '.' + $(el).parents(".question").attr('id') + '-tab';
                    var checkboxes = $(el).parents(".question").find(':checkbox');

                    var test = _(checkboxes).any(function(check) { return check.checked; });

                    if (el.checked) {
                        $(getTab).addClass("completed-q");
                    } else if (test === false) {
                        $(getTab).removeClass("completed-q");
                    }
                };

                // when the user answers a question it refilters/repopulates
                var getNewResults = function() {
                    activeSort = getActiveSort();
                    var criteria = getCriteria();
                    populate(criteria);
                };

                // this returns the current state of the sort
                var getActiveSort = function() {
                    var value = 0;
                    $sortInputs.each(function() {
                        if (this.checked) {
                            value = this.value;
                        }
                    });
                    return value;
                };

                // resets selector back to original state
                var resetForm = function() {
                    console.info("Reset form");
                    $tabs.each(function() {
                        $(this).removeClass('completed-q');
                    });
                    $inputs.each(function() {
                        this.checked = false;
                    });
                    getNewResults();
                };

                // EVENT LISTENERS

                // listens to questions - radio buttons and checkboxes, and gets new results
                $inputs.click(function(event) {
                    getNewResults();
                    markCompleted(this);
                });

                // listens to sort radio buttons and re-sorts, gets new results
                $sortInputs.click(function(event) {
                    getNewResults();
                });

                // start over - back to tab #1
                $startOverButton.click(function(event) {
                    resetForm();
                });

                // reset selector
                $resetButton.click(function(event) {
                    event.preventDefault();
                    resetForm();
                });


                // TRIGGERED ON PLUGIN LOAD
                console.info("[productselector] loaded");

                // initially populate with all results
                resetForm();
            });
        }
    });
})(jQuery);

