(function($) {
	var pasteEventName = ($.browser.msie ? 'paste' : 'input') + ".mask";
	var iPhone = (window.orientation != undefined);


	$.mask = {
		definitions: {
			'0': "[0-9,.]+",
			'9': "[0-9]",
			'a': "[A-Za-ząćęłńóśżźĄĆĘŁŃÓŹŻŹ]",
			'b': "[A-Za-z]",
			'*': "[A-Za-z0-9ąćęłńóśżźĄĆĘŁŃÓŹŻŹ]",
			'h': "[a-fA-F0-9]"
		},

		schemes: {
			'hex': "#hhhhhh",
			'just_hex': "hhhhhh",
			'kod': "99-999",
			'liczba': "9",
			'data': "9999-99-99",
			'data_czas': "9999-99-99 99:99"
		},

		hide_masks: {
			'liczba': true
		}
	}


	$.fn.extend({
		//Helper Function for Caret positioning
		caret: function(begin, end) {
			if (this.length == 0) return;
			if (typeof begin == 'number') {
				end = (typeof end == 'number') ? end : begin;
				return this.each(function() {
					if (this.setSelectionRange) {
						this.focus();
						this.setSelectionRange(begin, end);
					} else if (this.createTextRange) {
						var range = this.createTextRange();
						range.collapse(true);
						range.moveEnd('character', end);
						range.moveStart('character', begin);
						range.select();
					}
				});
			} else {
				if (this[0].setSelectionRange) {
					begin = this[0].selectionStart;
					end = this[0].selectionEnd;
				} else if (document.selection && document.selection.createRange) {
					var range = document.selection.createRange();
					begin = 0 - range.duplicate().moveStart('character', -100000);
					end = begin + range.text.length;
				}
				return { begin: begin, end: end };
			}
		},

		unmask: function() { return this.trigger("unmask"); },

		mask: function(pre_mask, settings) {
			if (!pre_mask && this.length > 0) {
				var input = $(this[0]);
				var tests = input.data("tests");
				return $.map(input.data("buffer"), function(c, i) {
					return tests[i] ? c : null;
				}).join('');
			}
			settings = $.extend({
				placeholder: "_",
				completed: null
			}, settings);

			var defs = $.mask.definitions;
			var schemes = $.mask.schemes;
			var hide_masks = $.mask.hide_masks;
			var tests = [];
			var hide_mask=hide_masks[pre_mask];

			if(schemes[pre_mask]==undefined) {
				$.mask.maskkk=pre_mask;
			} else {
				$.mask.maskkk=schemes[pre_mask];
			}
			var maskkk=$.mask.maskkk;

			var partialPosition = maskkk.length;
			var firstNonMaskPos = null;
			var len = maskkk.length;

			if(hide_mask==true) {
				settings.placeholder="";
				len=255;
			}


			$.each(maskkk.split(""), function(i, c) {
				if (c=='?') {
					len--;
					partialPosition = i;
				} else if(defs[c]) {
					tests.push(new RegExp(defs[c]));
					if(firstNonMaskPos==null) firstNonMaskPos = tests.length-1;
				} else {
					tests.push(null);
				}
			});


			return this.each(function() {
				var input = $(this);
				var buffer = $.map(maskkk.split(""), function(c, i) { if (c != '?') return defs[c] ? settings.placeholder : c });
				var ignore = false;  			//Variable for ignoring control keys
				var focusText = input.val();

				input.data("buffer", buffer).data("tests", tests);
				$(input).attr('autocomplete','off');


				function seekNext(pos) {
					while (++pos <= len && !tests[pos]);
					return pos;
				};


				function shiftL(pos) {
					while (!tests[pos] && --pos >= 0);
					for (var i = pos; i < len; i++) {
						if (tests[i]) {
							buffer[i] = settings.placeholder;
							var j = seekNext(i);
							if (j < len && tests[i].test(buffer[j])) {
								buffer[i] = buffer[j];
							} else
								break;
						}
					}
					writeBuffer();
					input.caret(Math.max(firstNonMaskPos, pos));
				};


				function shiftR(pos) {
					for (var i = pos, c = settings.placeholder; i < len; i++) {
						if (tests[i]) {
							var j = seekNext(i);
							var t = buffer[i];
							buffer[i] = c;
							if (j < len && tests[j].test(t))
								c = t;
							else
								break;
						}
					}
				};


				function keydownEvent(e) {
					var pos = $(this).caret();
					var k = e.keyCode;

					var ki	= new Array();
					ki[8]		= 1; //backspace
					ki[9]		= 1; //tab
					ki[13]	= 1; //enter
					ki[16]	= 1; //shift
					ki[17]	= 1; //control
					ki[18]	= 1; //alt
					ki[27]	= 1; //esc
					ki[33]	= 1; //page up
					ki[34]	= 1; //page down
					ki[35]	= 1; //end
					ki[36]	= 1; //home
					ki[37]	= 1; //left
					ki[38]	= 1; //up
					ki[39]	= 1; //right
					ki[40]	= 1; //down
					ki[45]	= 1; //insert
					ki[46]	= 1; //delete
					ki[116]	= 1; //f5
					ki[224]	= 1; //command

					ignore = (k < 16 || (k > 16 && k < 32) || (k > 32 && k < 41) || ki[k]!=undefined);


					//delete selection before proceeding
					if ((pos.begin - pos.end) != 0 && (!ignore || k == 8 || k == 46)) {
						if (k == 8 || (iPhone && k == 127)) {
							clearBuffer(pos.begin, pos.end);
							clearInput(pos.begin, pos.end);
						 	input.caret(pos.begin);
							return;
						} else {
							if (k == 46) {
								clearBuffer(pos.begin, pos.end);
								clearInput(pos.begin, pos.end);
							} else {
								clearBuffer(pos.begin, pos.end);
								clearInput(pos.begin, pos.end);
							 	input.caret(pos.begin);
							}
						}
					}


					//backspace, delete, and escape get special treatment
					if (k == 8 || k == 46 || (iPhone && k == 127)) {//backspace/delete
						e.preventDefault();

						if (k == 8 || (iPhone && k == 127)) {//backspace
							car1=1;
							car2=-1;
						} else { //delete
							car1=1;
							car2=0;
						}

						buff_str=buffer.join('');
					 	for(var z=0; z<buffer.length; z++) {
					 		if(z==pos.begin+car2) {
								if($.mask.definitions[maskkk.substring(pos.begin+car2, pos.begin+car2+1)]!=undefined) {
									buffer[z]=settings.placeholder;
								} else {
									buffer[z]=buff_str.substring(z, z+car1);
								}
					 		}
					 	}

						writeBuffer();
						input.caret(pos.begin+car2);
					} else if (k == 27) {//escape
						input.val(focusText);
						input.caret(0, checkVal());
					}
				};


				function keypressEvent(e) {
					if(e.keyCode==46) return false; //del event (move caret)

					if(ignore) {
						ignore = false;
						//Fixes Mac FF bug on backspace
						return (e.keyCode == 8) ? false : null;
					}
					e = e || window.event;
					var k = e.charCode || e.keyCode || e.which;
					var pos = $(this).caret();

					if (e.ctrlKey || e.altKey || e.metaKey) {//Ignore
						return true;
					} else if ((k >= 32 && k <= 125) || k > 186) {//typeable characters
						var p = seekNext(pos.begin - 1);
						if (p < len) {
							var c = String.fromCharCode(k);
							if(tests[p].test(c)) {
								buff_str=buffer.join('');
								shiftR(p);
								buffer[p] = c;

								for(var z=0; z<buffer.length; z++) {
									if(z==p) {
										buffer[z]=c;
									} else {
										buffer[z]=buff_str.substring(z, z+1);
									}
								}
								writeBuffer();

								var next = seekNext(p);
								$(this).caret(next);
								if (settings.completed && next == len) settings.completed.call(input);
							}
						}
					}
					return false;
				};


				function clearBuffer(start, end) {
					for (var i = start; i < end && i < len; i++) {
						if (tests[i]) buffer[i] = settings.placeholder;
					}
				};


				function clearInput(start, end) {
					for(var i=0; i<buffer.length; i++) {
				 		char_val=buffer[i];
				 		if(i>start-1 && i<end) {
							if($.mask.definitions[maskkk.substring(i, i+1)]!=undefined) {
								buffer[i]=settings.placeholder;
							} else {
					 			buffer[i]=char_val;
							}
				 		}
					}
					writeBuffer();
				};


				function writeBuffer() { return input.val(buffer.join('')).val(); };


				function checkVal(allow) {
					//try to place characters where they belong
					var test = input.val();
					var lastMatch = -1;
					for(var i = 0, pos = 0; i < len; i++) {
						if (tests[i]) {
							buffer[i] = settings.placeholder;
							while(pos++ < test.length) {
								var c = test.charAt(pos - 1);
								if (tests[i].test(c)) {
									buffer[i] = c;
									lastMatch = i;
									break;
								}
							}
							if(pos > test.length) break;
						} else if(buffer[i] == test[pos] && i!=partialPosition) {
							pos++;
							lastMatch = i;
						} 
					}
					if (!allow && lastMatch + 1 < partialPosition) {
						input.val("");
						clearBuffer(0, len);
					} else if (allow || lastMatch + 1 >= partialPosition) {
						writeBuffer();
						if (!allow) input.val(input.val().substring(0, lastMatch + 1));
					}
					return (partialPosition ? i : firstNonMaskPos);
				};

				if (!input.attr("readonly"))
					input
					.one("unmask", function() {
						input
							.unbind(".mask")
							.removeData("buffer")
							.removeData("tests");
					})
					.bind("focus.mask", function() {
						focusText = input.val();
						var pos = checkVal();
						writeBuffer();
						setTimeout(function() {
							if (pos == maskkk.length)
								input.caret(0, pos);
							else
								input.caret(pos);
						}, 0);
					})
					.bind("blur.mask", function() {
						checkVal();
						if (input.val() != focusText)
							input.change();
					})
					.bind("keydown.mask", keydownEvent)
					.bind("keypress.mask", keypressEvent)
					.bind(pasteEventName, function() {
						setTimeout(function() { input.caret(checkVal(true)); }, 0);
					});

				checkVal(); //Perform initial check for existing values
			});
		}
	});
})(jQuery);
