﻿/*
The code in this file or document and its designs, methods, data, know-how and all other related elements are the property of LUXSON ltd © Copyright 2009-2010 and/or may contain code operated under third party licence(s); unauthorised use is therefore prohibited, including (without limitation) copying, editing, adapting, reverse engineering or any other similar or related action, in part or in full. Separate rights may also exist for LUXSON and/or client and/or third party content and/or services. For licensing information please contact LUXSON ltd.
*/

/*
LUXSON SmartSearch™ v1.0
    
Inactive code, but included in this release
intAutoHideTimeout - if functionality is wanted where by the results are auto hidden after a period of time, uncomment the code marked #AUTOTIMEOUT# and some extra logic is required so the results do not disappear when you do a search and your mouse accidently moves out of the search area (strResultsDivID).
*/

function SmartSearch(istrSSID, istrTextBoxID, istrDefault, istrResultsDivID, iintMinNumCharsBeforeSearch, iintAutoHideTimeout, istrSmartSearchRowClass, istrSmartSearchRowSelected, istrSearchType, istrInputDelimiter, istrDefaultTextCssClass) {

    //input variables
    this.strSSID = istrSSID;
    this.strTextBoxID = istrTextBoxID;
    this.strDefault = istrDefault;
    this.strResultsDivID = istrResultsDivID;
    this.intMinNumCharsBeforeSearch = iintMinNumCharsBeforeSearch;
    this.intAutoHideTimeout = iintAutoHideTimeout; //currently not used
    this.strSmartSearchRowClass = istrSmartSearchRowClass;
    this.strSmartSearchRowSelected = istrSmartSearchRowSelected;
    this.strSearchType = istrSearchType;
    this.strInputDelimiter = istrInputDelimiter;
    this.strDefaultTextCssClass = istrDefaultTextCssClass;

    //private variables
    this.intSearchResultSelected;
    this.blnSearchIsFocus;
    this.blnTextBoxIsFocus;
    this.strOrgSearchTrem;
    this.intAjaxRequests;
    this.strPrevSearch;

    this.Init = function(strSSID) {

        //init/reset variables
        this.intSearchResultSelected = 0;
        this.blnSearchIsFocus = false;
        this.blnTextBoxIsFocus = false;
        this.strOrgSearchTrem = "";
        this.intAjaxRequests = 0;
        this.strPrevSearch = "";

        this.ResetTextBox(false);

        //remove events so we don't get duplicates
        $('#' + this.strTextBoxID).unbind();
        $('#' + this.strResultsDivID).unbind();

        //use jQuery Namespaced Events to remove events only associated with this obj
        $(document).unbind("mouseup." + strSSID);
        $(document).unbind("keyup." + strSSID);

        $('#' + this.strTextBoxID).focusin(function() {
            eval(strSSID + ".TextBoxFocus()");
        });

        $('#' + this.strTextBoxID).focusout(function() {
            eval(strSSID + ".TextBoxUnFocus()");
        });

        $('#' + this.strResultsDivID).mouseenter(function() {
            eval(strSSID + ".SetSearchIsFocus(true)");
        });

        $('#' + this.strResultsDivID).mouseleave(function() {
            eval(strSSID + ".SetSearchIsFocus(false)");
            //#AUTOTIMEOUT#
            //eval(strSSID + ".AutoCloseResults()");
        });

        $(document).bind("mouseup." + strSSID, function() {
            eval(strSSID + ".DocClickCloseResults()");
        });

        $('#' + this.strTextBoxID).keyup(function(e) {
            eval(strSSID + ".DoSearch(e)");
        });

        $(document).bind("keyup." + strSSID, function(e) {
            return eval(strSSID + ".ControlMenu(e)");
        });

    };

    this.ResetTextBox = function(blnOverride) {

        var strSearch = $('#' + this.strTextBoxID).val();

        //set the default text if the textbox is empty or the override flag is set
        if (strSearch.length == 0 || blnOverride) $('#' + this.strTextBoxID).val(this.strDefault);

        strSearch = $('#' + this.strTextBoxID).val();

        //add the default text class to the textbox (e.g. greyed out text)
        if (this.strDefaultTextCssClass.length > 0 && strSearch == this.strDefault) $('#' + this.strTextBoxID).addClass(this.strDefaultTextCssClass);

    };

    this.CleanString = function(str) {

        //replace ' with \'
        str = str.replace(/'/g, "\\'");

        return str;
    };

    this.ResultsRowClicked = function(str) {

        if (this.strSearchType == "Input") {

            //get all before the last ,
            //if no , replace all
            var strSearchValue = $("#" + this.strTextBoxID).val();
            if (strSearchValue.lastIndexOf(this.strInputDelimiter) > -1) {
                strSearchValue = strSearchValue.substr(0, strSearchValue.lastIndexOf(this.strInputDelimiter) + this.strInputDelimiter.length) + " ";
            } else {
                strSearchValue = "";
            }

            $("#" + this.strTextBoxID).val(strSearchValue + str + this.strInputDelimiter + " ");

        } else {
            $("#" + this.strTextBoxID).val(str);
        }

        this.MasterCloseResults();

        if (this.strSearchType == "Input") $('#' + this.strTextBoxID).focus();

    };

    this.ControlMenu = function(e) {

        if (document.getElementById(this.strResultsDivID).innerHTML.length > 0) {

            var KeyID = (window.event) ? event.keyCode : e.keyCode;
            var intSmartSearchMaxRows = 0;

            //get value of hSmartSearchRowCount, if exsists
            if ($('#' + this.strSSID + "_hSSRowCount")) {
                intSmartSearchMaxRows = $('#' + this.strSSID + "_hSSRowCount").val();
            }

            switch (KeyID) {
                case 9: case 13: //tab, enter
                    this.MasterCloseResults();

                    //if Input, add a comma to allow faster entry of the next word, e.g. keyword
                    if (this.strSearchType == "Input") $('#' + this.strTextBoxID).val($('#' + this.strTextBoxID).val() + this.strInputDelimiter + " ");

                    $('#' + this.strTextBoxID).focus();
                    break;
                case 27: //escape, close search results, revert to user entered value
                    this.MasterCloseResults();
                    $('#' + this.strTextBoxID).val(this.strOrgSearchTrem);
                    break;
                case 38: //up

                    //store the search term entered by the user
                    if (this.intSearchResultSelected == 0) {
                        this.strOrgSearchTrem = $('#' + this.strTextBoxID).val();
                    }

                    //if not reached top, -1
                    //if reached top, start again at the bottom
                    if (this.intSearchResultSelected > 1) {
                        this.intSearchResultSelected = this.intSearchResultSelected - 1;
                    } else {
                        this.intSearchResultSelected = intSmartSearchMaxRows;
                    }

                    var strRowID = this.strSSID + "_SSRow" + this.intSearchResultSelected;

                    if (this.strSearchType == "Input") {

                        //get all before the last ,
                        //if no , replace all
                        var strSearchValue = $('#' + this.strTextBoxID).val();
                        if (strSearchValue.lastIndexOf(this.strInputDelimiter) > -1) {
                            strSearchValue = strSearchValue.substr(0, strSearchValue.lastIndexOf(this.strInputDelimiter) + this.strInputDelimiter.length) + " ";
                        } else {
                            strSearchValue = "";
                        }

                        $('#' + this.strTextBoxID).val(strSearchValue + $('#' + "h_" + strRowID).val());

                    } else {
                        $('#' + this.strTextBoxID).val($('#' + "h_" + strRowID).val());
                    }

                    this.UnSelectAllSearchRows();
                    $('#' + strRowID).addClass(this.strSmartSearchRowSelected)

                    break;

                case 40: //down

                    //store the search term entered by the user
                    if (this.intSearchResultSelected == 0) {
                        this.strOrgSearchTrem = $('#' + this.strTextBoxID).val();
                    }

                    //if not reached bottom, +1
                    //if reached bottom, start again at the top
                    if (this.intSearchResultSelected < intSmartSearchMaxRows) {
                        this.intSearchResultSelected = this.intSearchResultSelected + 1;
                    } else {
                        this.intSearchResultSelected = 1;
                    }

                    var strRowID = this.strSSID + "_SSRow" + this.intSearchResultSelected;

                    if (this.strSearchType == "Input") {

                        //get all before the last ,
                        //if no , replace all
                        var strSearchValue = $('#' + this.strTextBoxID).val();
                        if (strSearchValue.lastIndexOf(this.strInputDelimiter) > -1) {
                            strSearchValue = strSearchValue.substr(0, strSearchValue.lastIndexOf(this.strInputDelimiter) + this.strInputDelimiter.length) + " ";
                        } else {
                            strSearchValue = "";
                        }

                        $('#' + this.strTextBoxID).val(strSearchValue + $('#' + "h_" + strRowID).val());

                    } else {
                        $('#' + this.strTextBoxID).val($('#' + "h_" + strRowID).val());
                    }

                    this.UnSelectAllSearchRows();
                    $('#' + strRowID).addClass(this.strSmartSearchRowSelected);

                    break;
            }

        }

        return false;

    };

    this.UnSelectAllSearchRows = function() {

        var intSmartSearchMaxRows = 0;
        var i;

        //get value of hSmartSearchRowCount, if exsists
        if ($('#' + this.strSSID + "_hSSRowCount")) {
            intSmartSearchMaxRows = $('#' + this.strSSID + "_hSSRowCount").val();
        }

        for (i = 1; i <= intSmartSearchMaxRows; i++) {
            $('#' + this.strSSID + "_SSRow" + i).removeClass(this.strSmartSearchRowSelected);
        }

    }

    this.TextBoxFocus = function() {

        this.blnTextBoxIsFocus = true;

        if ($('#' + this.strTextBoxID).val() == this.strDefault) {
            $('#' + this.strTextBoxID).val("");
        } else {
            //to enable search when click on the text box, uncomment this code
            //this.DoSearch("TextBoxFocus");
        }

    };

    this.TextBoxUnFocus = function() {
        this.blnTextBoxIsFocus = false;
    };

    //#AUTOTIMEOUT#
    //close search results if mouse leaves pnlSmartSearch after x s
    /*this.AutoCloseResults = function() {
    setTimeout(this.strSSID + ".CloseResults()", this.intAutoHideTimeout);
    };*/

    //if click on the webpage, but not in the pnlSmartSearch, close the results
    this.DocClickCloseResults = function() {
        if (!this.blnSearchIsFocus && !this.blnTextBoxIsFocus) this.MasterCloseResults();
    };

    //set the focus status of the whole SS control
    this.SetSearchIsFocus = function(bln) {
        this.blnSearchIsFocus = bln;
    };

    //#AUTOTIMEOUT#
    //only close if mouse is outside of pnlSmartSearch
    /*this.CloseResults = function() {
    if (!this.blnSearchIsFocus && !this.blnTextBoxIsFocus) this.MasterCloseResults();
    };*/

    this.MasterCloseResults = function() {
        //clear the results
        $('#' + this.strResultsDivID).html("");
        $('#' + this.strResultsDivID).addClass("SSHidden");
        $('#' + this.strResultsDivID).removeClass("SSShow");

        //reset selected result item
        this.intSearchResultSelected = 0;

        this.strPrevSearch = "";
    };

    this.SetSearchResultSelected = function(intSearchResultSelected) {
        this.intSearchResultSelected = intSearchResultSelected;
    }

    this.DoSearch = function(e) {

        //TextBoxFocus = override when you re-click in the textbox

        var KeyID;
        //get the value of the search
        var strSearch = $('#' + this.strTextBoxID).val();

        if (e != "TextBoxFocus") KeyID = (window.event) ? event.keyCode : e.keyCode;

        if (strSearch != this.strDefault) {
            $('#' + this.strTextBoxID).removeClass(this.strDefaultTextCssClass);
        }

        // See if a valid key key is pressed such as 0-9, A-Z, a-z, Hyphen, Underscore
        if ((e == "TextBoxFocus") || ((KeyID >= 48) && (KeyID <= 57)) ||  // Numbers 0-9
                ((KeyID >= 65) && (KeyID <= 90)) ||  // Upper case A-Z
                ((KeyID >= 97) && (KeyID <= 122)) ||  // Lower case a-z
                (KeyID == 189) || (KeyID == 8) || (KeyID == 46)) //backspace and delete
        // Hyphen
        {

            //get the value of the search
            var strSearch = $('#' + this.strTextBoxID).val();

            //if Input search, only search from last ,
            if (this.strSearchType == "Input") {
                if (strSearch.lastIndexOf(this.strInputDelimiter) > -1) {
                    strSearch = strSearch.substr(strSearch.lastIndexOf(this.strInputDelimiter) + this.strInputDelimiter.length);
                }
            }

            strSearch = $.trim(strSearch);

            //if > the req. num chars and the search term is not the default and the search term is not the same as the prev search, do the search
            if (strSearch.length >= this.intMinNumCharsBeforeSearch && strSearch != this.strDefault && strSearch != this.strPrevSearch) {

                this.intAjaxRequests++;
                this.strPrevSearch = strSearch;

                $.ajax({
                    async: "true",
                    cache: "false",
                    type: "POST",
                    url: "SmartSearchGetSearchResults.aspx/DoSearch",
                    data: "{'strSearch':'" + strSearch + "','strResultsDiv':'" + this.CleanString(this.strResultsDivID) + "', 'strSSID':'" + this.CleanString(this.strSSID) + "', 'strTextBoxID':'" + this.CleanString(this.strTextBoxID) + "', 'intAjaxRequests':'" + this.intAjaxRequests.toString() + "'}",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function(msg) {

                        var aryResult = msg.split("|");
                        var strSSID = aryResult[0];
                        var intAjaxRequestID = aryResult[1];
                        var strResultsDivID = aryResult[2];
                        var strResultsHTML = aryResult[3];

                        //if another ajax request in the queue, don't display the results
                        //wait until the next set of results

                        if (eval(strSSID + ".intAjaxRequests") == intAjaxRequestID) {
                            $('#' + strResultsDivID).html(strResultsHTML);
                            $('#' + strResultsDivID).removeClass("SSHidden");
                            $('#' + strResultsDivID).addClass("SSShow");

                            //reset selected result item
                            eval(strSSID + ".SetSearchResultSelected(0);")
                        }

                    },
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        //alert(XMLHttpRequest.status);
                    }
                });

            } else if (strSearch.length == 0) {
                this.MasterCloseResults();
            }

        } else if (KeyID == 188) { //comma
            if (this.strSearchType == "Input") this.MasterCloseResults();
        }

    };

}
