/**
 * FormNode wraps the Node of special FormInputElements to gain convenient methods for operating with these node types.
 * Provides abstract getters and setters for manipulating these nodes attributes.
 * @param formElementNode   the Node to be wrappped
 * @constructor
 * @author Thorsten Engl
 * @version 0.1
 */
function FormNode( formElementNode ) {
	this.setFormElementNode( formElementNode );
};

/**
 * Set the node
 * @return  the Node to be wrappped
 */
FormNode.prototype.getFormElementNode = function() {
	return this.formElementNode;
};
/**
 * get the wrapped node
 * @param formElementNode    the node to be wrapped
 **/
FormNode.prototype.setFormElementNode = function(formElementNode) {
	this.formElementNode = formElementNode;
	if( formElementNode != null ) {
	    this.metaData = new FormNodeMetadata( formElementNode );
	}
	else {
	    this.metaData = null;
	}
};
/**
 * Get metadataobject representing the wrapped node
 * @return  metadata for the wrapped node if node not null, else null
 * @see FormNodeMetadata
 **/
FormNode.prototype.getMetaData =  function() {
    return this.metaData;
};

/**
 * Get name for the node, if the wrapped node is of type "option" its label is returned otherwise the corresponding attribute value.
 * @return  the wrapped nodes name
 */
FormNode.prototype.getName = function() {
    var nodeName = "";
    if( this.metaData.isElementOption() ) {
        // get label per DOM 1 equals HTMLOptionElement.label
        if( this.formElementNode.hasChildNodes() ) {
            nodeName = null;
            for( var i=0; i < this.formElementNode.childNodes.length && nodeName == null ; i++ ) {
                var nextNode = this.formElementNode.childNodes.item( i );
                if( nextNode.nodeType == FormNodeMetadata.TEXT_NODE ) {
                    nodeName = nextNode.nodeValue;
                }
            }
            if( nodeName == null ) {
                nodeName = "";
            }
        }
    } else {
        var nameAttr = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_NAME );
        if( nameAttr != null ) {
            nodeName = nameAttr.value;
        }
    }

    return nodeName;
};
/**
 * set name for the node, if the wrapped node is of type "option" its label is set otherwise the corresponding attribute value.
 * @param newName   the name
 */
FormNode.prototype.setName = function( newName ) {
    if( this.metaData.isElementOption() ) {
        // set label per DOM 1 equals HTMLOptionElement.label = newName
        for( var i=0; i < this.formElementNode.childNodes.length && nodeName == null ; i++ ) {
            var nextNode = this.formElementNode.childNodes.item( i );
            if( nextNode.nodeType == FormNodeMetadata.TEXT_NODE ) {
                nextNode.nodeValue = newName;
            }
        }
    } else {
        var nameAttr = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_NAME );
        if( nameAttr != null ) {
            nameAttr.value = newName;
        }
    }
};

/**
 * Get the nodes value, if the wrapped node is of type "select" null will be returned otherwise the corresponding attribute value
 * @return  the nodes value
 */
FormNode.prototype.getValue = function() {
    var value = null;

    if( this.metaData.isElementSelect() == false ) {
        //value = getAttributeNodeValue( this.formElementNode, FormNodeMetadata.ATTRIBUTE_VALUE );
        var attrValue = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_VALUE );
        if( attrValue != null ) {
            value = attrValue.value;
        }
        if( this.metaData.isTypeText() ) {
            //value = getAttributeNodeValue( this.formElementNode,FormNodeMetadata.ATTRIBUTE_VALUE )
            value = this.formElementNode.value;
        }
    }

    return value;
};
/**
 * Set the nodes value, if the wrapped node is not of type "select" the corresponding attribute value will be set
 * @return  the nodes value
 */
FormNode.prototype.setValue = function( newValue ) {
    if( this.metaData.isElementSelect() == false ) {
        var attrValue = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_VALUE );
        if( attrValue != null ) {
            attrValue.value = newValue;
        }
    }
};

/**
 * Get possible node values for the wrapped node, if the wrapped node is of type "select"
 * the value attribute for all "option" childs will be returned,
 * otherwise the value attribute of the node itself if the node is either of type "text" or "option"
 * @return possible node values of type Array
 */
FormNode.prototype.getPossibleValues = function() {
    var values = new Array(0);

    if( this.metaData.isTypeText() || this.metaData.isElementOption() ) {
        values.push( this.getValue() );
    }

    if( this.metaData.isElementSelect() ) {
        var optionChilds = this.formElementNode.getElementsByTagName( FormNodeMetadata.ELEMENT_OPTION );
        if( optionChilds != null ) {
            for( var index=0; index < optionChilds.length; index++ ) {
                values.push( new FormNode( optionChilds.item( index ) ).getValue() );
            }
        }
    }

    return values;
};

/**
 * Add possible node value, only functional if the wrapped node is of type select
 * @param newValue  the value to be added
 * @param newName   the name
 */
FormNode.prototype.addPossibleValue = function( newValue, newName ) {

    if( this.metaData.isElementSelect() && arrayContains( this.getPossibleValues(), newValue ) == false )  {

        var optionNode = this.formElementNode.ownerDocument.createElement( FormNodeMetadata.ELEMENT_OPTION );
        var valueAttr = this.formElementNode.ownerDocument.createAttribute( FormNodeMetadata.ATTRIBUTE_VALUE );
        valueAttr.value = newValue;
        var textNode = this.formElementNode.ownerDocument.createTextNode( newName );

        optionNode.setAttributeNode( valueAttr );
        optionNode.appendChild( textNode );
        optionNode.selected = false;
        //this.formElementNode.appendChild( optionNode );
        //this.formElementNode.addOption( newValue, newName );
        this.formElementNode.options[ this.formElementNode.options.length ] = new Option( newValue, newName );

    }

};
/**
 * Remove possible node value, only functional if the wrapped node is of type select
 * @param oldValue  the value to be removed
 */
FormNode.prototype.removePossibleValue = function( oldValue ) {
    if( this.metaData.isElementSelect() && arrayContains( this.getPossibleValues(), oldValue ) )  {

        var optionIndex = this.getOptionIndexByValue( oldValue );
        if( optionIndex != -1 ) {
            this.formElementNode.options[ optionIndex ] = null;
        }
    }
};

/**
 * Get the first selected value for the wrapped node
 * @return  empty String if not selected values are present, or the value itself
 */
FormNode.prototype.getSelectedValue = function() {
    var value = "";

    var values = this.getSelectedValues();
    if( values != null && values.length > 0 ) {
        value = values[0];
    }

    return value;
};

/**
 * Sets the selected value for the wrapped node.
 * If of type "select" the provided value must be in the possible values,
 * otherwise the corresponding selected flags are enabled for the wrapped node,
 * or the corresponding attribute is set to the provided value
 * @param newValue  the value to be set to selected
 */
FormNode.prototype.setSelectedValue = function( newValue ) {

    // set value for SELECT
    if( this.metaData.isElementSelect() ) {

       if( !this.metaData.isMultiple() ) {
        if( arrayContains( this.getPossibleValues(), newValue ) == true ) {	    
            var optionIndex = this.getOptionIndexByValue( newValue );
            if( optionIndex != -1 ) {
                this.formElementNode.selectedIndex = optionIndex;
            }
        }
       } else {
		  var nextOptionNode = this.getOptionByValue( newValue );
		  if( nextOptionNode != null ) {
 		      var nextOptionFormNode = new FormNode( nextOptionNode );
                      if( !nextOptionFormNode.getMetaData().isDisabled() ) {
			nextOptionFormNode.setSelectedValue();
		      }
		  }
	     
	   
       }
    }
    else {

        var attrValue = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_VALUE );

        if( attrValue != null ) {

            if( this.metaData.isElementInput() ) {

                if( this.metaData.isTypeCheckbox() || this.metaData.isTypeRadio() ) {

                    if( attrValue.value == newValue && this.metaData.isChecked() == false ) {

                        var attrChecked = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_CHECKED );
                        if( attrChecked == null ) {
                            attrChecked = this.formElementNode.ownerDocument.createAttribute( FormNodeMetadata.ATTRIBUTE_CHECKED );
                            this.formElementNode.setAttributeNode( attrChecked );
                        }
                        this.formElementNode.checked = true;

                    }
                }
                else {

                    if( this.metaData.isTypeText() ) {
                        this.formElementNode.value = newValue;
                    } else {
                        attrValue.value = newValue;
                    }
                }
            }

            if( this.metaData.isElementOption() && this.metaData.isSelected() == false ) {

                var attrSelected = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_SELECTED );
                if( attrSelected == null ) {
                    attrSelected = this.formElementNode.ownerDocument.createAttribute( FormNodeMetadata.ATTRIBUTE_SELECTED );
                    this.formElementNode.setAttributeNode( attrSelected );
                }

                this.formElementNode.selected = true;
            }
        }
    }
};
FormNode.prototype.setSelectedValues = function( newValues ) {
   if( newValues != null && newValues.length > 0 ) {
	for( var i=0; i < newValues.length ; i++ ) {
	   this.setSelectedValue( newValues[ i ] );
	}
   }
};

FormNode.prototype.removeSelectedValues = function( selectedValues ) {
   if( selectedValues != null && selectedValues.length > 0 ) {
        for( var i=0; i < selectedValues.length ; i++ ) {
           this.removeSelectedValue( selectedValues[ i ] );
        }
   }
};

FormNode.prototype.clearSelectedValues = function() {
   this.removeSelectedValues( getSelectedValues() );
};

FormNode.prototype.removeSelectedValue = function( selectedValue ) {

    if( selectedValue != null && selectedValue.length > 0 && this.hasSelectedValue( selectedValue ) ) {

        if( this.metaData.isElementSelect() ) {

            var optionChilds = this.formElementNode.getElementsByTagName( FormNodeMetadata.ELEMENT_OPTION );

            if( optionChilds != null && optionChilds.length > 0 ) {

               if( this.metaData.isMultiple() ) {
                   for( var i=0; i < optionChilds.length ; i++ ) {

                        var nextOptionNode = optionChilds.item( i );

                        var nextFormNode = new FormNode( nextOptionNode );
                        if( nextFormNode.getValue() == selectedValue ) {
                            if( nextFormNode.metaData.isSelected() == true ) {
                                nextFormNode.removeSelectedValue( selectedValue );
                            }
                        }
                        /*
                        var attrSelected = nextOptionNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_SELECTED );
                        var attrValue = nextOptionNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_VALUE );

                        if( attrValue != null && attrValue.value == selectedValue && attrSelected != null ) {
                            nextOptionNode.removeAttributeNode( attrSelected );
                            nextOptionNode.selected = false;
                        } */
                    }
                } else {
                    this.formElementNode.options[ this.formElementNode.selectedIndex ] = null;
                }
            }
        } else {

            var attrValue = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_VALUE );

            if( attrValue != null ) {

                if( this.metaData.isElementInput() ) {

                    if( this.metaData.isTypeCheckbox() || this.metaData.isTypeRadio() ) {

                        if( attrValue.value == selectedValue && this.metaData.isChecked() == true ) {

                            var attrChecked = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_CHECKED );

                            if( attrChecked != null  ) {
                                this.formElementNode.removeAttributeNode( attrChecked );
                            }

                            this.formElementNode.checked = false;

                        }
                    }
                    else {
                        attrValue.value = "";
                    }
                }

                if( this.metaData.isElementOption() && this.metaData.isSelected() == true ) {
                    if( attrValue.value == selectedValue ) {

                        var attrSelected = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_SELECTED );

                        if( attrSelected != null ) {
                            this.formElementNode.removeAttributeNode( attrSelected );
                        }
                        this.formElementNode.selected = false;
                    }
                }
            }
        }
    }

};

/**
 * Determine all selected values for the wrapped node.
 * If of type "select" all selected option childs value are returned,
 * otherwise if the corresponding selected flags are checked the value of the node itself is returned.
 * @return  array of selected values
 */
FormNode.prototype.getSelectedValues = function() {
    var selectedValues = new Array(0);

    if( this.metaData.isElementSelect() ) {

        var optionChilds = this.formElementNode.getElementsByTagName( FormNodeMetadata.ELEMENT_OPTION );
        if( optionChilds != null && optionChilds.length > 0 ) {

            if( this.metaData.isMultiple() == true ) {

                var selectedOptionNodes = this.getSelectedOptionNodes();
                if( selectedOptionNodes != null ) {
                    for( var index = 0; index < selectedOptionNodes.length; index++ ) {
                        selectedValues.push( new FormNode( selectedOptionNodes[ index ] ).getValue() );
                    }
                }

            } else {
                var selectedOption = this.formElementNode.options[ this.formElementNode.selectedIndex ];
                selectedValues.push( new FormNode( selectedOption ).getValue() );
            }
        }

    } else {

        var value = this.getValue();

        if( this.metaData.isElementOption() && this.metaData.isSelected() ) {
            selectedValues.push( value );
        }

        if( this.metaData.isElementInput() ) {

            if( this.metaData.isTypeCheckbox() || this.metaData.isTypeRadio() ) {
                if( this.metaData.isChecked() ) {
                    selectedValues.push( value );
                }
            }
            else {
                // hack for text element
                //alert( attrValue.name + "|" + attrValue.value + "|" + getAttributeNodeValue( this.formElementNode,FormNodeMetadata.ATTRIBUTE_VALUE ) );
                //alert( value );
                selectedValues.push( value );
                //var attrValue = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_VALUE );

                //selectedValues.push( value );
            }
        }
    }

    return selectedValues;
};

/**
 * Verify if an selected values are present.
 * @return  true if there are selectedvalues otherwise false
 */
FormNode.prototype.hasAnySelectedValue = function() {
    return this.getSelectedValues().length > 0;
};

FormNode.prototype.hasSelectedValue = function( selectedValue ) {
    return arrayContains( this.getSelectedValues(), selectedValue );
};


FormNode.prototype.getOptionNodeByIndex = function( optionIndex ) {
    var optionNode = null;

    if( this.metaData.isElementSelect() == true ) {

        var optionNodes = this.formElementNode.getElementsByTagName( FormNodeMetadata.ELEMENT_OPTION );
        if( optionNodes != null && optionIndex >= 0 && optionIndex < optionNodes.length ) {
            optionNode = optionNodes.item( optionIndex );
        }
    }

    return optionNode;
};
FormNode.prototype.getOptionIndexByValue = function( optionValue ) {
    var optionNodeIndex = -1;

    if( this.metaData.isElementSelect() == true && arrayContains( this.getPossibleValues(), optionValue ) == true ) {

        var optionNodes = this.formElementNode.getElementsByTagName( FormNodeMetadata.ELEMENT_OPTION );
        for( var index = 0; index < optionNodes.length && optionNodeIndex == -1; index++ ) {

            var nextOptionFormNode = new FormNode( optionNodes.item( index ) );
            if( nextOptionFormNode.getValue() == optionValue ) {
                optionNodeIndex = index;
            }
        }
    }

    return optionNodeIndex;
};

FormNode.prototype.getOptionByValue = function( optionValue ) {
    var optionNode = null;

    if( this.metaData.isElementSelect() == true && arrayContains( this.getPossibleValues(), optionValue ) == true ) {

        var optionNodes = this.formElementNode.getElementsByTagName( FormNodeMetadata.ELEMENT_OPTION );
        for( var index = 0; index < optionNodes.length && optionNode == null; index++ ) {

            var nextOptionFormNode = new FormNode( optionNodes.item( index ) );
            if( nextOptionFormNode.getValue() == optionValue ) {
                optionNode = optionNodes.item( index );
            }
        }
    }

    return optionNode;
};

FormNode.prototype.getSelectedOptionNodes = function() {
    var selectedNodes = new Array(0);

    if( this.metaData.isElementSelect() ) {

        var optionNodes = this.formElementNode.getElementsByTagName( FormNodeMetadata.ELEMENT_OPTION );
        for( var index = 0; index < optionNodes.length; index++ ) {

            var nextOptionFormNode = new FormNode( optionNodes.item( index ) );
            if( nextOptionFormNode.metaData.isSelected() || nextOptionFormNode.metaData.isOptionSelected() ) {
                selectedNodes.push( optionNodes.item( index ) );
            }
        }

    }

    return selectedNodes;
};
FormNode.prototype.setDisabled = function( disabledValue ) {
    //var attrChecked = this.formElementNode.getAttributeNode( FormNodeMetadata.ATTRIBUTE_DISABLED );
    //if( attrChecked == null ) {
    //    alert( attrChecked );
    //}
    this.formElementNode.disabled = disabledValue;
};

