/**
* @author Rafael Melo
* @email Rafael.Melo@Sabre.com
* @date 20091118
* @class InputMask
* @version 1.0
* @lastUpdate Rafael Melo 20091118
*/

function InputMask(pHtmObj) {
	
	var htmObj = pHtmObj,
		arr = [];
	
	var Mask = {
        Chars: {
			Numeric: "#",
        	Alpha: "A"
		},
		NearestChar: function(htmObj, cursorPosition, dir) {
            var nearestChar = (htmObj.DataIndex.length > 0) ? cursorPosition : htmObj.MaskIndex[0];
            switch (dir) {
                case -1:
                    for (var i = htmObj.DataIndex.length - 1; i > -1; i--) {
                        if (htmObj.DataIndex[i] < cursorPosition) {
                            nearestChar = htmObj.DataIndex[i];
                            break;
                        };
					};
					break;
                case 0:
                    for (var i = 0; i < htmObj.DataIndex.length; i++) {
                        if (htmObj.MaskIndex[i] >= cursorPosition) {
                            nearestChar = htmObj.MaskIndex[i];
                            break;
                        }
                        else {
                            nearestChar = htmObj.MaskIndex[htmObj.DataIndex.length];
                        };
                    };
					break;
                case 1:
                    for (var i = 0; i < htmObj.DataIndex.length; i++) {
                        if (htmObj.DataIndex[i] > cursorPosition) {
                            nearestChar = htmObj.DataIndex[i];
                            break;
                        };
                    };                        
					if (cursorPosition == htmObj.MaskIndex[htmObj.MaskIndex.length - 1]) {
                        nearestChar = cursorPosition + 1;
                    }
                    else {
						if (cursorPosition == htmObj.DataIndex[htmObj.DataIndex.length - 1]) {
                            nearestChar = htmObj.MaskIndex[htmObj.DataIndex.length];
                        };
					};
					break;
            };
            return nearestChar;
        },
        IsComplex: function(htmObj) {
            var isComplex = false;
            var previousMaskChar = "";
            for (var i = 0; i < htmObj.MaskIndex.length; i++) {
                var currentMaskChar = htmObj.Mask[htmObj.MaskIndex[i]];
                if (currentMaskChar != previousMaskChar && previousMaskChar != "") {
                    isComplex = true;
                };
                previousMaskChar = currentMaskChar;
            };
            return isComplex
        }
    };
	
    var Cursor = {
        GetPos: function(htmObj) {
            var arr = [0, 0];
            if (htmObj.selectionStart && htmObj.selectionEnd) {
                arr[0] = htmObj.selectionStart;
                arr[1] = htmObj.selectionEnd;
            }
            else {
				if (document.selection) {
                    var range = htmObj.createTextRange();
                    range.setEndPoint("EndToStart", document.selection.createRange());
                    arr[0] = range.text.length;
                    arr[1] = document.selection.createRange().text.length;
                };
			};
            return arr;
        },
		Move: function(htmObj, dir) {
            var cursorPos = this.GetPos(htmObj)[0];
            var startIdx = Mask.NearestChar(htmObj, cursorPos, dir);
            this.SetPos(htmObj, startIdx);
        },
        SetPos: function(htmObj, startIdx) {
            var endIdx = startIdx + ((htmObj.HighlightChar) ? 1 : 0);
            if (htmObj.createTextRange) {
	            var fld = htmObj.createTextRange();
	            fld.moveStart("character", startIdx);
	            fld.moveEnd("character", endIdx - htmObj.value.length);
	            fld.select();
	        }
	        else {
	            if (htmObj.setSelectionRange) {
	                htmObj.setSelectionRange(startIdx, endIdx);
	            };
			};
        }
    };
    
	var Data = {
        AddData: function(htmObj, chr) {
            var cursorPos = Cursor.GetPos(htmObj)[0];
            if (htmObj.InsertActive) {
                var lastCharPos = htmObj.MaskIndex[htmObj.MaskIndex.length - 1];
	            var currentCharPos = this.CurrentIdxPos(htmObj);
	            for (var i = lastCharPos; i >= currentCharPos; i--) {
	                htmObj.Data[htmObj.MaskIndex[i + 1]] = htmObj.Data[htmObj.MaskIndex[i]];
	            };
	            htmObj.Data[htmObj.MaskIndex[currentCharPos]] = chr;
            }
            else {
                htmObj.Data[cursorPos] = chr;
            };
            this.UpdateIndex(htmObj);
        },
        RemoveChar: function(htmObj) {
            var lastCharPos = htmObj.DataIndex[htmObj.DataIndex.length - 1];
            var currentCharPos = this.CurrentIdxPos(htmObj);
            var cursorPos = Cursor.GetPos(htmObj)[0];
            if (currentCharPos != null && lastCharPos >= cursorPos) {
                for (var i = currentCharPos; i <= lastCharPos; i++) {
                    htmObj.Data[htmObj.DataIndex[i]] = htmObj.Data[htmObj.DataIndex[i + 1]];
                };
                htmObj.Data.length = htmObj.Data.length - 1;
                this.UpdateIndex(htmObj);
            };
        },
        UpdateIndex: function(htmObj) {
            htmObj.DataIndex.length = 0;
            for (var i = 0; i < htmObj.Data.length; i++) {
                if (htmObj.Data[i] != undefined) 
                    htmObj.DataIndex[htmObj.DataIndex.length] = i;
            };
        },
        CurrentIdxPos: function(htmObj) {
            var cursorPos = Cursor.GetPos(htmObj)[0];
            var currentDataIndexPosition = null;
            for (var i = 0; i < htmObj.MaskIndex.length; i++) {
                if (htmObj.MaskIndex[i] == cursorPos) {
                    currentDataIndexPosition = i;
                    break;
                };
            };
            return currentDataIndexPosition;
        }
    };
	
	var evt = function(e) {
        e = (!e) ? window.event : e;
        if (this.Mask[Cursor.GetPos(this)[0]] == undefined) {
            var startIdx = null;
            if (this.DataIndex.length > 0 && this.DataIndex.length != this.MaskIndex.length) {
                startIdx = this.MaskIndex[this.DataIndex.length];
            }
            else {
				if (this.DataIndex.length == this.MaskIndex.length) {
                    startIdx = this.DataIndex[this.DataIndex.length - 1] + 1;
                }
                else {
                    startIdx = this.MaskIndex[0];
                };
			};                        
            Cursor.SetPos(this, startIdx);
        };
        //Backspace
        if (e.keyCode == 8 && e.type == "keydown" && this.AllowInsert) {
            var preBackspaceCursorPosition = Cursor.GetPos(this)[0];
            Cursor.Move(this, -1);
            var postBackspaceCursorPosition = Cursor.GetPos(this)[0];
            if (preBackspaceCursorPosition != postBackspaceCursorPosition) {
               Data.RemoveChar(this);
            };
            Render(this);
        };
        //Tab
        if (e.keyCode == 9 && e.type == "keydown") { return; }
        //Enter
        else if (e.keyCode == 13 && e.type == "keyup") { return; }
        //End
        else if (e.keyCode == 35 && e.type == "keydown") {
            var startIdx = Mask.NearestChar(this, this.DataIndex[this.DataIndex.length - 1], 1);
            Cursor.SetPos(this, startIdx);
        }
        //Home
        else if (e.keyCode == 36 && e.type == "keydown") {
            Cursor.SetPos(this, this.MaskIndex[0]);
        }
        //Left or Up
        else if (e.keyCode == 37 && e.type == "keydown" || e.keyCode == 38 && e.type == "keydown") {
            Cursor.Move(this, -1);
        }
        //Right or Down
        else if (e.keyCode == 39 && e.type == "keydown" || e.keyCode == 40 && e.type == "keydown") {
            Cursor.Move(this, 1);
        }
        //Insert
        else if (e.keyCode == 45 && e.type == "keydown" && this.AllowInsert) {
            if (this.InsertActive) {
                this.InsertActive = false;
                this.HighlightChar = true;
            }
            else {
                this.InsertActive = true;
                this.HighlightChar = false;
            };
            var startIdx = Cursor.GetPos(this)[0];
            Cursor.SetPos(this, Cursor.GetPos(this)[0]);
        }
        //Delete
        else if (e.keyCode == 46 && e.type == "keydown") {
            if (this.InsertActive) {
                Data.RemoveChar(this);
            }
            else {
                var currentCharPos = Data.CurrentIdxPos(this);
	            if (currentCharPos != null) {
	                this.Data[this.DataIndex[currentCharPos]] = "";
	            };
            };
            Render(this);
        }
        //Numeric Characters
        else if ((this.Mask[Cursor.GetPos(this)[0]] == Mask.Chars.Numeric) && (e.keyCode >= 48 && e.keyCode <= 57 && e.type == "keydown" || e.keyCode >= 96 && e.keyCode <= 105 && e.type == "keydown")) {
            var keycode = parseInt(e.keyCode);
            keycode = (keycode >= 96 && keycode <= 105) ? keycode - 48 : keycode;
            Data.AddData(this, String.fromCharCode(keycode));
            Render(this);
            Cursor.Move(this, 1);
        }
        //Alpha Characters
        else if ((this.Mask[Cursor.GetPos(this)[0]] == Mask.Chars.Alpha) && (e.keyCode >= 65 && e.keyCode <= 90 && e.type == "keydown")) {
            Data.AddData(this, String.fromCharCode(e.keyCode));
            Render(this);
            Cursor.Move(this, 1);
        }
        //Refresh
        else if (e.keyCode == 116 && e.type == "keydown") {
            return;
        };
        return false;
    };
	
	var MouseUp = function(e) {
        e = (!e) ? window.event : e;
        var cursorPos = Cursor.GetPos(this)[0];
        var startIdx = Mask.NearestChar(this, cursorPos, 0);
        Cursor.SetPos(this, startIdx);
    };
	
    var Render = function(htmObj) {
        htmObj.CursorPersistance = Cursor.GetPos(htmObj);
		var composite = [];
        for (var i = 0; i < htmObj.Mask.length; i++) {
            composite[i] = htmObj.Mask[i];
            if (htmObj.DefaultText[i]) {
				composite[i] = htmObj.DefaultText[i];
			};
            if (htmObj.Data[i]) {
				composite[i] = htmObj.Data[i];
			};
        };
        htmObj.value = composite.join("");
        Cursor.SetPos(htmObj, htmObj.CursorPersistance[0]);
    };
	
	if (htmObj.type == "text") {
        htmObj.Data = [];
        htmObj.DataIndex = [];
        htmObj.DefaultText = (htmObj.maskData[1]) ? htmObj.maskData[1].split("") : htmObj.maskData[0].split("");
        arr = [];
		for (var i = 0; i < htmObj.maskData[0].length; i++) {
        	for (var maskChar in Mask.Chars) {
                var chr = Mask.Chars[maskChar];
                if (htmObj.maskData[0].substring(i, i + 1) == chr) {
                    arr[i] = chr;
                };
        	};
		};
		htmObj.Mask = arr;
        arr = [];
        for (var i = 0; i < htmObj.Mask.length; i++) {
            if (htmObj.Mask[i] != null) {
				arr[arr.length] = i;
			};
        };
		htmObj.MaskIndex = arr;
		htmObj.CursorPersistance = [];
        htmObj.InsertActive = (Mask.IsComplex(htmObj)) ? false : true;
        htmObj.HighlightChar = (Mask.IsComplex(htmObj)) ? true : false;
        htmObj.AllowInsert = (Mask.IsComplex(htmObj)) ? false : true;
		htmObj.value = htmObj.DefaultText.join("");
        htmObj.onkeyup = evt;
        htmObj.onkeydown = evt;
        htmObj.onmouseup = MouseUp;
    }
    else {
        throw new Error('InputMask Error: wrong object type , waiting for [html object] TextBox.');
    };
	
};
