﻿(function($) {
    var settings;
    var callbackFunction;
    var thisElement;
    var ajaxCall; // use to track ajax call
    var aborted = false;

    $.fn.nwsautocomplete = function(options, callbackOnError) {
        settings = $.extend({
            searchUrl: '',
            enableViewAllResults: true,
            resultUrl: '',
            numCharToStart: 3,
            numOfListItem: 5,
            viewAllResultsText: '',
            noResultsText: ''
        }, options);

        thisElement = $(this);
        if (typeof (callbackOnError) == 'function')
            callbackFunction = callbackOnError;

        thisElement.bind('keyup', keyUpHandler);
        return this;
    };

    function keyUpHandler(event) {

        var kc = event.which;
        if (kc == 13) {
            if ($('div.SuggestionList li.current').length != 0 && $('div.SuggestionList li.current div.Image') != undefined &&
                $('div.SuggestionList li.current div.Image').children("a") != undefined && $('div.SuggestionList li.current div.Image').children("a").attr("href") != undefined) {
                window.location = $('div.SuggestionList li.current div.Image').children("a").attr("href");
            } else {
                $('div.SuggestionList').remove();
                window.location = settings.resultUrl.replace("{0}", thisElement.val());
            }
        }
        if (kc == 8 || kc == 46) {
            $('div.SuggestionList').remove();
            $('div.noResult').remove();

            // Unbind keyup() event, set timeout for fast typing, catch all text, do search and rebind keyup() event
            thisElement.unbind('keyup');
            // Set timeout here
            $.doTimeout(250, function() {
                doSearch({ searchUrl: settings.searchUrl, element: thisElement });
            });
        }
        if (kc == 27) {
            // Clear search
            $('div.SuggestionList').remove();
            $('div.noResult').remove();
            thisElement.val('');
            if (typeof (ajaxCall) != 'undefined') {
                if (ajaxCall.status != 0)
                    ajaxCall.abort();
            }
            $('div.LoadingButton').remove();
            $('div.CloseButton').remove();
        }
        if ((kc == 38) || (kc == 40))
        // change class current of list
            if ($('div.SuggestionList li.current').length == 0)
            if (kc == 38)
            $($('div.SuggestionList li')[$('div.SuggestionList li').length - 1]).addClass('current');
        else
            $($('div.SuggestionList  li')[0]).addClass('current');
        else {
            var sel = false;
            $('div.SuggestionList li').each(function(index, listItem) {
                listItem = $(listItem);
                if (!sel && listItem.hasClass('current')) {
                    listItem.removeClass('current');
                    if (index == $('div.SuggestionList li').length - 1)
                        $($('div.SuggestionList li')[(kc == 38 ? (index - 1) : 0)]).addClass('current');
                    else if (index == 0)
                        $($('div.SuggestionList li')[(kc == 38 ? ($('div.SuggestionList li').length - 1) : (index + 1))]).addClass('current');
                    else
                        $($('div.SuggestionList li')[(kc == 38 ? (index - 1) : (index + 1))]).addClass('current');
                    sel = true;
                }
            });
        }

        var key = String.fromCharCode(kc);
        if (key.match(/[a-zA-Z0-9_\- ]/)) {
            $('div.SuggestionList').remove();

            // Unbind keyup() event, set timeout and rebind keyup() event
            thisElement.unbind('keyup');

            // Set timeout here
            $.doTimeout(250, function() {
                doSearch({ searchUrl: settings.searchUrl, element: thisElement });
            });
        }
    }

    function doSearch(o) {
        var queryString = o.element.val();
        queryString = $.trim(queryString);
        //console.log('--------------------------------------------------');
        //console.log('do search: ' + queryString);

        // input length must >= settings.numCharToStart
        if (queryString.length >= settings.numCharToStart) {

            var searchUrl = settings.searchUrl.replace('{0}', queryString);
            if (typeof (ajaxCall) != 'undefined') {
                //console.log('Current ajaxCall is: ' + typeof (ajaxCall));
                ajaxCall.abort();
                //ajaxCall = null;
                //console.log('Abort ajaxCall!');

                // Write log has aborted
                aborted = true;
            }

            // Add reqired timeout here! wait for abort ajax call, completely complete
            $.doTimeout(50, function() {
                // rebind the keyup event
                //console.log('Rebind keyup event');
                thisElement.bind('keyup', keyUpHandler);
                aborted = false;
                //console.log('New Ajax call');
                ajaxCall = $.ajax({
                    type: 'GET',
                    url: searchUrl,
                    dataType: 'json',
                    data: '',
                    success: doSearchCallBack,
                    error: ajaxErrorHandler
                });

                // Add Loading button, remove close button
                $('div.CloseButton').remove();
                $('div.noResult').remove();
                var LoadingDiv = $('<div>').addClass('LoadingButton');
                var pos = thisElement.offset();
                LoadingDiv.css('left', pos.left + thisElement.outerWidth() - 25).css('top', pos.top + 11);
                $('div.LoadingButton').remove();
                $(document.body).append(LoadingDiv);
            });
        }
        else {
            // just rebind the keyup event
            //console.log('Rebind keyup event');
            thisElement.bind('keyup', keyUpHandler);
        }
    }

    function ajaxErrorHandler(xhr, status) {
        callbackFunction.call(this, xhr.status);
    }

    function doSearchCallBack(data, status, xhr) {

        //console.log('do searchCallBack');
        // Bugs: abort ajax call still fire success callback (jQuery 1.4)
        if (xhr.status == 0) // has aborted
        {
            // add loading button, remove noResult div
            $('div.noResult').remove();

            //console.log('Call back: xhr.status:' + xhr.status + '; status: ' + status + '; data: ' + data);
            //console.log('return;')
            return;
        }

        var div = $('<div>');
        var pos = thisElement.offset();
        // Check data
        if (data == null) {
            if (!aborted) {
                $('div.SuggestionList').remove();
                $('div.noResult').remove();
                div.html(settings.noResultsText).addClass("noResult");
                //console.log('Call back and add noResult with: xhr.status:' + xhr.status + '; status: ' + status + '; data length: ' + data);
                aborted = false;
            }
        }
        else if (data.length > 0) {
            //console.log('Call back: xhr.status:' + xhr.status + '; status: ' + status + '; data length: ' + data.length);
            // Clear no result div
            $('div.noResult').remove();

            // Construct the dropdown list from json data
            div = $('<div>').addClass('SuggestionList');
            var ul = $('<ul>').addClass('AutoComplete');
            var liShowAll;

            try {
                $.each(data, function(index, value) {
                    // if more than 5 and enableViewAllResults must be true
                    if ((index > settings.numOfListItem - 1) & settings.enableViewAllResults) {
                        liShowAll = $('<li>').addClass('ViewAll')
                        liShowAll.html('<a href="' + settings.resultUrl.replace('{0}', thisElement.val()) + '">' + settings.viewAllResultsText + '<span class="showall"></span> </a>');
                        return false;
                    }
                    else {
                        var li = $('<li>').addClass('Item');
                        var liImageDiv = $('<div>').addClass('Image').html('<a href="' + value.Url + '"><img src="' + value.ImageUrl + '" alt="image" /></a>');
                        var liTitleDiv = $('<div>').addClass('Title').html('<a href="' + value.Url + '">' + value.Title + '</a>');
                        var liDescriptionDiv = $('<div>').addClass('Description').html('<a href="' + value.Url + '">' + value.Description + '</a>');
                        li.append(liImageDiv);
                        li.append(liTitleDiv);
                        li.append(liDescriptionDiv);
                        ul.append(li);
                    }
                });
            }
            catch (ex) {
                // Call errorCallback here                
                callbackFunction.call(this, 'There was something wrong with JSON data!');
            }
            if (typeof (liShowAll) != 'undefined') ul.append(liShowAll);
            div.html(ul);
        }

        // remove loading button, add close button
        if (!aborted) {
            $('div.LoadingButton').remove();
            $('div.CloseButton').remove();
            var CloseDiv = $('<div>').addClass('CloseButton');
            CloseDiv.css('left', pos.left + thisElement.outerWidth() - 60).css('top', pos.top + 8);
            $(document.body).append(CloseDiv);
        }
        //else
        //console.log("Call back of an aborted ajax call")

        div.css('left', pos.left - 4).css('top', pos.top + thisElement.outerHeight() - 2);
        $('div.SuggestionList').remove();
        $(document.body).append(div);

        $('div.SuggestionList li').each(function(index, listItem) {
            listItem = $(listItem);
            listItem.mouseenter(function() {
                $('div.SuggestionList li.current').removeClass('current');
                if (($('div.SuggestionList li.ViewAll')).length > 0) {
                    if ($(this).index() != $('div.SuggestionList li').length - 1)
                        $(this).addClass('current');
                }
                else
                    if ($(this).index() != $('div.SuggestionList li').length)
                    $(this).addClass('current');
            });
        });
        $('div.CloseButton').bind('click', function() {
            $('div.SuggestionList').remove();
            $('div.noResult').remove();
            $('div.CloseButton').remove();
            $('div.LoadingButton').remove();
            thisElement.val('');
            thisElement.focus();
        });
    }
})(jQuery);
