vanilla.namespace('vanilla.html');

vanilla.html =
{
    SCRIPT_EXPRESSION : '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',

    extractScripts: function(html)
    {
	var matchAll = new RegExp(this.SCRIPT_EXPRESSION, 'img');
	var matchOne = new RegExp(this.SCRIPT_EXPRESSION, 'im');

	var tags    = html.match(matchAll);
	var scripts = new Array();

	for ( var i = 0 ; i < tags.length ; i++ )
	{
	    var fragment = tags[i].match(matchOne);
	    if ( fragment )
	    {
		scripts.push(fragment[1]);
	    }
	}

	return scripts;
    },

    evalScripts: function(html)
    {
	var scripts = this.extractScripts(html);
	for ( var i = 0 ; i < scripts.length ; i++ )
	{
	    var script = scripts[i];
	    eval(script);
	}
    }
};

vanilla.html.DOM =
{
    toElement : function(e)
    {
	if ( typeof e == 'string' )
	{
	    return document.getElementById(e);
	}

	return e;
    },

    nextHomonym : function(element)
    {
	if ( !element.nodeName )
	{
	    return null;
	}

	for ( var n = element.nextSibling ; n ; n = n.nextSibling )
	{
	    if ( n.nodeName == element.nodeName )
	    {
		return n;
	    }
	}

	return null;
    },

    previousHomonym : function(element)
    {
	if ( !element.nodeName )
	{
	    return null;
	}

	for ( var n = element.previousSibling ; n ; n = n.previousSibling )
	{
	    if ( n.nodeName == element.nodeName )
	    {
		return n;
	    }
	}

	return null;
    },

    insertAfter : function(parentElement, newElement, refElement)
    {
	if ( refElement.nextSibling )
	{
	    parentElement.insertBefore(newElement, refElement.nextSibling);
	}
	else
	{
	    parentElement.appendChild(newElement);
	}
    },

    getFirstChildByTagName : function(e, tagName)
    {
	e = EL(e);
	if ( !e )
	{
	    return null;
	}

	tagName = tagName.toUpperCase();
	for ( var child = e.firstChild ; child ; child = child.nextSibling )
	{
	    if ( child.tagName == tagName )
	    {
		return child;
	    }
	}

	return null;
    },

    getAncestorByTagName : function(e, tagName)
    {
	e = EL(e);
	if ( !e )
	{
	    return null;
	}

	tagName = tagName.toUpperCase();
	for ( var p = e.parentNode ; p ; p = p.parentNode )
	{
	    if ( p.tagName == tagName )
	    {
		return p;
	    }
	}

	return null;
    },

    getAncestorForTagName : function(e, tagName)
    {
	vanilla.console("getAncestorForTagName is deprecated, use getAncestorByTagName instead");
	return vanilla.html.DOM.getAncestorByTagName(e, tagName);
    },
	
    getCommonAncestor : function(n1, n2)
    {
	var parents = Array();
	for ( var p = n1.parentNode ; p ; p = p.parentNode )
	{
	    parents.push(p);
	}

	if ( !parents.length )
	{
	    return n1;
	}

	for ( var p = n2.parentNode ; p ; p = p.parentNode )
	{
	    if ( parents.indexOf(p) >= 0 )
	    {
		return p;
	    }
	}

	return null;
    },

    getClassNames : function(element)
    {
	return EL(element).className.split(/\s+/);
    },

    updateClassName : function(element, classNames)
    {
	EL(element).className = classNames.join(' ');
    },

    hasClassName : function(element, className)
    {
	var classes = vanilla.html.DOM.getClassNames(element);
	for ( var i = 0 ; i < classes.length ; i++ )
	{
	    if ( classes[i] == className )
	    {
		return true;
	    }
	}

	return false;
    },

    addClassName : function(element, className, multiply)
    {
	if ( vanilla.html.DOM.hasClassName(element, className) )
	{
	    return;
	}

	var classes = vanilla.html.DOM.getClassNames(element);

	if ( multiply )
	{
	    var l = classes.length;
	    for ( var i = 0 ; i < l ; i++ )
	    {
		classes.push(classes[i] + '-' + className);
	    }
	}

	classes.push(className);
	vanilla.html.DOM.updateClassName(element, classes);
    },

    removeClassName : function(element, className, multiply)
    {
	var classes = vanilla.html.DOM.getClassNames(element);
	var newClasses  = new Array();
	var reg = new RegExp('-?(' + className + '-|' + className + '$)');

	var i, j;
	for ( i = 0, j = 0; i < classes.length ; i++ )
	{
	    if ( !multiply )
	    {
		if ( classes[i] != className )
		{
		    newClasses[j++] = classes[i];
		}
	    }
	    else
	    {
		if ( !reg.test(classes[i]) )
		{
		    newClasses[j++] = classes[i];
		}
	    }
	}

	vanilla.html.DOM.updateClassName(element, newClasses);
    }
};
EL = vanilla.html.DOM.toElement;

vanilla.html.style = 
{
    get : function(element, style) 
    {
	element	    = EL(element);
	var cstyle  = this.camelize(style);
	var value   = element.style[cstyle];

	if ( !value ) 
	{
	    if ( element.currentStyle ) 
	    {
		value = element.currentStyle[cstyle];
	    }
	    else if ( document.defaultView && document.defaultView.getComputedStyle ) 
	    {
		var css = document.defaultView.getComputedStyle(element, null);
		if ( css )
		{
		    value = css.getPropertyValue(style);
		}
	    }
	}

	if ( window.opera && (style == 'top' || style == 'right' || style == 'bottom' || style == 'left' ))
	{
	    if ( this.get(element, 'position') == 'static' )
	    {
		return null;
	    }
	}

	return (value == 'auto' ? null : value);
    },

    camelize : function(style)
    {
	if ( !style )
	{
	    return style;
	}

	var list	= style.split("-");
	var start	= (style.charAt(0) == '-' ? 0 : 1); 
	var camelized	= (start > 0 ? list[0] : '');
	
	for ( var i = start ; i < list.length ; i++ )
	{
	    camelized += list[i].charAt(0).toUpperCase() + list[i].substring(1);
	}

	return camelized;
    }
};

vanilla.html.position =
{
    fromStyle : function(element)
    {
	element = EL(element);

	var x   = parseInt(vanilla.html.style.get(element, 'left')  || '0', 10);
	var y   = parseInt(vanilla.html.style.get(element, 'top')   || '0', 10);

	return {x:x,y:y};
    },

    getRealOffset : function(element)
    {
	element = EL(element);
	var offset = {x: 0, y : 0};

	for ( ; element ; element = element.parentNode ) 
	{
	    offset.x += element.scrollLeft || 0;
	    offset.y += element.scrollTop  || 0;
	} 
	
	return offset;
    },

    getCumulativeOffset : function(element)
    {
	element = EL(element);
	var offset = {x: 0, y : 0};

	for ( var e = element; e ; e = e.offsetParent ) 
	{
	    offset.x += e.offsetLeft || 0;
	    offset.y += e.offsetTop  || 0;
	} 

	return offset;
    },

    nodeContains : function(element, pos)
    {
	element = EL(element);

	var box = this.getCumulativeOffset(element);
	box.w = element.offsetWidth;
	box.h = element.offsetHeight;

	return this.boxContains(box, pos);
    },

    boxContains : function(box, pos)
    {
	return ( pos.x >= box.x && pos.y >= box.y && pos.x < (box.x + box.w) && pos.y < (box.y + box.h) );
    }
};

vanilla.html.Form =
{
    NOTHING : {},
    
    serialize : function(form)
    {
	form = EL(form);
	
	var serializedCouples = new Array();
	for ( var i = 0 ; i < form.elements.length ; i++ )
	{
	    var field 	= form.elements.item(i);
	    var couple 	= this.serializeField(field);

	    if ( couple != this.NOTHING )
	    {
		serializedCouples.push(couple);
	    }
	}
	
	return serializedCouples.join('&');
    },
    
    serializeField : function(field)
    {
	return this.serializeCouple(field.name, this.getFieldValue(field));
    },
    
    serializeCouple : function(name, value)
    {
	if ( value != this.NOTHING && name != null && name.length )
	{
	    return name + '=' + this.encode(value);
	}
	
	return this.NOTHING;
    },

    encode : function(value)
    {
	if ( !value )
	{
	    return '';
	}

	value = value.replaceAll('%', 	'%25');
	value = value.replaceAll('&', 	'%26');
	value = value.replaceAll('\\?',	'%3F');
	value = value.replaceAll('=', 	'%3D');

	return value;
    },
    
    getFieldValue : function(field)
    {
	field = EL(field);
	switch(field.type)
	{
	    case 'textarea'	: return this._removeCarriageReturn(field.value);
	    case 'password'	: 
	    case 'hidden'	: 
	    case 'file' 	: 
	    case 'text' 	: return field.value;
	    case 'select-one' 	: return vanilla.html.Form.Popup.getSelectedValue(field);
	    case 'submit'	: return (field.value ? field.value : 'Envoyer');
	    case 'radio'	: 
	    case 'checkbox'	: return (field.checked ? field.value : this.NOTHING);
	}
    },

    setFieldValue : function(field, value)
    {
	field = EL(field);
	switch(field.type)
	{
	    case 'textarea'	: 
	    case 'password'	: 
	    case 'hidden'	: 
	    case 'text' 	: field.value = value; break;
	    case 'select-one' 	: vanilla.html.Form.Popup.setSelectedValue(field, value); break;
	    case 'radio'	: 
	    case 'checkbox'	: field.checked = (field.value == value); break;
	}
    },

    _removeCarriageReturn : function(value)
    {
	if ( value ) 
	{
	    value = value.replace(/\r/g, '');
	}

	return value;
    }
};

vanilla.html.Form.Popup =
{
    clear : function(popup, defaultValue, defaultText)
    {
	popup = EL(popup);
	if ( !popup )
	{
	    return;
	}

	while( popup.firstChild )
	{
	    popup.removeChild(popup.firstChild);
	}

	if ( typeof defaultValue != "undefined" )
	{
	    this.addOption(popup, defaultValue, defaultText);
	}
    },

    addOption : function(popup, value, text)
    {
	popup = EL(popup);
	if ( !popup )
	{
	    return;
	}
    
	popup.appendChild( this.createOption(value, text) );
    },

    createOption : function(value, text)
    {
	var o = document.createElement("option");
	o.setAttribute("value", value);
	o.appendChild(document.createTextNode(text));

	return o;
    },

    getSelectedOption : function(popup)
    {
	popup = EL(popup);
	if ( !popup )
	{
	    return;
	}
    
	if ( popup.selectedIndex < 0 )
	{
	    return null;
	}

	return popup.options[popup.selectedIndex];
    },

    getSelectedValue : function(popup)
    {
	var o = this.getSelectedOption(popup);
	return ( o ? o.value : null );
    },

    getSelectedText : function(popup)
    {
	var o = this.getSelectedOption(popup);
	return ( o ? o.text : null );
    },

    setSelectedValue : function(popup, value)
    {
	popup = EL(popup);
	if ( !popup )
	{
	    return false;
	}

	var i = 0;
	for ( var c = popup.firstChild ; c != null ; c = c.nextSibling, i++ )
	{
	    if ( c.value == value )
	    {
		popup.selectedIndex = i;
		return true;
	    }
	}

	return false;
    }
};

