﻿// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.

// This behavior can be attached to a textbox to enable auto-complete/auto-suggest
// scenarios.
Type.registerNamespace('ISC.Common.Web.Controls.Ajax');

ISC.Common.Web.Controls.Ajax.MFPNAutoCompleteBehavior = function(element) {
    /// <param name="element" domElement="true">The DOM element the behavior is associated with.</param>
    ISC.Common.Web.Controls.Ajax.MFPNAutoCompleteBehavior.initializeBase(this, [element]);
    this._servicePath = null;
    this._serviceMethod = null;
    this._minimumPrefixLength = 3;
    this._completionSetCount = 10;
    this._completionInterval = 1000;
    this._completionListElementID = null;
    this._completionListElement = null;
    this._hiddenIdElementID = null;
    this._hiddenIdElement = null;
    this._textColor = 'windowtext';
    this._textBackground = 'window';
    this._popupBehavior = null;
    this._timer = null;
    this._cache = null;
    this._currentPrefix = null;
    this._selectIndex = -1;
    this._focusHandler = null;
    this._blurHandler = null;
    this._keyDownHandler = null;
    this._mouseDownHandler = null;
    this._mouseUpHandler = null;
    this._mouseOverHandler = null;
    this._tickHandler = null;
    this._enableCaching = true;
    this._overCssClass = '';
    this._outCssClass = '';
    this._listWidth = 220;
    this._listHeight = null;
    this._parameters = null;
    this._callbackJS = null;
}
ISC.Common.Web.Controls.Ajax.MFPNAutoCompleteBehavior.prototype = {
    initialize: function() {

        ISC.Common.Web.Controls.Ajax.MFPNAutoCompleteBehavior.callBaseMethod(this, 'initialize');

        this._tickHandler = Function.createDelegate(this, this._onTimerTick);
        this._focusHandler = Function.createDelegate(this, this._onGotFocus);
        this._blurHandler = Function.createDelegate(this, this._onLostFocus);
        this._keyDownHandler = Function.createDelegate(this, this._onKeyDown);
        this._mouseDownHandler = Function.createDelegate(this, this._onListMouseDown);
        this._mouseUpHandler = Function.createDelegate(this, this._onListMouseUp);
        this._mouseOverHandler = Function.createDelegate(this, this._onListMouseOver);

        this._timer = new Sys.Timer();
        this.initializeTimer(this._timer);

        var element = this.get_element();
        this.initializeTextBox(element);

        if (this._completionListElementID !== null)
            this._completionListElement = $get(this._completionListElementID);
        if (this._hiddenIdElementID !== null)
            this._hiddenIdElement = $get(this._hiddenIdElementID);
        if (this._completionListElement == null) {
            this._completionListElement = document.createElement('div');
            this._completionListElement.id = this.get_id() + '_completionListElem';

            // Safari styles the element incorrectly if it's added to the desired location
            if (Sys.Browser.agent === Sys.Browser.Safari) {
                document.body.appendChild(this._completionListElement);
            } else {
                element.parentNode.appendChild(this._completionListElement);
            }
        }

        this.initializeCompletionList(this._completionListElement);

        this._popupBehavior = $create(AjaxControlToolkit.PopupBehavior,
                { 'id': this.get_id() + 'PopupBehavior', 'parentElement': element, "positioningMode": AjaxControlToolkit.PositioningMode.BottomLeft }, null, null, this._completionListElement);
    },

    get_completionInterval: function() {
        /// <value type="Number">Auto completion timer interval in milliseconds.</value>
        return this._completionInterval;
    },
    set_completionInterval: function(value) {
        this._completionInterval = value;
    },

    get_completionSetCount: function() {
        /// <value type="Number">Maximum completion set size.</value>
        return this._completionSetCount;
    },
    set_completionSetCount: function(value) {
        this._completionSetCount = value;
    },

    get_minimumPrefixLength: function() {
        /// <value type="Number">Minimum text prefix length required to perform behavior.</value>
        return this._minimumPrefixLength;
    },
    set_minimumPrefixLength: function(value) {
        this._minimumPrefixLength = value;
    },

    get_serviceMethod: function() {
        /// <value type="String">Web service method.</value>
        return this._serviceMethod;
    },
    set_serviceMethod: function(value) {
        this._serviceMethod = value;
    },

    get_servicePath: function() {
        /// <value type="String">Web service url.</value>
        return this._servicePath;
    },
    set_servicePath: function(value) {
        this._servicePath = value;
    },

    get_enableCaching: function() {
        /// <value type="Boolean">Get or sets whether suggestions retrieved from the webservice should be cached.</value>
        return this._enableCaching;
    },
    set_enableCaching: function(value) {
        this._enableCaching = value;
    },

    get_completionListElementID: function() {
        /// <value type="String>ID of the completion div element. </value>
        return this._completionListElementID;
    },
    set_completionListElementID: function(value) {
        this._completionListElementID = value;
    },

    get_completionList: function() {
        /// <value domElement="true">List dom element.</value>
        return this._completionListElement;
    },
    set_completionList: function(value) {
        this._completionListElement = value;
    },

    get_hiddenIdElementID: function() {
        /// <value type="String>ID of the hidden input element. </value>
        return this._hiddenIdElementID;
    },
    set_hiddenIdElementID: function(value) {
        this._hiddenIdElementID = value;
    },

    get_hiddenIdElement: function() {
        /// <value domElement="true">Hidden dom element.</value>
        return this._hiddenIdElement;
    },
    set_hiddenIdElement: function(value) {
        this._hiddenIdElement = value;
    },

    get_overCssClass: function() {
        /// <value type="String>CSS class for over element. </value>
        return this._overCssClass;
    },
    set_overCssClass: function(value) {
        this._overCssClass = value;
    },
    get_outCssClass: function() {
        /// <value type="String>CSS class for out/blank element. </value>
        return this._outCssClass;
    },
    set_outCssClass: function(value) {
        this._outCssClass = value;
    },
    get_listWidth: function() {
        /// <value type="String>Width list element. </value>
        return this._listWidth;
    },
    set_listWidth: function(value) {
        this._listWidth = value;
    },


    get_listHeight: function() {
        /// <value type="String>Height list element. </value>
        return this._listHeight;
    },
    set_listHeight: function(value) {
        this._listHeight = value;
    },

    get_parameters: function() {
        /// <value type="String>This is serialized string from AutoCompleteDTO object. </value>
        return this._parameters;
    },
    set_parameters: function(value) {
        this._parameters = value;
    },

    get_callbackJS: function() {
        /// <value type="String>This is JS code that will do after selected item. </value>
        return this._callbackJS;
    },
    set_callbackJS: function(value) {
        this._callbackJS = value;
    },

    dispose: function() {

        if (this._popupBehavior) {
            this._popupBehavior.dispose();
            this._popupBehavior = null;
        }
        if (this._timer) {
            this._timer.dispose();
            this._timer = null;
        }

        var element = this.get_element();
        if (element) {
            $removeHandler(element, "focus", this._focusHandler);
            $removeHandler(element, "blur", this._blurHandler);
            $removeHandler(element, "keydown", this._keyDownHandler);
            $removeHandler(this._completionListElement, 'mousedown', this._mouseDownHandler);
            $removeHandler(this._completionListElement, 'mouseup', this._mouseUpHandler);
            $removeHandler(this._completionListElement, 'mouseover', this._mouseOverHandler);
        }

        this._tickHandler = null;
        this._focusHandler = null;
        this._blurHandler = null;
        this._keyDownHandler = null;
        this._mouseDownHandler = null;
        this._mouseUpHandler = null;
        this._mouseOverHandler = null;


        ISC.Common.Web.Controls.Ajax.MFPNAutoCompleteBehavior.callBaseMethod(this, 'dispose');
    },

    initializeTimer: function(timer) {
        timer.set_interval(this._completionInterval);
        timer.add_tick(this._tickHandler);
    },

    initializeTextBox: function(element) {
        element.autocomplete = "off";
        $addHandler(element, "focus", this._focusHandler);
        $addHandler(element, "blur", this._blurHandler);
        $addHandler(element, "keydown", this._keyDownHandler);
    },

    initializeCompletionList: function(element) {
        var completionListStyle = element.style;
        completionListStyle.visibility = 'hidden';
        completionListStyle.backgroundColor = this._textBackground;
        completionListStyle.color = this._textColor;
        completionListStyle.border = 'solid 1px buttonshadow';
        completionListStyle.cursor = 'default';
        completionListStyle.unselectable = 'unselectable';
        completionListStyle.overflow = 'hidden';

        $addHandler(element, "mousedown", this._mouseDownHandler);
        $addHandler(element, "mouseup", this._mouseUpHandler);
        $addHandler(element, "mouseover", this._mouseOverHandler);
    },

    _hideCompletionList: function() {
        this._popupBehavior.hide();
        this._completionListElement.innerHTML = '';
        this._selectIndex = -1;
        // if (navigator.appVersion.indexOf('MSIE') != -1) {
//        if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { //test for MSIE x.x;
//            var ieversion = new Number(RegExp.$1) // capture x.x portion and store as a number
//            if (ieversion <= 5) {
//                if (selectTags == undefined || selectTags == null)
//                    selectTags = document.getElementsByTagName("select");
//                if (selectTags != null && selectTags.length > 0)
//                    for (j = 0; j < selectTags.length; j++) {
//                    selectTags[j].style.visibility = "visible";   
//                }
//            }
//        }
    },

    _highlightItem: function(item) {
        /// <param name="item">DOM element.</param>

        var children = this._completionListElement.childNodes;

        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            if (child !== item) {
                if (this._overCssClass == '' || this._outCssClass == '') {
                    child.style.backgroundColor = this._textBackground;
                    child.style.color = this._textColor;
                } else {
                    child.className = this._outCssClass;
                }

            }
        }

        // Only on Safari set the background color to be the same as "DropDown"
        // hightlighted item otherwise the text and the background are the same
        // color and the item hides itself.
        if (Sys.Browser.agent === Sys.Browser.Safari) {
            if (this._overCssClass == '' || this._outCssClass == '') {
                item.style.backgroundColor = '#FFF3DB';
                item.style.color = 'black';
            } else {
                item.className = this._overCssClass;
            }
        }
        else {
            if (this._overCssClass == '' || this._outCssClass == '') {
                item.style.backgroundColor = 'highlight';
                item.style.color = 'highlighttext';
            } else {
                item.className = this._overCssClass;
            }

        }
    },

    _onListMouseDown: function(ev) {
        var div = ev.target;
        while (div.tagName.toLowerCase() != 'div') {
            div = div.parentNode;
            if (div == null || div == undefined)
                break;
        }
        if (div !== this._completionListElement) {
            this._setId(div.getAttribute('itemId'));
            this._setText(div.getAttribute('valueId'));
            this._setCallback(this._callbackJS, div.getAttribute('itemCallbackArgument'));
            this._hideCompletionList();
        }
    },

    _onListMouseUp: function(ev) {
        this.get_element().focus();
    },

    _onListMouseOver: function(ev) {
        var div = ev.target;
        while (div.tagName.toLowerCase() != 'div') {
            div = div.parentNode;
            if (div == null || div == undefined)
                break;
        }
        var item = div;
        this._selectIndex = -1;
        this._highlightItem(item);
    },

    _onGotFocus: function(ev) {
        this._timer.set_enabled(true);
    },

    _onKeyDown: function(ev) {
        var k = ev.keyCode ? ev.keyCode : ev.rawEvent.keyCode;
        if (k === Sys.UI.Key.esc) {
            this._hideCompletionList();
            ev.preventDefault();
        }
        else if (k === Sys.UI.Key.up) {
            if (this._selectIndex > 0) {
                this._selectIndex--;
                this._highlightItem(this._completionListElement.childNodes[this._selectIndex]);
                ev.preventDefault();
            }
        }
        else if (k === Sys.UI.Key.down) {
            if (this._selectIndex < (this._completionListElement.childNodes.length - 1)) {
                this._selectIndex++;
                this._highlightItem(this._completionListElement.childNodes[this._selectIndex]);
                ev.preventDefault();
            }
        }
        else if (k === Sys.UI.Key.enter) {
            if (this._selectIndex !== -1) {
                this._setId(this._completionListElement.childNodes[this._selectIndex].getAttribute('itemId'));
                this._setText(this._completionListElement.childNodes[this._selectIndex].getAttribute('valueId'));
                this._setCallback(this._callbackJS, this._completionListElement.childNodes[this._selectIndex].getAttribute('itemCallbackArgument'));
                this._hideCompletionList();
                ev.preventDefault();
            }
        }
        else if (k === Sys.UI.Key.tab) {
            if (this._selectIndex !== -1) {
                this._setId(this._completionListElement.childNodes[this._selectIndex].getAttribute('itemId'));
                this._setText(this._completionListElement.childNodes[this._selectIndex].getAttribute('valueId'));
                this._setCallback(this._callbackJS, this._completionListElement.childNodes[this._selectIndex].getAttribute('itemCallbackArgument'));
                this._hideCompletionList();
            }
        }
        else {
            this._timer.set_enabled(true);
        }
    },

    _onLostFocus: function() {
        this._timer.set_enabled(false);
        this._hideCompletionList();
    },

    _onMethodComplete: function(result, context, methodName) {
        this._update(context, result, /* cacheResults */true);
    },
    _onMethodFailed: function(err, response, context) {
        // no op
    },

    _onTimerTick: function(sender, eventArgs) {
        if (this._servicePath && this._serviceMethod) {
            var text = this.get_element().value;

            if (text.trim().length < this._minimumPrefixLength) {
                this._currentPrefix = null;
                this._update('', null, /* cacheResults */false);
                return;
            }

            if (this._currentPrefix !== text) {
                this._currentPrefix = text;
                if (this._cache && this._cache[text]) {
                    this._update(text, this._cache[text], /* cacheResults */false);
                    return;
                }

                if (this._parameters == null || this._parameters == '') {
                    Sys.Net.WebServiceProxy.invoke(this.get_servicePath(), this.get_serviceMethod(), false,
											{ prefixText: this._currentPrefix, count: this._completionSetCount },
											Function.createDelegate(this, this._onMethodComplete),
											Function.createDelegate(this, this._onMethodFailed),
											text);
                } else {
                    Sys.Net.WebServiceProxy.invoke(this.get_servicePath(), this.get_serviceMethod(), false,
											{ prefixText: this._currentPrefix, parameters: this._parameters, count: this._completionSetCount },
											Function.createDelegate(this, this._onMethodComplete),
											Function.createDelegate(this, this._onMethodFailed),
											text);
                }
            }
        }
    },

    _setId: function(text) {
        if (this._hiddenIdElement != null) {
            this._hiddenIdElement.value = text;
        }
    },

    _setText: function(text) {
        this._timer.set_enabled(false);
        this._currentPrefix = text;
        var element = this.get_element();
        var control = element.control;
        // todo: should check for 'derives from' too and should somehow manually cause TB to raise property changed event
        if (control && control.set_text) {
            control.set_text(text);
        }
        else {
            element.value = text;
        }
    },

    _setCallback: function(text, argument) {
        if (this._callbackJS != null && this._callbackJS != undefined && this._callbackJS != '') {
            if (argument != null && argument != undefined)
                eval(this._callbackJS + '(' + argument + ');');
            else
                eval(this._callbackJS);
        }
    },

    _update: function(prefixText, completionItems, cacheResults) {
        if (cacheResults && this.get_enableCaching()) {
            if (!this._cache) {
                this._cache = {};
            }
            this._cache[prefixText] = completionItems;
        }

        this._completionListElement.innerHTML = '';
        this._selectIndex = -1;
        if (completionItems && completionItems.length) {
            for (var i = 0; i < completionItems.length; i++) {
                var ItemId = null;
                var ItemCallbackArgument = null;
                var ItemName = completionItems[i].name;
                var ItemValue = completionItems[i].value;
                if (this._hiddenIdElement != null) {
                    ItemId = completionItems[i].id;
                }
                if (this._callbackJS != null) {
                    ItemCallbackArgument = completionItems[i].script;
                }

                var indexPre = ItemValue.toLowerCase().indexOf(prefixText.trim().toLowerCase());
                var str;
                if (indexPre == -1) {
                    str = ItemValue;
                } else {
                    str = ItemValue.substring(0, indexPre) + '<b>' + prefixText + '</b>' + ItemValue.substr(indexPre + prefixText.length);
                }

                var s = '<table cellpadding="0" cellspacing="0" border="0" class="itemTable">\
                    <tr><td class="itemValue">' + str + '</td>\
                    <td class="itemName">&nbsp;' + ItemName + '</td></tr>\
                    </table>';
                /*<tr><td class="itemValue"><b>' + prefixText + '</b>' + ItemValue.substr(prefixText.length) + '</td>\    */
                //Description element
                /*
                var itemNameElement = document.createElement('div');
                itemNameElement.appendChild(document.createTextNode(ItemName));

                //Value element
                var itemValueElement = document.createElement('div');
                itemValueElement.innerHTML = '<b>' + prefixText + '</b>' + ItemValue.substr(prefixText.length-1);//appendChild(document.createTextNode(ItemValue));
                itemValueElement.style.color = this._valueColor;
                itemValueElement.style.styleFloat = 'left';
                itemValueElement.style.width = '100px';
                itemValueElement.style.fontWeight = 'bold';
                
                var itemElement = document.createElement('div');
                itemElement.appendChild(itemNameElement);
                itemElement.appendChild(itemValueElement);
                itemElement.__item = '';
                */
                var itemElement = document.createElement('div');
                if (ItemId != null)
                    itemElement.setAttribute('itemId', ItemId);
                if (ItemCallbackArgument != null)
                    itemElement.setAttribute('itemCallbackArgument', ItemCallbackArgument);

                itemElement.setAttribute('valueId', ItemValue);
                itemElement.innerHTML = s;
                itemElement.__item = '';

                var itemElementStyle = itemElement.style;
                itemElementStyle.padding = '1px';
                itemElementStyle.textAlign = 'left';
                itemElementStyle.textOverflow = 'ellipsis';
                itemElementStyle.cursor = 'pointer';
                if (this._overCssClass == '' || this._outCssClass == '') {
                    itemElementStyle.backgroundColor = this._textBackground;
                    itemElementStyle.color = this._textColor;
                } else {
                    itemElement.className = this._outCssClass;
                }
                this._completionListElement.appendChild(itemElement);
            }
            var elementBounds = CommonToolkitScripts.getBounds(this.get_element());

            if (completionItems.length == 1) {
                this._setId(this._completionListElement.childNodes[0].getAttribute('itemId'));
                this._setText(this._completionListElement.childNodes[0].getAttribute('valueId'));
                this._setCallback(this._callbackJS, this._completionListElement.childNodes[0].getAttribute('itemCallbackArgument'));
                this._hideCompletionList();
            } else {

                this._completionListElement.style.width = this._listWidth + 'px'; //Math.max(1, elementBounds.width - 2) + 'px';
                if (this._listHeight != null)
                    this._completionListElement.style.height = this._listHeight + 'px';

                this._popupBehavior.show();

                //              if (navigator.appVersion.indexOf('MSIE') != -1) {
//                if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { //test for MSIE x.x;
//                    var ieversion = new Number(RegExp.$1) // capture x.x portion and store as a number
//                    if (ieversion <= 5) {
//                        if (selectTags == undefined || selectTags == null)
//                            selectTags = document.getElementsByTagName("select");
//                        if (selectTags != null && selectTags.length > 0)
//                            for (j = 0; j < selectTags.length; j++) {
//                                selectTags[j].style.visibility = "hidden";
//                            }
//                    }
//                }
            }

        }
        else {
            this._popupBehavior.hide();
        }
    }
}
ISC.Common.Web.Controls.Ajax.MFPNAutoCompleteBehavior.descriptor = {
    properties: [   {name: 'completionInterval', type: Number},
                    {name: 'completionList', isDomElement: true},
                    {name: 'completionListElementID', type: String},
                    {name: 'completionSetCount', type: Number},
                    {name: 'minimumPrefixLength', type: Number},
                    {name: 'serviceMethod', type: String},
                    {name: 'servicePath', type: String},
                    {name: 'enableCaching', type: Boolean} ]
}
ISC.Common.Web.Controls.Ajax.MFPNAutoCompleteBehavior.registerClass('ISC.Common.Web.Controls.Ajax.MFPNAutoCompleteBehavior', AjaxControlToolkit.BehaviorBase);
if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();