/**
 * Created by Ing. Ernesto Pérez Amigo on 02/10/2015.
 */
(function($){
    //Clase Mensajear
    var Keyboard = function(elemento, opciones){
        /**********************/
        /* Variables privadas */
        /**********************/

        var elementoDOM = $(elemento);
        var language = [];
        var $layout = $("<div id='keyboard' class='row'/>");
        var _this = this;                   //almacenaremos el this para poder manipularlo después sin entrar en conflicto
        var optionsKeyboard = $.extend({    // Opciones del teclado y sus valores x defecto
            type: 'gatekeeper',         // Tipo de teclado a dibujar
            theme: 'default',           // Tema o estilo de CSS k se le aplicara al teclado
                                        // Temas disponibles: default, monokai, orange
            language: 'en_US',          // Lenguaje k se utilizara para dibujar el teclado
            active_shift: false,
            active_caps: false,

            is_hidden: true,            // Si el teclado se inicializa oculto o no
            open_speed: 300,            // Velocidad con k se muestra el teclado, default: 0.3 seg. Solo si is_hidden: true
            close_speed: 300,           // Velocidad con k se esconde el teclado, default: 0.1 seg. Solo si is_hidden: true
            show_on_focus_in: true,     // Mostrar el teclado cuando pierda el focus el input. Solo si is_hidden: true
            hide_on_focus_out: true,    // Esconder el teclado cuando pierda el focus el input. Solo si is_hidden: true

            trigger: undefined,         // Id del selector k al ser clickeado mostrara el teclado, ejemplo un boton

            enabled: true
        }, opciones || {});


        /********************/
        /* Metodos Privados */
        /********************/
        initKeyboard = function(){
            $('body').append($layout);

            language = languages[optionsKeyboard.language][optionsKeyboard.type];

            setupKeys();

            if (optionsKeyboard.is_hidden){
                $layout.hide();
            }

            // No funciona la option de disable o enable
            if (!optionsKeyboard.enabled){
                $('div#keyboard button').attr('disabled', 'disabled');
            }
        };

        setupKeys = function(){
            var keys = [];
            var keys1 = [];

            var divisor = false;

            $.each(language, function(key, val) {
                //if( val.d && val.u )
                if( val.d )
                    if(val.d.length == 1)
                        if(!divisor)
                            keys.push('<button class="btn btn-default char" data-up="' +  val.u + '" data-down="' +  val.d +'">'+val.d+'</button>');
                        else
                            keys1.push('<button class="btn btn-default char" data-up="' +  val.u + '" data-down="' +  val.d +'">'+val.d+'</button>');
                    else
                        if(val.d == 'divisor')
                            divisor = true;
                        else {
                            if(!divisor)
                                keys.push('<button class="btn btn-default ' +  val.d + '">' + val.u + '</button>');
                            else
                                keys1.push('<button class="btn btn-default ' +  val.d + '">' + val.u + '</button>');
                        }
            });

            $layout.append("<div class='col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 row' id='gatekeeper' />");

            $('<div/>', {
                'id': 'keypad',
                'class': 'col-md-9 '+optionsKeyboard.theme,
                html: keys.join('')
            }).appendTo('div#gatekeeper');

            $('<div/>', {
                'id': 'numpad',
                'class': 'col-md-3 '+optionsKeyboard.theme,
                html: keys1.join('')
            }).appendTo('div#gatekeeper');

            _this.setEnabled(optionsKeyboard.enabled);

            setUpFor();
            drawChar();
        };

        hideKeyboard = function() {
            if (!$layout.is(':hidden')) {
                $layout.slideUp(optionsKeyboard.close_speed);
            }
        };

        showKeyboard = function() {
            if ($layout.is(':hidden')) {
                $layout.slideDown(optionsKeyboard.open_speed);
            }
        };

        setUpFor = function() {
            var VERIFY_STATE_DELAY = 300;

            $('div#keypad, div#numpad').mouseenter(function() {
                _this.onFocus = true;
            });
            $('div#keypad, div#numpad').mouseleave(function() {
                _this.onFocus = false;
            });

            if(optionsKeyboard.is_hidden){

                if (optionsKeyboard.show_on_focus_in) {
                    $(elementoDOM).focusin(function() {
                        showKeyboard();
                    });
                }

                if (optionsKeyboard.hide_on_focus_out) {
                    $(elementoDOM).focusout(function() {
                        if(!_this.onFocus)
                            setTimeout(function(){hideKeyboard();}, VERIFY_STATE_DELAY);
                            //hideKeyboard();
                    });
                }

                if (optionsKeyboard.trigger) {
                    var $trigger = $(optionsKeyboard.trigger);
                    $trigger.click(function(e) {
                        e.preventDefault();

                        if ($layout.is(':hidden')){
                            showKeyboard();
                            elementoDOM.focus();

                        }
                        else {
                            if(!_this.onFocus){
                                setTimeout(function(){hideKeyboard();}, VERIFY_STATE_DELAY);
                                //hideKeyboard();
                            }
                        }
                   });
                }
            }
        };

        deleteChar = function(action, char){
            pos_i = elementoDOM.prop("selectionStart");
            pos_e = elementoDOM.prop("selectionEnd");
            length = elementoDOM.val().length;
            array = elementoDOM.val().split('');

            switch (action){
                case 'delete':
                    if (pos_i < length){
                        if (pos_e - pos_i == 0)
                            array.splice(pos_i, 1);
                        else if (pos_e - pos_i > 0)
                            array.splice(pos_i, pos_e - pos_i);
                        else return false;

                        this.pos_i = pos_i;
                    }
                    break;

                case 'backspace':
                    if (pos_i > 0){
                        if (pos_e - pos_i == 0) {
                            array.splice(pos_i - 1, 1);
                            pos_i -= 1;
                        }
                        else if (pos_e - pos_i > 0)
                            array.splice(pos_i, pos_e - pos_i);
                        else return false;
                    }
                    break;

                case 'enter':
                    if(elementoDOM.is("textarea")){
                        if(pos_e < length) {
                            array_1 = array.slice(0, pos_i).concat(String.fromCharCode(13, 10));
                            array_2 = array.slice(pos_e, length);

                            array = array_1.concat(array_2);
                            pos_i += 1;
                        }

                        if(pos_e == length){
                            //array.splice(pos_i, pos_e - pos_i);
                            array.push(String.fromCharCode(13, 10));
                            pos_i = array.length;
                        }
                    }

                    break;

                default:
                    if(pos_e < length) {
                        array_1 = array.slice(0, pos_i).concat(char);
                        array_2 = array.slice(pos_e, length);

                        array = array_1.concat(array_2);
                        pos_i += 1;
                    }

                    if(pos_e == length){
                        //array.splice(pos_i, pos_e - pos_i);
                        array.push(char);
                        pos_i = array.length;
                    }
            }

            value = "";
            for (i = 0; i < array.length; i++)
                value = value.concat(array[i]);

            elementoDOM.val(value);
            elementoDOM.prop("selectionStart", pos_i);
            elementoDOM.prop("selectionEnd", pos_i);
            elementoDOM.focus();

            return true;
        };

        drawChar = function(){
            var time, shift = false, capslock = false;

            $('div#keyboard').find('button.backspace').focusin(function(e){
                time = e.timeStamp;
            });
            $('div#keyboard').find('button.backspace').focusout(function(e){
                diff = e.timeStamp - time;
                if(parseInt(diff / 1000) >= 2) {
                    elementoDOM.val('');
                }
                //console.log(diff);
            });

            $('div#keyboard').find('button').click(function(){
                var $this = $(this);
                character = $this.data('down'); // If it's a lowercase letter, nothing happens to this variable

                // Shift keys
                if ($this.hasClass('shift')) {
                    $('.char').toggleClass('uppercase');
                    $('.symbol span').toggle();

                    shift = !shift;
			        capslock = false;
                    $this.toggleClass('active');

                    return;
                }

                // Caps lock
                if ($this.hasClass('capslock')) {
                    $('.char').toggleClass('uppercase');

                    capslock = true;
                    if(capslock) $this.toggleClass('active');

                    return;
                }

                // BackSpace
                if ($this.hasClass('backspace')) {

                    deleteChar('backspace');

                    return;
                }

                // Delete
                if ($this.hasClass('delete')) {

                    deleteChar('delete');

                    return;
                }

                // Enter
                if ($this.hasClass('enter')) {

                    deleteChar('enter');

                    return;
                }

                // Enter
                if ($this.hasClass('submit')) {

                    _this.SubmitKey();

                    return;
                }

                // Uppercase letter
                if ($this.hasClass('uppercase')) character = character.toUpperCase();

                // Remove shift once a key is clicked.
                if (shift) {
                    if (capslock === false) $('.char').toggleClass('uppercase');

                    shift = false;

                    $('div#keyboard').find('button.shift').removeClass('active');
                }

                // Space
                if ($this.hasClass('space')){
                    deleteChar('space', ' ');
                    return;
                    //character = ' ';
                }

                // Tab
                if ($this.hasClass('tab')) {
                    //character = "\t";
                    console.info('La tecla Tab fue presionada.');
                    return;
                }

                // Special characters
                //if ($this.hasClass('symbol')) character = $('span:visible', $this).html();

                // Draw all other characters(letters, numbers and symbols)
                if ($this.hasClass('char')){
                    deleteChar('char', character);
                    return;
                }
                elementoDOM.focus();
            });
        };


        /***************************************************************************/
        /* Metodos Publicos (Constructor, Getters y Setters, Submit Button Action) */
        /***************************************************************************/
        _this.init = function(){
            initKeyboard();
        };

        _this.setTheme = function($value){
            $this = $('div#'+optionsKeyboard.type).find('div');
            if ($value){
                switch($value){
                    case 'monokai':
                        $this.removeClass('default');
                        $this.removeClass('orange');
                        $this.addClass('monokai');
                        break;
                    case 'orange':
                        $this.removeClass('monokai');
                        $this.removeClass('default');
                        $this.addClass('orange');
                        break;
                    default:
                        $this.removeClass('monokai');
                        $this.removeClass('orange');
                        $this.addClass('default');
                }

                optionsKeyboard.theme = $value;
            }
        };

        _this.getTheme = function(){
            return optionsKeyboard.theme;
        };

        _this.setEnabled = function($value){
            if (!$value){
                $('div#keyboard button').attr('disabled', 'disabled');
                optionsKeyboard.enabled = false;
            }
            else{
                $('div#keyboard button').removeAttr("disabled");
                optionsKeyboard.enabled = true;
            }
        };

        _this.getEnabled = function(){
            return optionsKeyboard.enabled;
        };

        _this.setHidden = function($value){
            if (!$value){
                hideKeyboard();
            }
            else{
                showKeyboard();
            }
        };

        _this.getHidden = function(){
            return optionsKeyboard.is_hidden;
        };

        _this.setOpenSpeed = function($value){
            if ($value >= 100)
                optionsKeyboard.open_speed = parseInt($value);
        };

        _this.getOpenSpeed = function(){
            return optionsKeyboard.open_speed;
        };

        _this.setCloseSpeed = function($value){
            if ($value >= 100)
                optionsKeyboard.close_speed = parseInt($value);
        };

        _this.getCloseSpeed = function(){
            return optionsKeyboard.close_speed;
        };

        _this.SubmitKey = function(){};

        /******************************/
        /* Tipos de teclado e Idiomas */
        /******************************/
        var languages = {
            en_US : {
                gatekeeper: [
                    //{d: 'div', u: ''},
                    {d: 'q',u: 'Q'},
                    {d: 'w',u: 'W'},
                    {d: 'e',u: 'E'},
                    {d: 'r',u: 'R'},
                    {d: 't',u: 'T'},
                    {d: 'y',u: 'Y'},
                    {d: 'u',u: 'U'},
                    {d: 'i',u: 'I'},
                    {d: 'o',u: 'O'},
                    {d: 'p',u: 'P'},
                    {d: 'backspace', u: '&larr;'},   // Backspace


                    {d: 'capslock', u: '&udarr; CapsLock'}, // Caps lock
                    {d: 'a',u: 'A'},
                    {d: 's',u: 'S'},
                    {d: 'd',u: 'D'},
                    {d: 'f',u: 'F'},
                    {d: 'g',u: 'G'},
                    {d: 'h',u: 'H'},
                    {d: 'j',u: 'J'},
                    {d: 'k',u: 'K'},
                    {d: 'l',u: 'L'},
                    {d: 'shift', u: '&DoubleUpArrow; Shift'},       // Left shift
                    {d: 'z',u: 'Z'},
                    {d: 'x',u: 'X'},
                    {d: 'c',u: 'C'},
                    {d: 'v',u: 'V'},
                    {d: 'b',u: 'B'},
                    {d: 'n',u: 'N'},
                    {d: 'm',u: 'M'},
                    {d: 'delete', u: '&rarr; Del'},         // Delete
                    {d: 'enter', u: '&crarr; Enter'},


                    {d: 'space', u: 'Space'},           // Space

                    {d: 'divisor', u: 'divisor'} ,      // row divisor

                    //{d: 'backspace', u: 'BackSpace'},   // Backspace


                    {d: '7',u: '7'},
                    {d: '8',u: '8'},
                    {d: '9',u: '9'},
                    {d: '4',u: '4'},
                    {d: '5',u: '5'},
                    {d: '6',u: '6'},
                    {d: '1',u: '1'},
                    {d: '2',u: '2'},
                    {d: '3',u: '3'},
                    {d: '0',u: '0'},
                    {d: 'submit', u: 'Submit'}
                ]
            }
        };
    };

    // Esta función genera la instancia de nuestra Clase
    $.fn.keyboard = function(options){
        return this.each(function(){
            var oElemento = $(this);

            // Si ya se cuenta con una instancia del objeto
            // hacemos un return para evitar generarla nuevamente
            if(oElemento.data('pluginKeyboard')) return;

            // aquí generamos el objeto donde ingresamos el parametro
            // "this" que sera nuestro elemento
            var oKeyboard = new Keyboard(oElemento, options);
            oKeyboard.init();

            // Ahora guardamos la instancia del objeto en el elemento
            oElemento.data('pluginKeyboard', oKeyboard);
        });
    };
})(jQuery);
