/*
 * Copyright (c) 2007 Josh Bush (digitalbush.com)
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:

 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE. 
 */
 
/*
 * Version: 1.0
 * Release: 2007-07-25
 */ 
(function($) {
    //Helper Functions for Caret positioning
    function getCaretPosition(ctl) {
        var res = { begin: 0, end: 0 };
        if (ctl.setSelectionRange) {
            res.begin = ctl.selectionStart;
            res.end = ctl.selectionEnd;
        } else if (document.selection && document.selection.createRange) {
            var range = document.selection.createRange();
            res.begin = 0 - range.duplicate().moveStart('character', -100000);
            res.end = res.begin + range.text.length;
        }
        return res;
    };

    function setCaretPosition(ctl, pos) {
        try {
            if (ctl.createTextRange) {
                var range = ctl.createTextRange();
                range.collapse(true);
                range.moveEnd('character', pos);
                range.moveStart('character', pos);
                range.select();
            }
            else if (ctl.setSelectionRange) {
                ctl.setSelectionRange(pos, pos);
            }
        }
        catch (B) {
            //ctl.focus();
            var test = B.d != null ? B.d : B;
            alert(test);
        }
    };

    //Predefined character definitions
    var charMap = {
        'j': "[0-3]",
        'J': "[0-9]",
        'm': "[0-1]",
        'M': "[0-9]",
        'a': "[1-2]",
        's': "[0,9]",
        'A': "[0-9]"
    };

    //Helper method to inject character definitions
    $.mask = {
        addPlaceholder: function(c, r) {
            charMap[c] = r;
        }
    };


    //Main Method
    $.fn.mask = function(mask, format, settings) {
        settings = $.extend({
            placeholder: "_",
            completed: null,
            format: format
        }, settings);

        //Build Regex for format validation
        var reString = "^";
        for (var i = 0; i < mask.length; i++)
            reString += (charMap[mask.charAt(i)] || ("\\" + mask.charAt(i)));
        reString += "$";
        var re = new RegExp(reString);

        return this.each(function() {
            var input = $(this);
            var buffer = new Array(mask.length);
            var locked = new Array(mask.length);

            //Build buffer layout from mask
            for (var i = 0; i < mask.length; i++) {
                locked[i] = charMap[mask.charAt(i)] == null;
                buffer[i] = locked[i] ? mask.charAt(i) : settings.placeholder;
            }

            /*Event Bindings*/
            input.focus(function() {
                answerBuffer.AddAnswer(input.attr("name"), input.val());
                if (validerVal(input.val())) {
                    buffer = loadBuffer(input.val());
                }
                buffer = new checkVal2(buffer);
                writeBuffer1(buffer, undefined);
                setCaretPosition(this, 0);
                if ($("div[id=tmpDivMask]").length == 0) {
                    var tmpDiv = $("<div id=\"tmpDivMask\" class=\"tmpDivMask\" ><table cellpadding=\"0\" cellspacing=\"0\"><tr><td><img src=\"../../img/common/auto/testCorner.PNG\" /></td><td style=\"padding-bottom:1px;padding-top:1px\">" + format + "</td></tr></table></div>");
                    var offset = input.offset();
                    var top = isIE6 ? offset.top - 1 : offset.top - input.outerHeight() - 1;
                    var left = isIE6 ? offset.left + input.outerWidth() + 7 : offset.left + input.outerWidth() + 4;
                    tmpDiv.css("top", top + "px");
                    tmpDiv.css("left", left + "px");
                    tmpDiv.css("width", (input.outerWidth() + 5) + "px");
                    $("body").append(tmpDiv);
                }
            });

            input.blur(function() {
                $("div[id=tmpDivMask]").remove();
                var currentVal = $(this).val();
                var century = { before: '19', after: '20' };
                var daysMonths;
                var decade;
                var months;
                //Si la saisie est volontairement incomplète (i.e.: 01/01/01) on complète le siècle à 
                //partir d'un seuil de décennies. Si les décennies > 20, alors on considère qu'il s'agit 
                //d'une date en 1900.
                if (currentVal.length == 10) {
                    Exp1 = new RegExp("\\d{2}/\\d{2}/\\d{2}_{2}", 'gi');
                    if (Exp1.test(currentVal)) {
                        daysMonths = currentVal.substring(0, 6);
                        decade = currentVal.substring(6, 8);
                        currentVal = (decade > century.after) ? daysMonths + century.before + decade : daysMonths + century.after + decade;
                        $(this).val(currentVal);
                        buffer = loadBuffer($(this).val());
                    }
                }
                if (currentVal.length == 7) {
                    Exp2 = new RegExp("\\d{2}/\\d{2}_{2}", 'gi');
                    if (Exp2.test(currentVal)) {
                        months = currentVal.substring(0, 3);
                        decade = currentVal.substring(3, 5);
                        currentVal = (decade > century.after) ? months + century.before + decade : months + century.after + decade;
                        $(this).val(currentVal);
                        buffer = loadBuffer($(this).val());
                    }
                }
                buffer = checkVal2(buffer);

                if (!validerVal($(this).val())) {
                    $(this).val(format);
                }
            });


            //Paste events for IE and Mozilla thanks to Kristinn Sigmundsson
            if ($.browser.msie)
                this.onpaste = function() { setTimeout(checkVal2(buffer), 0); };
            else if ($.browser.mozilla)
                this.addEventListener('input', checkVal2(buffer), false);

            var ignore = false;  //Variable for ignoring control keys

            input.keydown(function(e) {
                var pos = getCaretPosition(this);
                var k = e.keyCode;
                ignore = (k < 16 || (k > 16 && k < 32) || (k > 32 && k < 41));

                //delete selection before proceeding
                if ((pos.begin - pos.end) != 0 && (!ignore || k == 8 || k == 46)) {
                    buffer = clearBuffer1(buffer, pos.begin, pos.end);
                }
                //backspace and delete get special treatment
                if (k == 8) {//backspace					
                    while (pos.begin-- >= 0) {
                        if (!locked[pos.begin]) {
                            buffer[pos.begin] = settings.placeholder;
                            if ($.browser.opera) {
                                //Opera won't let you cancel the backspace, so we'll let it backspace over a dummy character.								
                                writeBuffer1(buffer, pos.begin);
                                setCaretPosition(this, pos.begin + 1);
                            } else {
                                writeBuffer1(buffer, undefined);
                                setCaretPosition(this, pos.begin);
                            }
                            return false;
                        }
                    }
                } else if (k == 46) {//delete
                    buffer = clearBuffer1(buffer, pos.begin, pos.begin + 1);
                    writeBuffer1(buffer, undefined);
                    setCaretPosition(this, pos.begin);
                    return false;
                } else if (k == 27) {
                    buffer = clearBuffer1(buffer, 0, mask.length);
                    writeBuffer1(buffer, undefined);
                    setCaretPosition(this, 0);
                    return false;
                }

            });

            input.keypress(function(e) {
                if (ignore) {
                    ignore = false;
                    return;
                }
                e = e || window.event;

                var k = e.charCode || e.keyCode || e.which;
                var pos = getCaretPosition(this);
                var caretPos = pos.begin;

                if (e.ctrlKey || e.altKey) {//Ignore
                    return true;
                } else if ((k >= 41 && k <= 122) || k == 32 || k > 186) {//typeable characters
                    while (pos.begin < mask.length) {
                        var reString = charMap[mask.charAt(pos.begin)];
                        var match;
                        if (reString) {
                            var reChar = new RegExp(reString);
                            match = String.fromCharCode(k).match(reChar);
                        } else {//we're on a mask char, go forward and try again
                            pos.begin += 1;
                            pos.end = pos.begin;
                            caretPos += 1;
                            continue;
                        }

                        if (match)
                            buffer[pos.begin] = String.fromCharCode(k);
                        else
                            return false; //reject char

                        while (++caretPos < mask.length) {//seek forward to next typable position
                            if (!locked[caretPos])
                                break;
                        }
                        break;
                    }
                } else
                    return false;

                writeBuffer1(buffer, undefined);
                if (settings.completed && caretPos >= buffer.length)
                    settings.completed.call(input);
                else
                    setCaretPosition(this, caretPos);

                return false;
            });


            function checkVal2(b) {
                //try to place charcters where they belong
                var test = input.val();
                var pos = 0;
                for (var i = 0; i < mask.length; i++) {
                    if (!locked[i]) {
                        //while (pos++ < test.length) {
                        //Regex Test each char here.
                        var reChar = new RegExp(charMap[mask.charAt(i)]);
                        if (test.charAt(i).match(reChar)) {
                            b[i] = test.charAt(i);
                            //break;
                        }
                        else {
                            b[i] = settings.placeholder;
                        }
                        //}
                    }
                }
                var s = writeBuffer1(b, undefined);
                if (!s.match(re)) {
                    input.val(settings.format);
                    b = clearBuffer1(b, 0, mask.length);
                }
                return b;
            };

            function writeBuffer1(b, pos) {
                var s = "";
                for (var i = 0; i < mask.length; i++) {
                    s += b[i];
                    if (i == pos)
                        s += settings.placeholder;
                }
                input.val(s);
                return s;
            };

            function clearBuffer1(b, start, end) {
                for (var i = start; i < end; i++) {
                    if (!locked[i])
                        b[i] = settings.placeholder;
                }
                return b;
            };


            function validerVal(val) {

                switch (settings.format) {
                    case "JJ/MM/AAAA":
                        return validerDate(val);
                    case "MM/AAAA":
                        return validerDate("01/" + val);
                    case "JJ/MM":
                        //Année bisextile
                        return validerDate(val + "/2000");
                    case "AAAA":
                        return validerDate("01/01/" + val);
                    case "MM":
                        return validerDate("01/" + val + "/2000");
                    default:
                        return false;
                }
            };


            function loadBuffer(val) {
                for (var i = 0; i < mask.length; i++) {
                    buffer[i] = val.charAt(i);
                    //locked[i] = true;
                }
                return buffer;
            }

        });
    };
})(jQuery);
