// autosuggest.js

// \param textboxID is the ID of INPUT textbox element
// \param asmxUrl is the URL to an ASMX WebService
function autoSuggest(textboxID, asmxUrl)
{
    this.textboxID = textboxID;
    this.popupID = this.textboxID + '_autoSuggest';
    
    // \proto function(data, width, _this)
    // \param data is what ASMX service return
    // \param width is textbox's outerWidth
    this.onNeedHTML = null; 
    
    // \proto function(value, _this)
    // \param data is the value of textbox
    this.onNeedJSON = null;
    
    // \proto function(xhr, status, _this)
    // \param xhr is the XMLHttpRequest object
    // \param status is jQuery's status string, can be 'success', 'error' etc.
    this.onComplete = null;
    
    // \proto function(s)
    // \param s is debug message
    this.onDebug = null;
    
    this.asmxUrl = asmxUrl;
    
    // At what interval should the code monitor the textbox
    this.interval = 300;
    // Animation speed to show popup
    this.showSpeed = 888;
    // Animation speed to hide popup
    this.hideSpeed = 333;
    // Can optionally specify popup width and height.
    // If not specified width is the same as the textbox,
    // and height will be null.
    this.popupWidth = null;
    this.popupHeight = null;
    // User data
    this.userData = null;
    
    var _this = this;
    
    var _arrayToStr = function(a)
    {
        var s = '';
        for(var i = 0; i < a.length; i++)
        {
            s += '  [' + i + ']: ' + a[i] + '\r\n';
        }
        return s;
    }
    
    var _objectToStr = function(o)
    {
        var s = '{\r\n';
        for(var k in o)
        {
            s += '  ' + k + ': ' + o[k] + '\r\n';
        }
        s += '}';
        return s;
    }
    
    var _argsToStr = function()
    {
        var s = 'autoSuggest debug information:\r\n\r\n';
        for(var i = 0; i < arguments.length; i++)
        {
            var arg = arguments[i];
            switch(typeof(arg))
            {
            case 'object':
                if(arg.push)
                {
                    s += _arrayToStr(arg);
                }
                else
                    s += _objectToStr(arg);
                break;
            case 'string':
            case 'number':
            case 'date':
            case 'function':
            default:
                s += '[' + typeof(arg) + '] ' + arg + '\r\n';
            }
        }
        return s;
    }
    
    var _onAjaxData = function(data)
    {
        if(_this.onNeedHTML)
        {
            try
            {
                var popup = jQuery('#' + _this.popupID);
                var target = jQuery('#' + _this.textboxID);
                var offset = target.offset();
                var width = _this.popupWidth;
                if(width == null)
                {
                    //width = target.outerWidth();
                    width = '';
                }
                
                html = _this.onNeedHTML(data, _this.popupWidth, _this);
                if(html == null || html.length == 0)
                {
                    popup.slideUp(_this.hideSpeed);
                    return;
                }

                popup.css({top: offset.top + target.outerHeight(),
                    left: offset.left,
                    width: width,
                    height: _this.popupHeight});
            }
            catch(e)
            {
                if(_this.onDebug) _this.onDebug(_argsToStr('_onAjaxData', e));
            }
            
            popup.html(html);
            if(!popup.is(':visible'))
            {
                //popup.slideUp(_this.hideSpeed);
                popup.slideDown(_this.showSpeed);
            }
        }
    };
    
    var _onAjaxComplete = function(result, status)
    {
        if(_this.onComplete != null) _this.onComplete(result, status, _this);
    };
    
    var _ajax = function(value)
    {
        var jsonData = _this.onNeedJSON(value, _this);

        jQuery.ajax({
            url: _this.asmxUrl,
            contentType: 'application/json; charset=utf-8',
            type: 'POST',
            dataType: 'json',
            data: jsonData,
            complete:  _onAjaxComplete,
            success: _onAjaxData
        });
    };
    
    // old value that is used for searching
    var _oldValue = '';
    var _temp = 0;
    // Periodically checks value of the textbox.
    var _checkChange = function()
    {
        try
        {
            var target = jQuery('#' + textboxID);
            var value = jQuery.trim(target.val());
            if(value != _oldValue)
            {
                //document.title = value;
                _oldValue = value;
                if(value == '')
                {
                    var popup = jQuery('#' + _this.popupID);
                    popup.slideUp(_this.hideSpeed);
                }
                else
                {
                    _ajax(value);
                }
            }
        }
        catch(e)
        {
            if(_this.onDebug) _this.onDebug(_argsToStr('_checkChange', e));
        }
        
        window.setTimeout(_checkChange, _this.interval);
    }
    
    this.start = function(onNeedJSON, onNeedHTML)
    {
        if(this.onNeedJSON == onNeedJSON && this.onNeedHTML == onNeedHTML) return false;

        var target = jQuery('#' + this.textboxID);
        if(target == null || target.length == 0) return false;
        
        var popup = jQuery('#' + this.popupID);
        if(popup == null || popup.length == 0)
        {
            popup = jQuery('<div id="' + this.popupID + '" class="suggest"></div>');
            target.after(popup);
        }
        
        jQuery(document).click(function(e)
        {
            if(e.target.id != textboxID)
            {
                var popup = jQuery('#' + _this.popupID);
                if(popup.is(':visible')) popup.slideUp(_this.hideSpeed);
            }
        });
        
        this.onNeedJSON = onNeedJSON;
        this.onNeedHTML = onNeedHTML;
        
        window.setTimeout(_checkChange, this.interval);
        return true;
    }
    
    this.notifyValue = function(value)
    {
        _oldValue = value;
        jQuery('#' + this.textboxID).val(value);
        var popup = jQuery('#' + this.popupID);
        popup.slideUp(this.hideSpeed);
    }
    
    this.test = function()
    {
        alert(_this.popupID);
    }
}

