(function($) {
    // JQuery create Function
    $.fn.ssnMenu = function(options) {
        var defaults = {
            BindData: null,
            BindOn: function(target, items) { return items.filter('.Group' + target.id) },
            TargetFilter: function(target) { return target; },
            ItemsEffect: function(target, hideItems, showItems) { hideItems.hide(); showItems.show(); },
            NoItemEffect: function(items) { },
            SelectMouseOffSet: { X: 5, Y: 5 },
            SelectCheckTimes: 100,
            NoItemSelectedDelay: 2000,
            StartUpWithSelectedItem: null,
            NoItemSelectedGoBackToStartupItem: false,
            LockedArea: null
        };
        // Setup
        options = $.extend(defaults, options);

        // Data
        var data = {
            Items: this,
            SelectedTarget: null,
            NoSelectTimer: null,
            MouseStopTimer: null,
            MouseX: 0,
            MouseY: 0,
            MouseXSaved: 0,
            MouseYSaved: 0,
            Target: null
        };
        options.Data = data;

        //
        if (options.BindData != null && options.BindData != null)
            bindEvent(options);

        // Select an item on startup
        var selectedItem = options.StartUpWithSelectedItem;
        if (selectedItem != null && selectedItem.size() > 0) {
            options.Data.Target = selectedItem.get(0);
            itemEventCalled(options);
        }

        return this;
    };
    function bindEvent(options) {
        $(options.BindData).hover(function(e) {
            options.Data.Target = options.TargetFilter(e.target);
            clearTimeout(options.Data.NoSelectTimer);
            $(this).mousemove(function(e) {
                options.Data.MouseX = e.clientX;
                options.Data.MouseY = e.clientY;
            });
            options.Data.MouseStopTimer = setTimeout(function() { CheckIfMouseStopped(options); }, options.SelectCheckTimes);
        }, function(e) {
            clearTimeout(options.Data.MouseStopTimer);
            $(this).unbind('mousemove');
            options.Data.NoSelectTimer = setTimeout(function() { noItemEventCalled(options); }, options.NoItemSelectedDelay);
            options.Data.SelectedID = '';
        });
        if (options.LockedArea != null) {
            $(options.LockedArea).hover(function(e) {
                clearTimeout(options.Data.NoSelectTimer);
                clearTimeout(options.Data.MouseStopTimer);
            }, function(e) {
                options.Data.NoSelectTimer = setTimeout(function() { noItemEventCalled(options); }, options.NoItemSelectedDelay);
            });
        }
    }
    function CheckIfMouseStopped(options) {
        var data = options.Data;
        if (data.MouseXSaved <= data.MouseX + 5 && data.MouseXSaved >= data.MouseX - 5 &&
            data.MouseYSaved <= data.MouseY + 5 && data.MouseYSaved >= data.MouseY - 5) {
            whenMouseStops(options);
            return true;
        }
        data.MouseXSaved = data.MouseX;
        data.MouseYSaved = data.MouseY;
        options.Data.MouseStopTimer = setTimeout(function() { CheckIfMouseStopped(options); }, options.SelectCheckTimes);
        return false;
    }
    function whenMouseStops(options) {
        itemEventCalled(options);
    }
    function itemEventCalled(options) {
        if (options.Data.SelectedTarget != options.Data.Target) {
            var items = options.BindOn(options.Data.Target, options.Data.Items);
            options.ItemsEffect($(options.Data.Target), options.Data.Items.not(items), items);
        }
        options.Data.SelectedTarget = options.Data.Target;
    }
    function noItemEventCalled(options) {
        if (options.NoItemSelectedGoBackToStartupItem && options.StartUpWithSelectedItem != null) {
            options.Data.Target = options.StartUpWithSelectedItem.get(0);
            itemEventCalled(options);
        } else {
            options.Data.SelectedTarget = null;
        }
        options.NoItemEffect(options.Data.Items);
    }
})(jQuery);
