﻿/// <reference path="~/Standard/Core/Javascript/Relational.Standard.Core.js" />
/// <reference path="~/Standard/Core/Javascript/jquery.js" />

(function ($) {


    $.fn.facetSearch = function (options) {

        var defaults = {}; // set defaults in vb
        var config = $.extend(defaults, options);
        this.each(function () {

            var self = this, $self = $(this);

            var $facetSearchState = $(".FacetSearchState", self);
            var $facetFilters = $("div.FacetFilter", self);
            var $facetStateDisplay = $("div.FacetStateDisplay", self); // includes anything that might need to adjust to the current state: filters, summary, pager, etc
            var $facetStateDisplayOnLoad = $("div.FacetStateDisplayOnLoad", self); // controls that need to be told to update their state on first load (i.e. not checkboxlists because they come pre-populated with their correct state from the server)
            var $facetSearchResultCount = $("span.FacetSearchResultCount", self);
            var $facetSearchResultSum = $("span.FacetSearchResultSum", self);
            var $facetSearchSummary = $("div.FacetSearchSummary", self);
            var $facetSearchNoResults = $("div.FacetSearchNoResults", self);
            var $facetSearchPager = $("div.FacetSearchPagerContainer", self), facetSearchPager = $facetSearchPager[0];
            var $facetSearchInstructions = $("div.FacetSearchInstructions", self);
            var $databoundTargetControl = $("div.DataboundTargetControl", self);
            var $searchResults = $("div.SearchResults", self);

            var state = { // Stores the user's current selections. Used both to pass to server and to store in cookie.
                filters: [],
                page: 1,
                sortField: config.defaultSortField,
                sortDirection: config.defaultSortDirection
            };

            $self
                .bind("clear", clear)
                .bind("pageChanged", pageChanged)
                .bind("sortChanged", sortChanged)
                .bind("stateChanged", stateChanged)
                .bind("dataBind", dataBind)
                .bind("dataBound", dataBound)
                .bind("targetControlDatabound", targetControlDatabound);

            // PUBLIC FUNCTIONS & PROPERTIES

            self.getState = function () { return state; }
            self.restoreState = function () { return restoreState(); }
            self.noFiltersActive = function () { return noFiltersActive(); }

            self.getPageSize = config.pageSize;

            self.sortBy = function (sortField, sortDirection) { return sortChanged(null, sortField, sortDirection); }

            self.getIDs = function () {
                // Request list of IDs from server
                var result;
                $.ajax({
                    url: $r.cleanHref(window.location),
                    async: false, // need to get result back before continuing
                    type: "POST",
                    data: {
                        containerId: self.id,
                        action: "getIDs",
                        state: JSON.stringify(state)
                    },
                    success: function (msg) {
                        result = msg;
                    }, // success
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        $r.showError(XMLHttpRequest, errorThrown);
                        return errorThrown + ' ' + textStatus;
                    } // error
                });
                return result;
            };

            // PRIVATE FUNCTIONS


            function initialize() {
                restoreState();
                // Check if filters are ready (e.g. checkboxlists databound)
                var checkForFiltersReadyInterval = setInterval(function () {
                    filtersReady = true;
                    $facetFilters.each(function () {
                        if (!$(this).data("ready")) filtersReady = false;
                    });
                    if (filtersReady) {
                        clearInterval(checkForFiltersReadyInterval);
                        if (facetSearchPager) facetSearchPager.setPage(state.page); // new search - always go back to page 1
                        getState();
                        // Have summary, maps, etc. display state on first load
                        $facetStateDisplayOnLoad.each(function () {
                            var $el = $(this);
                            var t = setTimeout(function () { $el.trigger("displayState", [state]); }, 1);
                        });
                        // Continue databinding
                        if (config.clientDataBind) {
                            $self.trigger("dataBind");
                        } else {
                            initializeStateDisplay();
                        }
                    }
                }, 100);
                $self.trigger("postInitialize");
            }

            function noFiltersActive() {
                // Returns true if none of the filters has a selection
                var result = true;
                if (state.filters) {
                    $.each(state.filters, function () {
                        var filterState = this;
                        var $filter = $("#" + filterState.clientId);
                        var value = filterState.value;
                        if (value && value.length > 0) result = false; // found something with a value (textbox or checkboxlist)
                        // Range filter - not tested
                        //if (filterState.value.lowValue != undefined || filterState.value.highValue != undefined) {
                        //    if (!$filter[0].isNullState()) result = false; // range filter - return false if it's been changed 
                        //};
                    });
                };
                return result;
            }

            function saveState() {
                $.cookie((self.id + "_state").toLowerCase(), JSON.stringify(state), { path: '/' }); // Cookie name needs to be kept in sync with FacetSearch.vb
                $facetSearchState.val(JSON.stringify(state));
            }

            function restoreState() {
                // 1) TODO - why isn't the cookie valid here on full page refresh? the cookie should get set by the server
                // 2) TODO - add a setting to take the initialstatejson - if that value exists, init our state and set initstate = true (ignore state for the future)
                // Check cookie
                if (config.persistFilters) {
                    stateCookie = $.cookie((self.id + "_state").toLowerCase()); // Cookie name needs to be kept in sync with FacetSearch.vb
                    if (!!stateCookie) { state = JSON.parse(stateCookie); }
                }
                return state;
            }

            function sortChanged(event, sortField, sortDirection) {
                state.sortField = sortField;
                state.sortDirection = sortDirection;
                if (facetSearchPager && facetSearchPager.setPage) facetSearchPager.setPage(1); // new sort - always go back to page 1
                saveState();
                $self.trigger("dataBind");
                if (event) event.stopPropagation;
            }

            function stateChanged(event) {
                //$r.showProgress(self.id);
                var t = setTimeout(function () {
                    if (facetSearchPager) facetSearchPager.setPage(1); // new search - always go back to page 1
                    getState();
                    saveState();
                    updateStateDisplay();
                    $self.trigger("dataBind");
                }, 1);
                if (event) event.stopPropagation;
            }

            function pageChanged(event) {
                if (facetSearchPager) state.page = facetSearchPager.getPage();
                saveState();
                $self.trigger("dataBind");
                if (event) event.stopPropagation;
            }

            function getState() {
                // Get current state: Ask each filter about its current state. 
                // Could be a string [for a textbox], an array of IDs [for a checkboxlist or autocompletextab] etc.
                state.filters = []; // reset filter state
                $facetFilters.each(function () {
                    var filter = this;
                    state.filters.push({
                        id: filter.getId, // server-side control id, e.g. Sectors
                        clientId: filter.id, // client-side element id e.g. ctl00_ctl00_Content_Content_Sectors_FacetCheckboxlistFilterContainer
                        title: filter.getTitle, // friendly title, e.g. Sector
                        value: filter.getState() // text value (of a textbox) or array of values (for a checkboxlist etc)
                    });
                });
                if (config.searchTextboxSelector && $(config.searchTextboxSelector).length > 0) {
                    // push the state of the SearchPageTextbox onto the state
                    // TODO - decide if we need server side id & title - replace string constants
                    var filter = $(config.searchTextboxSelector)[0];
                    state.filters.push({
                        id: filter.getId,
                        clientId: filter.id,
                        title: filter.getTitle,
                        value: filter.getState()
                    });
                }
                if (facetSearchPager) state.page = facetSearchPager.getPage();
                $facetSearchState.val(JSON.stringify(state));
            }

            function initializeStateDisplay() {
                // Look up the result count in order to initialize the pager
                showResultCount();
                // Ask each elements that display state UI, and that don't initialize themselves on the server on load, to adjust to the current state
                $facetStateDisplay.each(function () {
                    var $el = $(this);
                    var t = setTimeout(function () {
                        $el.trigger("initializeState", [state]);
                    }, 1);
                });
            }

            function updateStateDisplay() {
                // Ask each elements that display state UI to adjust to the current state (e.g. checkbox lists update counts, summary display summary, etc.)
                showResultCount();
                showResultSums();
                $facetStateDisplay.each(function () {
                    var $el = $(this);
                    var t = setTimeout(function () {
                        $el.trigger("displayState", [state]);
                    }, 1);
                });
            }

            function dataBind(event) {
                var noFilters = noFiltersActive();
                if (config.showAllByDefault == true || noFilters == false) {
                    // We're showing all or some results
                    $facetSearchInstructions.hide();
                    if (config.clientDataBind) {
                        // Request data and bind it on the client
                        $.ajax({
                            url: $r.cleanHref(window.location),
                            type: "POST",
                            data: {
                                containerId: self.id,
                                action: "search",
                                state: JSON.stringify(state)
                            },
                            success: function (msg) {
                                var data = JSON.parse(msg);
                                dataBindChildren(data);
                            }, // success
                            error: function (XMLHttpRequest, textStatus, errorThrown) {
                                $r.showError(XMLHttpRequest, errorThrown + ' ' + textStatus);
                            } // error
                        }); // ajax
                    } else {
                        dataBindChildren(); // children just need state rather than data, since they databind on the server
                    }
                } else {
                    // Show search instructions
                    $facetSearchInstructions.show();
                    $facetSearchNoResults.hide();
                    $facetSearchPager.hide();
                    // Show zero results
                    $facetSearchResultCount.html('...');
                    $facetSearchResultSum.html('...');
                    // Clear targets
                    $databoundTargetControl.html('');
                    var $facetTargets = $(".FacetTarget", self);
                    $facetTargets.each(function () {
                        var $target = $(this);
                        $target.trigger("dataBind", [-1]); // clear results
                    });
                }
                event.stopPropagation();
            }

            function databindTargetControl() {
                $databoundTargetControl.dim();
                if (config.databoundTargetControl) {
                    // Request html for the target control from server and fill it in for them
                    $.ajax({
                        url: $r.cleanHref(window.location),
                        type: "POST",
                        data: {
                            containerId: self.id,
                            action: "databindTargetControl",
                            state: JSON.stringify(state)
                        },
                        success: function (msg) {
                            $databoundTargetControl
                                .html(msg)
                                .unDim()
                                .setupDisplay()
                                .setupEvents();
                            $self.trigger("targetControlDatabound");
                            $r.hideProgress(self.id);
                        }, // success
                        error: function (XMLHttpRequest, textStatus, errorThrown) {
                            $r.hideProgress(self.id);
                            $r.showError(XMLHttpRequest, errorThrown + ' ' + textStatus);
                        } // error
                    }); // ajax
                }
            }

            function dataBindChildren(data) {
                // Pass on data to child targets
                var $facetTargets = $(".FacetTarget", self);
                $facetTargets.show();
                $facetTargets.each(function () {
                    var $target = $(this);
                    var t = setTimeout(function () {
                        $target.trigger("dataBind", [data, state]);
                    }, 1);
                });
                if (config.databoundTargetControl) {
                    databindTargetControl();
                }
                $self.trigger("dataBound", [data, state]);
            }

            function showResultSums() {
                $facetSearchResultSum.html('...');
                $facetSearchResultSum.each(function () {
                    var $resultSum = $(this);
                    var sumField = $resultSum.attr("_sumfield");
                    if (!!sumField) {
                        // Request sum from server
                        $.ajax({
                            url: $r.cleanHref(window.location),
                            type: "POST",
                            data: {
                                containerId: self.id,
                                action: "sum",
                                sumField: sumField,
                                state: JSON.stringify(state)
                            },
                            success: function (msg) {
                                var resultSum = parseInt(msg);
                                if (!isNaN(resultSum)) {
                                    var resultSumFormatted = parseInt(msg).format("N0");
                                    $resultSum.html(resultSumFormatted);
                                }
                            }, // success
                            error: function (XMLHttpRequest, textStatus, errorThrown) {
                                $r.hideProgress(self.id);
                                $r.showError(XMLHttpRequest, errorThrown + ' ' + textStatus);
                            } // error
                        });
                    }
                });
            }

            function showResultCount() {
                if ($facetSearchResultCount.length > 0 || facetSearchPager) {
                    $facetSearchResultCount.html('...');
                    $.ajax({
                        url: $r.cleanHref(window.location),
                        type: "POST",
                        data: {
                            containerId: self.id,
                            action: "count",
                            state: JSON.stringify(state)
                        },
                        success: function (msg) {
                            var resultCount = parseInt(msg);
                            if (!isNaN(resultCount)) {
                                if (resultCount >= 0) {
                                    $facetSearchInstructions.hide();
                                    $facetSearchResultCount.html(resultCount.format("N0"));
                                    if (facetSearchPager) facetSearchPager.setResultCount(resultCount);
                                    if (resultCount == 0) { $facetSearchNoResults.show() } else { $facetSearchNoResults.hide() };
                                    if (config.tabFormatString && config.tabSelector) {
                                        $(config.tabSelector).html(String.format(config.tabFormatString, resultCount.format("N0")));
                                    }
                                } else {
                                    // Server returned -1 -> no filters set and we don't want to show all results
                                    $facetSearchInstructions.show();
                                    $facetSearchNoResults.hide();
                                    $facetSearchPager.hide();
                                }
                            }
                        }, // success
                        error: function (XMLHttpRequest, textStatus, errorThrown) {
                            $r.hideProgress(self.id);
                            $r.showError(XMLHttpRequest, errorThrown + ' ' + textStatus);
                        } // error
                    });
                }
            }

            function dataBound(event, data) {
                if (event) event.stopPropagation();
            }

            function targetControlDatabound(event) {
                if (event) event.stopPropagation();
            }

            function clear(event) {
                $facetFilters.each(function () {
                    $(this).trigger("clear");
                });
                $self.trigger("stateChanged");
                if (event) event.stopPropagation();
            }

            // INITIALIZE

            initialize();


        }); // each
        return this; // don't break the chain

    }; // $.fn.facetSearch

})(jQuery);



