/**
 * Gfaces Password
 */
PrimeFaces.widget.GFacesPassword = PrimeFaces.widget.InputText.extend({

	init : function(cfg) {
		this._super(cfg);
		var $this = this;

		this.input = this.jq;

		var state = {
			value : this.cfg.value || '',
			selection : undefined,
			keyCode : undefined,
			isUndo : false,
			widget : $this,
			pasteData : {}
		}

		if (!this.cfg.allowSaving) {
			this.hinput = $(this.jqId + '_hinput');

			this.disableContextMenu();
			this.disableCutCopy();
			this.handlePaste(state);
			this.bindKeyEvents(state);
			this.bindMouseEvents(state);
			this.bindNewMethods(state);
		}

		this.setValue(state);
	},

	// Disables the context menu.
	// We don't want the context menu for the password field because
	// there is no way to detect changes on rightclick + delete in IE9
	disableContextMenu : function() {
		var $this = this;
		var input = $this.input;

		input.on('contextmenu', function(e) {
			e.preventDefault();
			return false;
		});
	},

	disableCutCopy : function() {
		var $this = this;
		var input = $this.input;

		input.on('copy cut', function(e) {
			e.preventDefault();
			return false;
		});
	},

	bindKeyEvents : function(state) {
		var $this = state.widget;
		var input = $this.input;

		input.on('keydown', function(event) {
			state.selection = input.getSelection();
			var keyCode = event.which;
			state.keyCode = keyCode;
			state.isUndo = (event.ctrlKey || event.metaKey) && keyCode == 90;
			if (keyCode == 8 || keyCode == 46) {
				$this.handleDelete(state);
				$(this).trigger('input');
				return false;
			} else if (state.isUndo) {
				// Need to capture this here because IE9 is not triggering the
				// input event when doing an undo
				state.widget.input.val('');
				state.value = '';
				state.widget.hinput.val('');
				$(this).trigger('input');
				return false;
			}
		});

		input.on('input', function(event) {
			if (state.keyCode != 8 && state.keyCode != 46 && !state.isUndo) {
				$this.handleInput(event, state);
			}
		});

	},

	bindMouseEvents : function(state) {
		var $this = state.widget;
		var input = $this.input;
		input.on('mouseup', function(event) {
			state.selection = input.getSelection();
		});
	},

	//Add some functions the input field so that they can be accessed anywhere
	bindNewMethods : function(state) {
		var $this = this;
		
		//Add a function so that we can programitically set the password field value
		this.input[0].applyValue = function(value) {
			state.value = value;
			$this.setValue(state);
		};

		//Add function to get the hidden input field
		this.input[0].getHidden = function() {
			if (!$this.cfg.allowSaving) {
				return $this.hinput[0];
			}
			return null;
		};
	},

	handleDelete : function(state) {
		var submitVal = state.value || '';
		var selection = state.selection;
		var cursorPos = selection.start;
		var keyCode = state.keyCode;

		// Handle delete and backspace keys
		var delEnd = selection.start + 1;
		var delStart = selection.start;
		if (selection.length > 0) {
			delEnd = selection.end;
		} else if (keyCode == 8) {
			delStart -= 1;
			delEnd = selection.start;
			if (cursorPos > 0) {
				cursorPos -= 1;
			}
		}

		submitVal = submitVal.substring(0, delStart)
				+ submitVal.substring(delEnd);

		state.value = submitVal;
		state.widget.setValue(state, cursorPos);
	},

	handlePaste : function(state) {
		var pasteData = state.pasteData;
		var $this = state.widget;
		var input = $this.input;

		input.on('paste', function(event) {
			pasteData.pasted = true;
			var clipboardData = event.originalEvent.clipboardData
					|| window.clipboardData;

			pasteData.value = clipboardData.getData('Text');
		});

	},
	handleInput : function(event, state) {
		var selection = state.selection;
		if (!selection) {
			// If the selection does not exist we do not want to continue.
			// This can happen in IE if there is placeholder
			// text as on focus incorrectly triggers the input event.
			return;
		}
		var keyCode = state.keyCode;
		var submitVal = state.value || '';
		var cursorPos = selection.start;
		// Create the hidden field data

		// Handle any text input
		var pasteData = state.pasteData;
		var value;
		if (pasteData.pasted) {
			pasteData.pasted = false;
			value = pasteData.value;
		} else {
			value = state.widget.input.val().substring(selection.start,
					selection.start + 1);

		}

		submitVal = submitVal.substring(0, selection.start) + value
				+ submitVal.substring(selection.end);
		cursorPos += value.length;

		// update the hidden field
		state.value = submitVal;
		state.widget.setValue(state, cursorPos);

		return true;
	},

	setValue : function(state, cursorPos) {
		var $this = state.widget;
		var value = state.value.replace(/\r?\n|\r/g, "");
		var input = $this.input;

		// If there is no cursor position passed in or if the value length = 0
		// then we don't want to set the position of the field.
		var setPosition = !(cursorPos === undefined) && value.length > 0;

		if (cursorPos != 0) {
			cursorPos = cursorPos || value.length;
		}

		if (!$this.cfg.allowSaving) {
			$this.hinput.val(value);

			// Show only dots
			var length = value.length;
			// TODO we should be able to pass dynamic mask character if
			// neccessary
			input.val(Array(length + 1).join("•"));
		} else {
			input.val(value);
		}

		if (input.setSelection && setPosition) {
			input.setSelection(cursorPos, cursorPos);
		}

	}

});