/////////////////////////////////////////////////////////////////////////////
//
// Gladiator Components
//
// http://www.gladiatorweb.com
//
// (c) 2006 by Edward H. Trager .  All Rights Reserved
//
// NAME: gladiatorFormComponent.js
//
// DESCRIPTION: Implements the following form components:
//
//              -> gFormComponent (base class)
//              -> gText
//              -> gDropDown
//              -> gDivider
//
// AUTHOR: Edward H. Trager
//
// LAST UPDATE: 2006.05.22
//
// NOTE: SEE "LICENSE" FILE FOR LICENSING TERMS
//
//////////////////////////////////////////////////////////////////////////////

//
// DEPENDENCY CHECKING:
//
if(typeof GLADIATOR_CORE_INCLUDED == 'undefined') alert('NOTA BENE: "gladiatorFormComponents.js" REQUIRES "gladiatorCore.js"!');

var GLADIATOR_FORM_COMPONENTS_INCLUDED=true;

var GLADIATOR_INPUT_NULL  = '.'; // No input
var GLADIATOR_INPUT_OK    = 'O'; // Passes validation
var GLADIATOR_INPUT_SO_SO = 'S'; // Used for marginally acceptable passwords, etc.
var GLADIATOR_INPUT_BAD   = 'X'; // Fails validation

//////////////////////////////////////////
//
// gFormComponent (Base class)
//
//////////////////////////////////////////
function gFormComponent(label,id,parentNode){
	
	var _label  = label;
	var _id     = id;
	
	// CREATE THE COMPONENT:
	var _thisComponent = document.createElementNS(NS.xhtml,"div");
	_thisComponent.setAttribute("class","formComponent");
	
	if(_label) {
		var _thisLabel = document.createElementNS(NS.xhtml,"div");
		_thisLabel.setAttribute("class","label");
		var _text      = document.createTextNode(label+":");
		_thisLabel.appendChild(_text);
		_thisComponent.appendChild(_thisLabel);
	}
	////////////////////////////////////////////////
	//
	// Add the component node to the DOM tree:
	// By default, add the component to the BODY element,
	// unless some other parentNode was supplied as
	// an argument to the constructor:
	//
	////////////////////////////////////////////////
	if(parentNode){
		parentNode.appendChild(_thisComponent);
		
	}else{
		// Using document.body.appendChild is convenient, but 
		// apparently it is not in the W3C standard ...
		// ==> document.body.appendChild(_thisWindow);
		// The W3C standards way to get the document body:
		var bodyRef = document.getElementsByTagName("body").item(0);
		bodyRef.appendChild(_thisComponent);
	}
	
	this.getNode = function(){
		
		return _thisComponent;
		
	}
	
	this.getId = function(){
		
		return _id;
		
	}
}

//////////////////////////////////////////
//
// gStatusComponent
//
//////////////////////////////////////////
function gStatusComponent(label,id,parentNode){
	
	var _label  = label;
	var _id     = id;
	
	// CREATE THE COMPONENT:
	var _thisComponent = document.createElementNS(NS.xhtml,"div");
	_thisComponent.setAttribute("class","formComponent");
	
	if(_label) {
		var _thisLabel = document.createElementNS(NS.xhtml,"div");
		_thisLabel.setAttribute("class","statusString");
		var _text      = document.createTextNode(label);
		_thisLabel.appendChild(_text);
		_thisComponent.appendChild(_thisLabel);
	}
	if(parentNode){
		parentNode.appendChild(_thisComponent);
	}else{
		var bodyRef = document.getElementsByTagName("body").item(0);
		bodyRef.appendChild(_thisComponent);
	}
	
	this.getNode = function(){
		
		return _thisComponent;
		
	}
	
	this.setLabel = function(labelString){
		
		_text.nodeValue=labelString;
		
	}
	
	this.getId = function(){
		
		return _id;
		
	}
}

//////////////////////////////////////////
//
// gText: Simple text box
//
//////////////////////////////////////////
function gText(label,id,parentNode){
	
	var _parentComponent = new gFormComponent(label,id,parentNode);
	
	var _thisComponent = _parentComponent.getNode();
	var _textBox = document.createElementNS(NS.xhtml,"input");
	_textBox.id=id;
	_textBox.name=id;
	_textBox.setAttribute("class","gTextInput");
	
	_thisComponent.appendChild(_textBox);
	
	this.getNode = function(){
		
		return _thisComponent;
		
	}
	
	this.setValue = function(value){
		_textBox.value = value;
	}
	
	this.getValue = function(){
		return _textBox.value;
	}
	
	this.addEventListener = function(eventType,eventMethod){
		_textBox.addEventListener(eventType,eventMethod,false);
	}
	
}

/////////////////////////////////////////////////////////
//
// gValidatedInput: A gText with regex or custom method validation
//
//       Arguments: label          - label
//
//                  id             - id
//                                   (NOTA BENE: If the id string contains the string 'password', 
//                                   then a password box is created instead of a regular text box.
//
//                  validator      - a (1) regular expression OR a (2) a custom validation method
//                                   taking the input string as input and returning true or false.
//
//                  defaultTooltip - Phrase to show by default
//
//                  invalidTooltip - Phrase to show if input tests invalid.
//                                   Note: may contain "%s" representing the 
//                                   current input text string.
//
//                  isPassword     - True if this is a password field (prints "****" ...)
//
//                  soSoTooltip    - Phrase to show if the result is marginally acceptable
//                                   (Useful for Password strength validation) 
//
//                  parentNode     - Where to insert the object (<body> by default)
//
/////////////////////////////////////////////////////////
function gValidatedInput(label,id,validator,defaultTooltip,invalidTooltip,parentNode,isPassword,soSoTooltip){
	
	var _parentComponent = new gFormComponent(label,id,parentNode);
	
	var _thisComponent = _parentComponent.getNode();
	var _textBox = document.createElementNS(NS.xhtml,"input");
	if(isPassword) _textBox.setAttribute("type","password");
	
	_textBox.id=id;
	_textBox.name=id;
	_textBox.className="gTextInput";
	
	_thisComponent.appendChild(_textBox);
	
	var _inputState=GLADIATOR_INPUT_NULL;
	
	var _validator      = validator;
	var _defaultToolTip = defaultTooltip;
	var _invalidToolTip = invalidTooltip;
	var _soSoToolTip    = soSoTooltip;
	
	_textBox.title=_defaultToolTip;
	
	//
	// getNode
	//
	this.getNode = function(){
		
		return _thisComponent;
		
	}
	
	//
	// setValue
	//
	this.setValue = function(value){
		_textBox.value = value;
	}
	
	//
	// getValue
	//
	this.getValue = function(){
		return _textBox.value;
	}
	
	//
	// validateInput
	//
	function validateInput(){
		
		var inputString = _textBox.value;
		//
		// No input:
		//
		if(inputString==""){
			if(_textBox.className!="gTextInput"){ 
				_textBox.className="gTextInput";
				_textBox.title=_defaultToolTip;
			}
			_inputState=GLADIATOR_INPUT_NULL;
			return true;
		}
		
		var inputOK=false;
		if     ( _validator.test){
			///////////////////////////////////////
			//
			// Regular expression-based validation:
			//
			///////////////////////////////////////
			inputOK =  _validator.test(inputString);
			
		}else if( typeof _validator == "function" ){
			///////////////////////////////////////
			//
			// Custom validation:
			//
			///////////////////////////////////////
			_inputState = _validator( inputString );
			switch(_inputState){
			case GLADIATOR_INPUT_BAD:
				if(_textBox.className!="gTextInputWarning") _textBox.className="gTextInputWarning";
				_textBox.title = _invalidToolTip.replace(/%s/,inputString);
				inputOK=false;
				break;
			case GLADIATOR_INPUT_SO_SO: 
				if(_textBox.className!="gTextInputSoSo") _textBox.className="gTextInputSoSo";
				_textBox.title=_soSoToolTip;
				inputOK=true;
				break;
			case GLADIATOR_INPUT_OK: 
				if(_textBox.className!="gTextInput") _textBox.className="gTextInput";
				_textBox.title=_defaultToolTip;
				inputOK=true;
			}
			return inputOK;
			
		} else {
			///////////////////////////////////////
			//
			// Default:
			//
			///////////////////////////////////////
			inputOK=false;
		}
		
		if(inputOK){
			
			_inputState=GLADIATOR_INPUT_OK;
			if(_textBox.className!="gTextInput"){ 
				_textBox.className="gTextInput";
				_textBox.title=_defaultToolTip;
			}
			
		}else{
			
			_inputState=GLADIATOR_INPUT_BAD;
			if(_textBox.className!="gTextInputWarning") _textBox.className="gTextInputWarning";
			_textBox.title = _invalidToolTip.replace(/%s/,inputString);
			
		}
		return inputOK;
		
	}
	
	//
	// getStatus
	//
	this.getStatus = function(){
		return _inputState;
	}
	
	this.addEventListener = function(eventType,eventMethod){
		_textBox.addEventListener(eventType,eventMethod,false);
	}
	
	///////////////////
	//
	// Event Handlers:
	//
	///////////////////
	
	_textBox.addEventListener("blur",validateInput,false);
	
}

/////////////////////////////////////////////////////////
//
// gNameInput: A gValidatedInput with built-in "name" format validation
//
/////////////////////////////////////////////////////////
function gNameInput(label,id,parentNode){
	
	defaultTooltip = "Please enter a valid name.";
	invalidTooltip = "“%s” is not a valid name.";
	regexFilter = /^[\w]+[ ]*[\w]*$/i ;
	
	var _vi = new gValidatedInput(label,id,regexFilter,defaultTooltip,invalidTooltip,parentNode);
	
	//
	// getNode
	//
	this.getNode = function(){
		
		return _vi.getNode();
		
	}
	
	//
	// setValue
	//
	this.setValue = function(value){
		_vi.setValue(value);
	}
	
	//
	// getValue
	//
	this.getValue = function(){
		return _vi.getValue();
	}
	
	//
	// addEventListener
	//
	this.addEventListener = function(eventType,eventMethod){
		_vi.addEventListener(eventType,eventMethod);
	}
	
}

/////////////////////////////////////////////////////////
//
// gEmailInput: A gValidatedInput with built-in email format validation
//
/////////////////////////////////////////////////////////
function gEmailInput(label,id,parentNode){
	
	defaultTooltip = "Please enter a valid email address.";
	invalidTooltip = "“%s” is not a valid email address.";
	regexFilter = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i ;
	
	var _vi = new gValidatedInput(label,id,regexFilter,defaultTooltip,invalidTooltip,parentNode);
	
	//
	// getNode
	//
	this.getNode = function(){
		
		return _vi.getNode();
		
	}
	
	//
	// setValue
	//
	this.setValue = function(value){
		_vi.setValue(value);
	}
	
	//
	// getValue
	//
	this.getValue = function(){
		return _vi.getValue();
	}
	
	//
	// addEventListener
	//
	this.addEventListener = function(eventType,eventMethod){
		_vi.addEventListener(eventType,eventMethod);
	}
	
}

////////////////////////////////////////////////////////////////////////////////
//
// gPasswordInput: A gValidatedInput with built-in password strength validation
//
////////////////////////////////////////////////////////////////////////////////
function gPasswordInput(label,id,parentNode){
	
	defaultTooltip = "Please enter password.";
	invalidTooltip = "Weak password :Use mixed-case letters, numerals, and special characters.";
	soSoTooltip    = "Marginal password: Use mixed-case letters, numerals, and special characters.";
	//
	// checkRepetitions
	//
	function checkRepetition(pLen,str){
		
		res = "";
		for ( i=0; i<str.length ; i++ ) {
			repeated=true;
			for (j=0;j < pLen && (j+i+pLen) < str.length;j++)
				repeated=repeated && (str.charAt(j+i)==str.charAt(j+i+pLen));
			if (j<pLen) repeated=false;
			if (repeated) {
				i+=pLen-1;
				repeated=false;
			}else {
				res+=str.charAt(i);
			}
		}
		return res;
	}
	
	//
	// Password strength validator based on a password strength
	// meter written by firas kassem [2007.04.05] and released under a GPL/MIT license.
	// See: Firas Kassem  phiras.wordpress.com || phiras at gmail {dot} com
	// for more information : http://phiras.wordpress.com/2007/04/08/password-strength-meter-a-jquery-plugin/
	//
	function validator(password){
		
		var score = 0;
		
		if(!password) return GLADIATOR_INPUT_NULL;
		
		//
		//Check if password < 4:
		//
		if (password.length < 4 ) return GLADIATOR_INPUT_BAD;
		
		// TODO:
		//password == username
		// if (password.toLowerCase()==username.toLowerCase()) return GLADIATOR_INPUT_BAD;
		
		//
		// Check password length:
		//
		score += password.length * 4;
		score += ( checkRepetition(1,password).length - password.length ) * 1;
		score += ( checkRepetition(2,password).length - password.length ) * 1;
		score += ( checkRepetition(3,password).length - password.length ) * 1;
		score += ( checkRepetition(4,password).length - password.length ) * 1;
		
		//
		// Check if password has 3 numbers:
		//
		if (password.match(/(.*[0-9].*[0-9].*[0-9])/))  score += 5 ;
		
		//
		// Check if password has 2 symbols:
		//
		if (password.match(/(.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~])/)) score += 5;
		
		//
		// Check if password has Upper and Lower chars:
		//
		if (password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/))  score += 10; 
		
		//
		// Check if password has number and chars:
		//
		if (password.match(/([a-zA-Z])/) && password.match(/([0-9])/))  score += 15;
		//
		// Check if password has number and symbols:
		//
		if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([0-9])/))  score += 15;
		//
		// Check if password has char and symbols:
		//
		if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([a-zA-Z])/))  score += 15; 
		//
		// Check if password is just numbers or chars:
		//
		if (password.match(/^\w+$/) || password.match(/^\d+$/) )  score -= 10;
		//
		// Verifing 0 < score < 100:
		//
		if ( score < 0 )    score = 0;
		if ( score > 100 )  score = 100; 
		
		if (score < 34 )  return GLADIATOR_INPUT_BAD; 
		if (score < 68 )  return GLADIATOR_INPUT_SO_SO;
		return GLADIATOR_INPUT_OK;
		
	}
	
	var _vi = new gValidatedInput(label,id,validator,defaultTooltip,invalidTooltip,parentNode,true,soSoTooltip);
	
	//
	// getNode
	//
	this.getNode = function(){
		
		return _vi.getNode();
		
	}
	
	//
	// setValue
	//
	this.setValue = function(value){
		_vi.setValue(value);
	}
	
	//
	// getValue
	//
	this.getValue = function(){
		return _vi.getValue();
	}
	
	//
	// addEventListener
	//
	this.addEventListener = function(eventType,eventMethod){
		_vi.addEventListener(eventType,eventMethod);
	}
	
}

//////////////////////////////////////////
//
// gFormButton: Input button field
//
//////////////////////////////////////////
function gFormButton(label,id,parentNode){
	
	var _parentComponent = new gFormComponent("",id,parentNode);
	var _thisComponent = _parentComponent.getNode();
	var _button = document.createElementNS(NS.xhtml,"div");
	
	var _disabled=false;
	var _eventMethod=false;
	
	_button.setAttribute("class","gFormButton");
	var _label= document.createTextNode(label);
	_button.appendChild(_label);
	
	_thisComponent.appendChild(_button);
	
	this.getNode = function(){
		
		return _thisComponent;
		
	}
	this.show = function(showIt){
                _show = showIt;
                if(_show){
                        _thisComponent.style.display="block";
                }else{
                        _thisComponent.style.display="none";
                }
        }
	
	//
	// setLabel
	//
	this.setLabel = function(label){
		_button.firstChild.nodeValue=label;
	}
	
	this.enable = function(){
		_disabled = false;
		_button.setAttribute("class","gFormButton");
	}
	
	this.disable = function(){
		_disabled = true;
		_button.setAttribute("class","gFormButtonDisabled");
	}
	
	this.addEventMethod = function(eventMethod){
		_eventMethod = eventMethod;
	}
	
	function mouseDown(){
		
		if(_disabled) return;
		_button.setAttribute("class","gFormButtonDown");
		
	}
	
	function mouseUp(){
		
		if(_disabled) return;
		_button.setAttribute("class","gFormButton");
		if(_eventMethod) _eventMethod();
		
	}
	
	_button.addEventListener("mousedown",mouseDown,false);
	_button.addEventListener("mouseup",mouseUp  ,false);
	
	
	
}

//////////////////////////////////////////
//
// gPassword: Input password field
//
//////////////////////////////////////////
function gPassword(label,id,parentNode){
	
	var _parentComponent = new gFormComponent(label,id,parentNode);
	
	var _thisComponent = _parentComponent.getNode();
	var _textBox = document.createElementNS(NS.xhtml,"input");
	_textBox.id=id;
	_textBox.name=id;
	_textBox.setAttribute("class","gTextInput");
	_textBox.type="password";
	_thisComponent.appendChild(_textBox);
	
	this.getNode = function(){
		
		return _thisComponent;
		
	}
	
	this.setValue = function(value){
		_textBox.value = value;
	}
	
	this.getValue = function(){
		return _textBox.value;
	}
	
	this.addEventListener = function(eventType,eventMethod){
		_textBox.addEventListener(eventType,eventMethod,false);
	}
	
	
}

//////////////////////////////////////////
//
// gCheckBox: Simple checkbox
//
//////////////////////////////////////////
function gCheckBox(label,id,parentNode){
	
	var _parentComponent = new gFormComponent(label,id,parentNode);
	
	var _thisComponent = _parentComponent.getNode();
	var _checkBox = document.createElementNS(NS.xhtml,"input");
	_checkBox.id=id;
	_checkBox.name=id;
	_checkBox.type ="checkbox";
	_checkBox.setAttribute("class","gCheckBox");
	
	_thisComponent.appendChild(_checkBox);
	
	this.getNode = function(){
		
		return _thisComponent;
		
	}
	this.hide = function(){
		_thisComponent.style.display = "none";
	}
	
	this.show = function(){
		_thisComponent.style.display = "";
	}
	
	this.reset = function(){
		_checkBox.checked = false;
	}
	
	this.addEventListener = function(eventType,eventMethod){
		_checkBox.addEventListener(eventType,eventMethod,false);
	}
	
	this.isChecked = function(){
		
		if(_checkBox.checked) return true;
		return false;
		
	}
}


//////////////////////////////////////////
//
// gDropDown: 
//
//////////////////////////////////////////
function gDropDown(label,id,parentNode){
	
	var _parentComponent = new gFormComponent(label,id,parentNode);
	
	var _thisComponent = _parentComponent.getNode();
	
	var _dropDown = document.createElementNS(NS.xhtml,"select");
	_dropDown.setAttribute("class","gSelectList");
	_dropDown.id=id;
	_dropDown.name=id;
	
	//_dropDown.addEventListener("change",foobar,false);
	
	_thisComponent.appendChild(_dropDown);
	
	////////////////////
	//
	// Private Methods
	//
	////////////////////
	
	//
	// DEBUGGING FUNCTION foobar():
	//
	//function foobar(){
	//	
	//	alert(_dropDown.value);
	//	alert(_dropDown.name);
	//	alert(_dropDown.id);
	//	
	//}
	
	////////////////////
	//
	// Public Methods
	//
	////////////////////
	
	//
	// getNode()
	//
	this.getNode = function(){
		
		return _thisComponent;
		
	}
	
	//
	// addSelection()
	//
	this.addSelection = function(value,label){
		
		var selection = document.createElementNS(NS.xhtml,"option");
		selection.value = value;
		var text = document.createTextNode(label);
		selection.appendChild(text);
		_dropDown.appendChild(selection);
		
	}
	
	this.addEventListener = function(eventType,eventMethod){
		_dropDown.addEventListener(eventType,eventMethod,false);
	}
	
	//
	// getSelectedText: get the text of the selected index
	//
	this.getSelectedText = function(){
		var index = _dropDown.selectedIndex;
		if(index != -1){
			return _dropDown.options[index].text;
		}else return ".";
	}
	
	//
	// setSelection: select the option with a given index
	//
	this.setSelection = function(index){
	if(index < _dropDown.options.length)
		_dropDown.selectedIndex = index;
	}
	
}


//
// Section Divider
//
function gDivider(label,id,parentNode){
	
	var _label  = label;
	var _id     = id;
	
	// CREATE THE COMPONENT:
	var _thisComponent = document.createElementNS(NS.xhtml,"div");
	_thisComponent.setAttribute("class","gDivider");
	
	var _thisLabel = document.createElementNS(NS.xhtml,"div");
	_thisLabel.setAttribute("class","label");
	var _text      = document.createTextNode(label);
	_thisLabel.appendChild(_text);
	_thisComponent.appendChild(_thisLabel);
	
	if(parentNode){
		parentNode.appendChild(_thisComponent);
	}else{
		var bodyRef = document.getElementsByTagName("body").item(0);
		bodyRef.appendChild(_thisComponent);
	}
	
	this.hide = function(){
		_thisComponent.style.display = "none";
	}
	
	this.show = function(){
		_thisComponent.style.display = "";
	}
	
}

//////////////////////////////////////////
//
// gFormExpansionArrow
//
//////////////////////////////////////////
function gFormExpansionArrow(id,downArrowClickMethod,upArrowClickMethod,parentNode){
	
	// CREATE THE COMPONENT:
	var _thisComponent = document.createElementNS(NS.xhtml,"div");
	_thisComponent.id=id;
	_thisComponent.className="formExpansionArrowDown";
	_thisComponent.title=L("Click to expand");
	
	var _self=this;
	var _isUp=false;
	
	if(parentNode) parentNode.appendChild(_thisComponent);
	else document.getElementsByTagName("body").item(0).appendChild(_thisComponent);
	
	//
	// getNode
	//
	this.getNode = function(){
		return _thisComponent;
	}
	
	//
	// getId
	//
	this.getId = function(){
		return _thisComponent.id;
	}
	
	//
	// setUp / setDown
	//
	this.setUp   = function(){ _thisComponent.className="formExpansionArrowUp"  ; _isUp=true;  }
	this.setDown = function(){ _thisComponent.className="formExpansionArrowDown"; _isUp=false; }
	
	//
	// toggle
	//
	this.toggle = function(){
		
		if(_isUp){
			if(upArrowClickMethod) upArrowClickMethod();
			_thisComponent.className="formExpansionArrowDown"; 
			_thisComponent.title=L("Click to expand");
			_isUp=false;
		}else{
			if(downArrowClickMethod) downArrowClickMethod();
			_thisComponent.className="formExpansionArrowUp"; 
			_thisComponent.title=L("Click to contract");
			_isUp=true;
		}
		
	}
	
	_thisComponent.addEventListener("click",_self.toggle,false);
	
}

