/*																																										*/
if( typeof pln == 'undefined' || typeof nvi == 'undefined' ){

	/**
	 @requires pln.js
	 @requires nvi.core.js
	 @requires class.nvi.basic.panel.js
	 @description if not found, alert the developers and do nothing;
	*/
	if( typeof pln == 'undefined' ) alert( "This file required the PLN Javascript Library ( pln.js ) and it need to be loaded before this file." );
	if( typeof nvi == 'undefined' ) alert( "This file required the NVI CORE ( nvi.core.js ) and it need to be loaded before this file." );
	if( typeof class_nvi_basic_panel == 'undefined' ) alert( "This file required the Class Nvi Basic Panel and it need to be loaded before this file." );

}else{



	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 @name 			Input Panel Class
	 @version		1.00
	*/
	function class_nvi_input_panel(){
		
		var _validationObjectCollection = [] ;
		var _initialValue = '' ;
		var _errorLabelPrefix = 'nvi_modules_validation_' ;
		var _validationSummaryErrorPrefix = 'nvi_modules_validation_summary_error_' ;
		var _defaultValidationSummaryId = 'nvi_modules_validation_summary' ;
		var _customValidationSummaryId = null ;
		var _enableWordCount = false ;
		var _characterCountCallbackCollection = [] ;
		var _error_classname = 'error' ;
		var _host = this ;
		
		this.constructor = function( $id ){
			__super.constructor( $id ) ;
		}			
		
		this.toString = function(){ return "Nvi Input Panel Class" ; }
		
		this.initialize = function(){
			if( _enableWordCount ){
				_characterCounter = new class_nvi_input_characters_count( this.getElement() ) ;
				_characterCounter.onChange = function( total , remaining ){
					for( var i = 0 ; i < _characterCountCallbackCollection.length ; i++ ){
						_characterCountCallbackCollection[ i ]( total , remaining ) ;
					}
				} ;
			}
			__super.initialize() ;
		}
		
		this.terminate = function(){
			__super.terminate() ;
		}
	
		this.registerWordCountCallBack = function( callback ){
			if( pln.isFunction( callback ) ){
				_characterCountCallbackCollection.push( callback ) ;
				_enableWordCount = true ;
			}
		}
		
		function getValidationSummaryContainer(){
			var validationSummaryContainer = pln.node.getById( _customValidationSummaryId ) ;
			if( !pln.isHtmlElement( validationSummaryContainer ) ) validationSummaryContainer = pln.node.getById( _defaultValidationSummaryId ) ;
			if( pln.isHtmlElement( validationSummaryContainer ) ){
				return validationSummaryContainer ;
			}else{
				nvi.logManager.log( 'The default validation summary with the following id: ' + _defaultValidationSummaryId + ' is not available in the current document' , 'Error' , 'class_nvi_input_panel' , 'getValidationSummaryContainer' );
			}		
			return null ;
		}
		
		function manageErrorDisplay( display , validationObject ){
			
			if( pln.isBoolean( display ) ){

				// Add style to the input element
				pln.node[ display ? 'addClassName' : 'removeClassName' ]( _host.getElement() , _error_classname ) ;

				// We acquire the error label element
				var errorLabelElement = pln.node.getById( _errorLabelPrefix + validationObject.getId() ) ;
				if( pln.isHtmlElement( errorLabelElement ) ){
					// We display or hide the error label(if it exist) depending on the display variable (Boolean)				
					pln.node.setProperty( errorLabelElement , 'display' , display ? 'inline' : 'none' ) ;
				}
				
				var errorId = validationObject.getId() ;
				var errorMessage = validationObject.getErrorMessage() ;	
				var validationSummaryContainer = getValidationSummaryContainer() ;
				
				if( pln.isHtmlElement( validationSummaryContainer ) ){
					// The validation summary is a ul node, so for each error message, we add a li
					if( display ){
						var node = pln.node.add( pln.node.create( 'li' ) , validationSummaryContainer ) ;
						pln.node.setProperty( node , 'innerHTML' , errorMessage ) ;
						// We also set the error id so we can remove it later
						pln.node.setProperty( node , 'id' , _validationSummaryErrorPrefix + errorId ) ;
						pln.node.setProperty( validationSummaryContainer , 'display' , '' ) ; // This should not be 'block' because we dont know if the element was of type inline or block
					}else{
						var node = pln.node.getById( _validationSummaryErrorPrefix + errorId ) ;
						if( pln.isHtmlElement( node ) ) pln.node.remove( node ) ;
						if( pln.node.getLength( validationSummaryContainer ) == 0 ) pln.node.setProperty( validationSummaryContainer , 'display', 'none' ) ;
					}
				}
			}
		}
		
		/**
		 @public
		 @description	Return the value of the input
		 @return		String ;
		*/		
		this.getValue = function(){
			var element = this.getElement() ;
			// Depend on the type of the input...
			var value = null ;
			if( pln.isHtmlElement( element ) ){
				try{ value = element.value ; }
				catch( e ){
					// Special case input !? 
				}
			}
			return value ;
		}
		
		/**
		 @public
		 @description	Return the type of the input
		 @return		String ;
		*/		
		this.getType = function(){
			try{ return this.getElement().type.toLowerCase() ; }
			catch( e ){ return null ; }
		}
		
		/**
		 @public
		 @description	Return the true or false if the element is checked or not an
						if the property is not supported, return null.
		 @return		String ;
		*/		
		this.isChecked = function(){
			try{ return this.getElement().checked ; }
			catch( e ){ return null ; }
		}			
		
		/**
		 @public
		 @description	Add a validation object to validation object collection
		 @return		Nothing
		*/
		this.addValidationObject = function( validationObject ){
			if( pln.isObject( validationObject ) ) _validationObjectCollection.push( validationObject ) ;
		}
		
		/**
		 @public
		 @description	Remove an object from the validation collection using it's ID ( the id of the validation object ).
		 @return		Nothing
		*/		
		this.removeValidationObject = function( id , removeAll ){
			var removeAll = pln.isBoolean( removeAll )? removeAll : false ;
			if( !removeAll && !pln.isString( id ) ) return null ;
			for( var i = 0 ; i < _validationObjectCollection.length ; i++ ){
				var validationObject = _validationObjectCollection[ i ] ;
				
				// We only select the validationObject with the same id as the one passed as argument
				if( removeAll || ( !removeAll && validationObject.getId() == id ) ){
					
					manageErrorDisplay( false , validationObject ) ;
					
					// We remove the validationObject form the validation object collection
					if( !removeAll ){
						_validationObjectCollection.splice( i , 1 ) ;
						break ;
					}

				}
			}
		}
		
		/**
		 @public
		 @description	Remove all validation objects from the validation collection .
		 @return		Nothing
		*/		
		this.removeAllValidationObjects = function( resetCollection ){
			var resetCollection = pln.isBoolean( resetCollection ) ? resetCollection : true ;
			this.removeValidationObject( null , true ) ;
			if( resetCollection ) _validationObjectCollection = [] ;
		}
		
		/**
		 @public
		 @description	Validate the input value of the field using all registered validation object.
		 @return		Nothing
		*/		
		this.validate = function(){
			var isValid = true ;
			this.removeAllValidationObjects( false );
			for( var i = 0 ; i < _validationObjectCollection.length ; i++ ){
			
				var result = true ;
				var validationObject = _validationObjectCollection[ i ] ;
				var value = this.getValue() ;
				
				if( !pln.isString( value ) ){
					nvi.logManager.log( 'The value of the input is not valid: ' + value , 'Error' , 'class_nvi_input_panel' , 'validate' );
					result = false ;
					break ;

				}else{
					var success = validationObject.validate( value ) ;
					if( !success ){
						manageErrorDisplay( true , validationObject ) ;
						isValid = false ;
						nvi.eventManager.dispatchEvent( this.getId() , nvi.eventManager.events.__validationFailed ) ;
						break ;
					}else{
						nvi.eventManager.dispatchEvent( this.getId() , nvi.eventManager.events.__validationSucceeded ) ;					
						manageErrorDisplay( false , validationObject ) ;
					}
				}
			}
			return isValid ;
		}
		
		/**
		 @public
		 @description	Set the initial value of the field so it can be reassign to the input using the reset method.
		 @return		Nothing
		*/		
		this.setInitialValue = function( value ){
			if( pln.isString( value ) ) _initialValue = value ;
		}

		/**
		 @public
		 @description	reset the input, set the value to the initial value or empty, and remove any trace of validation
		 @return		Nothing
		*/		
		this.reset = function(){
			var input = this.getElement() ;
			if( pln.isHtmlElement( input ) && pln.isString( _initialValue ) ){
				input.value = _initialValue ;
				this.removeAllValidationObjects() ;
			}
		}

		/**
		 @public
		 @description	Enable you to assign another error validation summary for this selected input.
						Note that the validation summary must be a UL tag
		 @return		Nothing
		*/	
		this.setCustomValidationSummaryId = function( id ){
			if( pln.isString( id ) ) _customValidationSummaryId = id ;
		}
		
		/**
		 @public
		 @description	Get the desired data and returned it( when called) to 
						the Nvi Shared Ressources Manager
		 @returns		Object ;
		*/		
		this.getSharedRessources = function(){
			return {
				type : 'input' ,
				id : this.getId() ,
				parameters : {
					value : this.getValue()
				}
			} ;
		}
		
		this.changeErrorCssClassName = function( className ){
			if( pln.isString( className ) ) _error_classname = className ;
		}
		
	}
	/**
	 @definition	We defined here which other class we extend.
	*/
	class_nvi_input_panel.extend = class_nvi_basic_panel ;


	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 @name 			Input Characters Count Class
	 @version		1.00
	*/
	function class_nvi_input_characters_count( element ){
		
		var _element = pln.isHtmlElement( element ) ? element : null ;
		if( !pln.isset( _element ) ) return null ;
		
		var _maxlength = pln.node.getAttributeValue( _element , 'maxlength' ) ;
		if( !pln.isset( _maxlength ) || !pln.isNumber( _maxlength ) ) return null ;
		
		var _interval ;		
		var _host = this ;
		
		this.onChange ;
		
		function validate( e ){
			var bypass = false ;
			if(pln.events.selection.length>1) bypass = true ;
			var keyCode = pln.events.getKeyCode( pln.events.getEventObject(e) ) ;
			if( keyCode == pln.events.key.BACKSPACE || keyCode == pln.events.key.DELETE ) bypass = true ;
			if( pln.events.isKeyDown( pln.events.key.SHIFT ) ){
				if( keyCode == 37 || keyCode == 38 || keyCode == 39 || keyCode == 40 ) bypass = true ;
			}
			if(bypass){
				return true;
			}else{
				return _element.value.length < _maxlength ;
			}
		}
		function cleanup(){
			var value = _element.value ;
			var new_value = value.length > _maxlength ?  value.substr( 0 , _maxlength ) : null ;
			if( pln.isset( new_value ) ){
				_element.value = new_value ;
			}
		}

		function activate( ){
			_interval = setInterval( function(){
				cleanup() ;
				if( pln.isFunction( _host.onChange ) ) _host.onChange( _element.value.length , _maxlength - _element.value.length ) ;
			} , 80 ) ;
		}
		function deactivate(){
			clearInterval( _interval ) ;
		}

		pln.events.addListener( _element , 'focus' , null , activate ) ;
		pln.events.addListener( _element , 'blur' , null , deactivate ) ;		

		_element.onkeypress = _element.onkeyup = function(e){
			return validate(e) ; 
		} ;		
		
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	
}