(function($) {
    var jcarousel = $.fn.jcarousel;

    $.fn.jcarousel = function(o) {
        o = o || {};
        var ic = $.isFunction(o.initCallback) ? o.initCallback : function() {};
        o.initCallback = function(c) {
            ic(c);
            $.jcarouselkeys.bindBlur($.jcarouselkeys.bindFocus(c.list.find('li'), c), c);

            $(document).bind('keydown', function(e) {
                if ($.jcarouselkeys.curr == null) {
                    return true;
                }

                var k1 = c.options.vertical ? 38 : 37;
                var k2 = c.options.vertical ? 40 : 39;

                if (e.which == k1 || e.which == k2) {
                    (e.which == k1) ? $.jcarouselkeys.curr.c.prev() : $.jcarouselkeys.curr.c.next();
                    e.preventDefault();
                    e.stopPropagation();
                    return false;
                }
            });
        };

        if ($.isFunction(o.itemLoadCallback)) {
            var ilc = o.itemLoadCallback;
            o.itemLoadCallback = function(c, state) {
                ilc(c, state);
                $.jcarouselkeys.correctFocus(c);
            };
        } else {
            var ilcaa = o.itemLoadCallback && $.isFunction(o.itemLoadCallback.onAfterAnimation) ? o.itemLoadCallback.onAfterAnimation : function() {};
            o.itemLoadCallback = {
                onBeforeAnimation: o.itemLoadCallback && $.isFunction(o.itemLoadCallback.onBeforeAnimation) ? o.itemLoadCallback.onBeforeAnimation : null,
                onAfterAnimation: function(c, state) {
                    ilcaa(c, state);
                    $.jcarouselkeys.correctFocus(c, state);
                }
            };
        }
        return jcarousel.apply(this, [o]);
    };

    var add = $.jcarousel.prototype.add;
    $.jcarousel.prototype.add = function(i, s) {
        return $.jcarouselkeys.bindBlur($.jcarouselkeys.bindFocus(add.apply(this, [i, s]), this), this);
    };

    $.jcarouselkeys = {
        curr: null,
        idx: function(el) {
            if ($(el).is('[jcarouselindex]')) {
                return parseInt($(el).attr('jcarouselindex'));
            } else {
                return parseInt($(el).parents('[jcarouselindex]').attr('jcarouselindex'));
            }
        },
        bindFocus: function(el, c) {
            var f = function() {
                var curr = {idx: $.jcarouselkeys.idx(this), c: c};

                if (c.first > curr.idx || c.last < curr.idx) {
                    c.scroll(curr.idx);
                }
                $.jcarouselkeys.curr = curr;
            };
            $.jcarouselkeys.el(el).bind('focus', f);
            return el;
        },
        bindBlur: function(el, c) {
            var f = function() {
                $.jcarouselkeys.curr = null;
            };
            $.jcarouselkeys.el(el).bind('blur', f);
            return el;
        },
        correctFocus: function(c, state) {
            if ($.jcarouselkeys.curr == null) {
                return;
            }

            if (c.first > $.jcarouselkeys.curr.idx || c.last < $.jcarouselkeys.curr.idx || state == 'prev') {
                var el = $.jcarouselkeys.curr.c.get(c.first);
                $.jcarouselkeys.el(el).trigger('focus');
            }
        },
        el: function(el) {
        	if (el.is('[tabindex]')) {
                return el;
            } else {
                var t = el.find('[tabindex]');
	            if (t.length > 0) {
	                return t;
	            } else {
	                return el.find('a:eq(0)');
	            }
            }
        }
    };
})(jQuery);
