'use strict';

/*@
Ox.Focus <o> Basic focus controller
@*/

Ox.Focus = (function() {

    var stack = [],

        that = {
            cleanup: function() {
                stack = stack.filter(function(item) {
                    try {
                        return !!Ox.$elements[item]
                    } catch(e) {
                        return false;
                    }
                });
            },
            debug: function() {
                return stack.map(function(item) {
                    try {
                        return Ox.$elements[item][0];
                    } catch(e) {
                        return item;
                    }
                });
            },
            focusedElement: function() {
                return Ox.$elements[Ox.last(stack)];
            },
            focusedElementIsInput: function() {
                var $element = that.focusedElement();
                return $element && $element.hasClass('OxKeyboardFocus');
            },
            gainFocus: function($element) {
                var $focusedElement = that.focusedElement(),
                    oxid = $element.oxid,
                    index = stack.indexOf(oxid);
                if (index == -1 || index < stack.length - 1) {
                    stack = $element.parentElements().map(function($element) {
                        return $element.oxid;
                    }).concat(oxid);
                    if ($focusedElement) {
                        try {
                            $focusedElement
                                .removeClass('OxFocus')
                                .triggerEvent('losefocus');
                        } catch(e) {
                            that.cleanup();
                        }
                    }
                    try {
                        $element
                            .addClass('OxFocus')
                            .triggerEvent('gainfocus');
                    } catch(e) {
                        that.cleanup();
                    }
                }
            },
            hasFocus: function($element) {
                return Ox.last(stack) == $element.oxid;
            },
            loseFocus: function($element) {
                var $focusedElement,
                    index = stack.indexOf($element.oxid);
                if (index > -1 && index == stack.length - 1) {
                    stack.pop();
                    try {
                        $element
                            .removeClass('OxFocus')
                            .triggerEvent('losefocus');
                    } catch(e) {
                        that.cleanup();
                    }
                    $focusedElement = that.focusedElement();
                    if (stack.length) {
                        if ($focusedElement) {
                            try {
                                $focusedElement
                                    .addClass('OxFocus')
                                    .triggerEvent('gainfocus');
                            } catch(e) {
                                that.cleanup();
                            }
                        }
                    }
                }
            },
            removeElement: function($element) {
                var index = stack.indexOf($element.oxid);
                if (index == stack.length - 1) {
                    that.loseFocus($element);
                } else if (index > -1) {
                    stack.splice(index, 1);
                }
            }
        };

    return that;

}());