/**
 * Off-canvas menu
 * @module Ink.UI.Drawer_1
 * @version 1
 */
 
Ink.createModule('Ink.UI.Drawer', '1', ['Ink.UI.Common_1', 'Ink.Dom.Loaded_1', 'Ink.Dom.Selector_1', 'Ink.Dom.Element_1', 'Ink.Dom.Event_1', 'Ink.Dom.Css_1'], function(Common, Loaded, Selector, Element, Event, Css) {
    'use strict';

    function elNotFound(el) {
        Ink.warn( 'Ink.UI.Drawer_1: Could not find the "' +
            el + '" element on this page. Please make sure it exists.' );
    }

    function Drawer(options) {
        Common.BaseUIComponent.apply(this, [document.body, options]);
    }

    Drawer._name = 'Drawer_1';

    Drawer._optionDefinition = {
        parentSelector:     ['String', '.ink-drawer'],
        leftDrawer:         ['String', '.left-drawer'],
        leftTrigger:        ['String', '.left-drawer-trigger'],
        rightDrawer:        ['String', '.right-drawer'],
        rightTrigger:       ['String', '.right-drawer-trigger'],
        contentDrawer:      ['String', '.content-drawer'],
        closeOnContentClick: ['Boolean', true],
        closeOnLinkClick:    ['Boolean', true],
        mode:               ['String', 'push'],
        sides:              ['String', 'both']
    };

    Drawer.prototype = {
        /**
         * Displays off-canvas content which can be triggered by clicking elements with the 'left-drawer-trigger' and 'right-drawer-trigger', respectively.
         * The left drawer has the 'left-drawer' class, and the right drawer has the 'right-drawer' class. The content drawer (EG your `<div id="main">`) must have the 'content-drawer' class. For more, see the example below, or try the sample.
         * @class Ink.UI.Drawer_1
         * @constructor
         *
         * @param {Object}      [options]                       Configuration options.
         * @xparam {String}     [options.parentSelector]        The class you are using in your wrapper (in the example below, it's the `body` tag.)
         * @xparam {String}     [options.leftDrawer]            Selector for the left drawer element. This element is placed outside the screen and shown when you click the `leftTrigger` element.
         * @xparam {String}     [options.leftTrigger]           Selector for the left drawer trigger(s). When you click this trigger, the `leftDrawer` is shown.
         * @xparam {String}     [options.rightDrawer]           Right drawer selector. (see `options.leftDrawer`)
         * @xparam {String}     [options.rightTrigger]          Right trigger selector (see `options.leftTrigger`)
         * @xparam {String}     [options.contentDrawer]         Selector for the content drawer.
         * @param {Boolean}     [options.closeOnContentClick]   Flag to close the drawer when someone clicks on the `.contentDrawer`
         * @param {String}      [options.mode]                  This can be 'push' or 'over'.
         * @param {String}      [options.sides]                 Can be 'left', 'right', or 'both'. Controls what sides have a drawer.
         *
         * @example
         * <body class="ink-drawer">
         *     <div class="left-drawer">
         *         Right drawer content...
         *     </div>
         *     <div class="right-drawer">
         *         Left drawer content...
         *     </div>
         *     <div id="main-content" class="content-drawer ink-grid">
         *         <a class="left-drawer-trigger" href="">Open left drawer</a>
         *         <a class="right-drawer-trigger" href="">Open right drawer</a>
         *         Content...
         *     </div>
         * </body>
         *
         * <script>
         *     Ink.requireModules(['Ink.UI.Drawer_1'], function (Drawer) {
         *         new Drawer();
         *     });
         * </script>
         */
        _init: function () {
            // make sure we have the required elements acording to the config options

            this._contentDrawers = Ink.ss(this._options.contentDrawer);

            this._leftDrawer = Ink.s(this._options.leftDrawer);
            this._leftTriggers = Ink.ss(this._options.leftTrigger);

            this._rightDrawer = Ink.s(this._options.rightDrawer);
            this._rightTriggers = Ink.ss(this._options.rightTrigger);

            // The body might not have it
            Css.addClassName(document.body, 'ink-drawer');

            if(this._contentDrawers.length === 0) {
                throw new Error('Ink.UI.Drawer_1: Could not find any "' +
                    this._options.contentDrawer + '" elements on this page. ' +
                    'Please make sure you have at least one.' );
            }

            switch (this._options.sides) {
                case 'both':
                    this._triggers =
                        this._options.leftTrigger + ', ' +
                        this._options.rightTrigger + ', ' +
                        this._options.contentDrawer;
                break;

                case 'left':
                    this._triggers =
                        this._options.leftTrigger + ', ' +
                        this._options.contentDrawer;
                break;

                case 'right':
                    this._triggers =
                        this._options.rightTrigger + ', ' +
                        this._options.contentDrawer;
                break;
            }

            if (this._options.sides === 'left' || this._options.sides === 'both') {
                if( !this._leftDrawer ){
                    elNotFound(this._options.leftDrawer);
                }

                if(this._leftTriggers.length === 0){
                    elNotFound(this._options.leftTrigger);
                }
            } else {
                if( !this._rightDrawer ){
                    elNotFound(this._options.rightDrawer);
                }

                if( this._rightTriggers.length === 0 ){
                    elNotFound(this._options.rightTrigger);
                }
            }

            this._isOpen = false;
            this._direction = undefined;

            this._handlers = {
                click:     Ink.bindEvent(this._onClick, this),
                afterTransition: Ink.bindEvent(this._afterTransition, this)
            };
            this._delay = 10;
            this._addEvents();
        },

        /**
         * Click event handler.
         * Listens to the body's click event
         *
         * @method _onClick
         * @private
         **/
        _onClick: function(ev){
            var triggerClicked = Ink.bind(function (side) {
                // When clicking on the trigger, the corresponding side is toggled.
                if (this._isOpen) {
                    this.close();
                } else {
                    this.open(side);
                }
                ev.preventDefault();
            }, this);

            if(Element.findUpwardsBySelector(ev.currentTarget,this._options.leftTrigger)){
                // Clicked on the left trigger
                triggerClicked('left');
            } else if(Element.findUpwardsBySelector(ev.currentTarget,this._options.rightTrigger)){
                triggerClicked('right');
            } else if(Element.findUpwardsBySelector(ev.currentTarget,this._options.contentDrawer)){
                // Clicked on the rest of the body
                if(this._options.closeOnContentClick) {
                    this.close();
                }
            } else if (this._options.closeOnLinkClick && Element.isLink(ev.target)) {
                this.close();
                // No preventDefault() here
            }
        },

        _afterTransition: function(){
            if(!this._isOpen){
                if(this._direction === 'left') {
                    Css.removeClassName(this._leftDrawer, 'show');
                } else {
                    Css.removeClassName(this._rightDrawer, 'show');
                }
            }
        },

        _addEvents: function(){
            Event.on(document.body, 'click', this._triggers + ', a[href*="#"]', this._handlers.click);
        },

        open: function(direction) {
            this._isOpen = true;
            this._direction = direction;

            var open = direction === 'left' ?
                this._leftDrawer :
                this._rightDrawer;

            Css.addClassName(open,'show');
            setTimeout(Ink.bind(function(){
                Css.addClassName(document.body, [this._options.mode, direction]);
            },this), this._delay);
        },

        close: function() {
            if (this._isOpen === false) { return; }
            this._isOpen = false;
            // TODO detect transitionEnd exists, otherwise don't rely on it
            Event.one(document.body, 'transitionend oTransitionEnd webkitTransitionEnd', this._handlers.afterTransition);
            Css.removeClassName(document.body, [this._options.mode, this._direction]);
        }

    };

    Common.createUIComponent(Drawer);

    return Drawer;
});
