(function ($) {

    var methods = {
        //Constructeur du plugin
        init : function () {
            return this.each(function () {

                var self            = this;
                var $this           = $(this);

                //Si l'input est de type text
                if ($this.is(':text, :password, input[type="email"]') && $this.attr('id') !== undefined) {
                    //Permet de retenir une valeur par défault si il y a
                    var defaultValue    = null;
                    //Permet de retenir une autre type d'input (pour le cas du password par exemple)
                    var secondInput     = null;

                    defaultValue    = $this.attr('alt') === undefined ? $this.val():$this.attr('alt');
                    defaultColor    = $this.css('color');
                    //Si une valeur par défault est entré, on commence la gestion

                    if ($this.attr('alt') !== undefined) {
                        $this.css('color', '#000');
                    }

                    //Au focus on efface si necessaire
                    $this.focus(function () {
                        if ($this.val().length == defaultValue.length && $this.val() === defaultValue) {
                            if ($this.is(':password') && secondInput !== null) {
                                secondInput.hide();
                                $this.show();
                            }

                            $this.val('');
                            $this.css('color', '#000');
                        }
                    });

                    //Au blur on affiche si necessaire
                    $this.blur(function () {
                        if (defaultValue !== null && ($this.val() === defaultValue || $.trim($this.val()).length == 0)) {
                            if ($this.is(':password') && secondInput !== null) {
                                $this.hide();
                                secondInput.show();
                            }

                            $this.val(defaultValue);
                            $this.css('color', defaultColor);
                        }
                    });

                    $this.change(function () {
                        if (defaultValue !== null && ($this.val() === defaultValue || $.trim($this.val()).length == 0)) {
                            if ($this.is(':password') && secondInput !== null) {
                                $this.hide();
                                secondInput.show();
                            }

                            $this.css('color', defaultColor);
                        }
                        else {
                            if ($this.is(':password') && secondInput !== null) {
                                secondInput.hide();
                                $this.show();
                            }

                            $this.css('color', '#000');
                        }
                    });

                    if ($this.val().length > 0 || $this.attr('alt') !== undefined) {

                        //Si l'input est de type password on a besoin d'un input text
                        if ($this.is(':password')) {
                            secondInput = $('<input />').attr({type : 'text', 'class' : $this.attr('id')}).val(defaultValue).focus(function () {
                                $this.focus();
                            });
                            $this.after(secondInput);
                            $this.hide();
                        }

                    }

                }
                //Sinon si c'est select
                else if ($this.is('select')) {

                    //Curseur sur les options ?
                    var isOnOptions = false;
                    //Le select a le focus ?
                    var isFocus     = false;
                    //Curseur sur le menu select ?
                    var isOnSelect  = false;
                    //Le menu viens juste d'être ouvert ?'
                    var justOpened  = false;
                    //Une option viens tout juste d'être selectionnée ?
                    var justClicked = false;
                    //Dernière séléction
                    var lastSearch  = 0;
                    //Nombre de recherche
                    var nbSameSearch = 0;
                    //Le menu select
                    var select      = $('<a></a>').attr({'class':'select','href':'#'}).width($this.width());
                    //Le text affiché sur le select
                    var textSelect  = $('<span></span>').attr('class', 'text').width(((40*$this.width())/100) + '%');
                    //Le calque des options
                    var optSelect   = $('<span></span>').attr('class', 'options').width($this.width());
                    //Les options
                    var options     = $('<ul></ul>');

                    //On construit le menu select
                    select.append(textSelect).append(optSelect.hide());
                    optSelect.append(options);

                    //On cache le vrai select et on affiche le notre justre avant
                    $this.hide();
                    $this.before(select);

                    //On construit le menu select
                    $.each($('option', self), function () {
                        var opt = $('<li></li>');

                        if ($(this).attr('value') !== undefined) {
                            opt.attr('value', $(this).attr('value'));
                        }
                        if ($(this).attr('selected') !== undefined) {
                            textSelect.html($(this).text());
                        }

                        opt.click(function () {
                            if ($.browser.msie) {
                                justClicked = true;
                            }
                            $this.val($(this).attr('value'));
                            $this.change();
                            textSelect.html($(this).html());
                            textSelect.change();
                        });
                        opt.mousemove(function () {
                            if (!justOpened) {
                                $('li.hovered').removeClass('hovered');
                                $(this).addClass('hovered');
                            }
                            justOpened = false;
                        }).mouseleave(function () {
                            $(this).removeClass('hovered');
                        });

                        opt.html($(this).text());
                        options.append(opt);
                    });

                    //On selectionne le premier
                    if (textSelect.html().length === 0) {
                        textSelect.html($(':first', options).html());
                    }

                    defaultColor    = textSelect.css('color');

                    textSelect.change(function () {
                        if ($(this).html() == $(':first', options).html()) {
                            $(this).css('color', defaultColor);
                        }
                        else {
                            $(this).css('color', '#000');
                        }
                    });
                    textSelect.change();

                    //Fonction pour afficher/cacher les options
                    function displayOptions(val) {
                        var display = (val !== undefined ? val:!optSelect.is(':visible'));

                        if (display) {
                            justOpened = true;
                            $('li', options).removeClass('wrong');
                            optSelect.show();
                            optSelect.scrollTop(0);

                            $('li.hovered', options).removeClass('hovered');
                            $('li', options).each(function () {
                                if ($(this).html() == textSelect.html()) {
                                    $(this).addClass('hovered');
                                    optSelect.scrollTop($(this).position().top);
                                }
                            });

                            select.css({'backgroundPosition':'right -45px','backgroundColor':'#E5E5E5'});
                        }
                        else {
                            optSelect.hide();
                            select.css({'backgroundPosition':'right -4px','backgroundColor':'#FFF'});
                        }
                    }


                    select.hover(function () {
                        isOnSelect = true;
                    }, function () {
                        isOnSelect = false;
                    });

                    optSelect.hover(function () {
                        isOnOptions = true;
                    }, function () {
                        isOnOptions = false;
                    });

                    $(document).keydown(function (e) {
                        var code = (e.keyCode ? e.keyCode : e.which);
                        if (options.is(':visible')) {

                            //Flèche du bas
                            if (code == 40) {
                                e.preventDefault();
                                if ($('li.hovered', options).length > 0 && $('li.hovered', options).next('li').length > 0) {
                                    $('li.hovered', options).removeClass('hovered').next('li').addClass('hovered');
                                    justOpened = true;
                                    if ($('li.hovered', options).length > 0 && ($('li.hovered', options).position().top + $('li.hovered', options).outerHeight()) > (optSelect.height())) {
                                        optSelect.scrollTop(optSelect.scrollTop() + $('li.hovered', options).outerHeight());
                                    }
                                }
                                else if ($('li.hovered', options).length == 0) {
                                    $('li:first', options).addClass('hovered');
                                    optSelect.scrollTop(0);
                                }
                            }
                            //Flèche du haut
                            else if (code == 38) {
                                e.preventDefault();
                                if ($('li.hovered', options).length > 0 && $('li.hovered', options).prev('li').length > 0) {
                                    $('li.hovered', options).removeClass('hovered').prev('li').addClass('hovered');
                                    justOpened = true;
                                    if ($('li.hovered', options).length > 0 && ($('li.hovered', options).position().top) < 0) {
                                        optSelect.scrollTop(optSelect.scrollTop()- Math.abs($('li.hovered', options).position().top));
                                    }
                                }
                            }
                            //Echap
                            else if (code == 27) {
                                e.preventDefault();
                                $('li.hovered', options).removeClass('hovered');
                                displayOptions(false);
                            }
                            //Entrée
                            else if (code == 13) {
                                e.preventDefault();
                                if ($('li.hovered', options).length > 0) {
                                    $this.val($('li.hovered').attr('value'));
                                    $this.change();
                                    textSelect.html($('li.hovered').html());
                                    textSelect.change();
                                }
                                $('li.hovered', options).removeClass('hovered');
                                displayOptions(false);
                            }
                            //Back space
                            else if (code == 8) {
                                e.preventDefault();
                                $('li.hovered', options).removeClass('hovered');
                                $('li', options).removeClass('wrong');
                            }
                            //Autre touches (lettres, chiffres)
                            else if ((code >= 48 && code <= 57) || (code >= 65 && code <= 90)) {
                                var keyCode = String.fromCharCode(code);
                                var firstIndex = null;
                                var boucle = 0;
                                var changeSearch = false;
                                $('li.hovered', options).removeClass('hovered');
                                $('li', options).each(function (index) {
                                    if ($(this).text().substr(0,1) != keyCode) {
                                        $(this).addClass('wrong');
                                    }
                                    else {
                                        $(this).removeClass('wrong');
                                        if (firstIndex == null) {
                                            firstIndex = index;
                                            nbSameSearch++;
                                        }

                                        if (index > lastSearch && nbSameSearch == boucle) {
                                            lastSearch = index;
                                            changeSearch = true;
                                        }

                                        boucle++;
                                    }
                                });

                                if (!changeSearch && lastSearch > -1) {
                                    lastSearch = firstIndex;
                                    nbSameSearch = 0;
                                }

                                optSelect.scrollTop(0);
                                optSelect.scrollTop($('li', options).eq(lastSearch).position().top);
                                $('li', options).removeClass('hovered');
                                $('li', options).eq(lastSearch).addClass('hovered');
                                justOpened = true;
                            }
                        }
                        else {
                            if (code == 13 && select.is(':focus')) {
                                e.preventDefault();
                                displayOptions(true);
                            }
                        }
                    });

                    select.bind({
                        click : function (e) {
                            e.preventDefault();
                            if (!isFocus) {
                                displayOptions(undefined);
                            }
                            isFocus = false;
                        },
                        focus : function () {
                            if (!optSelect.is(':visible') && !justClicked) {
                                isFocus = true;
                                displayOptions(true);
                            }
                            justClicked = false;
                        },
                        blur : function () {
                            displayOptions(false);
                        }
                    });

                    $("html").click(function () {
                        if (!isOnSelect && !isOnOptions && optSelect.is(':visible')) {
                            displayOptions(false);
                        }
                    });

                    $this.change(function () {
                        textSelect.html($(' option:selected', this).text());
                        textSelect.change();
                    });

                }
            });
        }
    };

    $.fn.input = function (method) {

        //Si le paramètre correspond à une fonction de l'objet méthode.. On lance
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        }
        //Sinon si le param est un objet de parametre ou aucun param, on lance le constructeur
        else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        }
        //Sinon on sait pas !
        else {
            $.error('Method ' +  method + ' does not exist on jQuery.input');
            return false;
        }

    }

})(jQuery);
