/**
 * Namespace: Amblique
 *
 * Common Javascript Utilities
 * Requires: Prototype Library 1.5.1+
 *
 * TODO: Extend the namespace to:
 *	Amblique.DOM;
 *
 * FIXME: Can we factor some of the error checking mechanisms out
 */

var Amblique = {
	Company : "Amblique Pty, Ltd.",
	Version	: "1.0",
	_DEBUG	: false,	// Set this to true if you want to debug javascript

	/**
	 * Returns true if the element given is of type "object"
	 */
	isObject : function(obj) {
		return (typeof(obj) == "object") ? true : false;
	},
	
	/**
	 * Returns true if the element given is of type "string"
	 */
	isString : function(obj) {
		return (typeof(obj) == "string") ? true : false;
	},
	
	isStringOrObject : function(obj) {
	    if (obj == null) return false;
		return this.isObject(obj) || this.isString(obj);
	},
	
	CopyElement : function(elementToCopy, elementTo) {
	    if (!this.isStringOrObject(elementToCopy)) this.Print("Error");
	    if (this.isString(elementToCopy)) elementToCopy = $(elementToCopy);
	    this.Print(elementToCopy);
	    var objCopy = Object.clone(elementToCopy);
	    this.Print(objCopy);
	    this.MoveElement(objCopy, elementTo);
	},
	
	/**
	 * Move child elements of element "from" to elemen "to". This method
	 * appends elements instead of replacing. Also removes the child elements
	 * from the element "from"
	 */
	MoveElement : function(element, elementTo) {
		if (!this.isStringOrObject(element) || !this.isStringOrObject(elementTo)) this.Print("Amblique.MoveElement(element, elementTo): arguments must be of type string or object");
		else if (this.isString(elementTo)) $(elementTo).appendChild($(element)); 
		else if (this.isObject(elementTo)) elementTo.appendChild(element);
		else throw "Amblique.MoveElement(element, elementTo): element could not be found";
	},
	
	/**
	 * Remove the given element if found
	 */
	RemoveElement : function(element) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.RemoveElement(element): argument must be of type string or object");
		else if (this.isString(element)) $(element).remove();
		else element.remove();
	},
	
	/**
	 * Clear elements inside the given element
	 */
	ClearElements : function(element) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.ClearElement(element): argument must be of type string or object");
		else if (this.isString(element)) $(element).childElements().each(function(e) { e.remove() });
		else element.childElements().each(function(e) { e.remove() });
	},
	
	/**
	 * Add event to the element. If an event exists already, attach it
	 * safely by appending
	 * TODO: support both ID and element as the first argument
	 */
	AddEvent : function(element, eventName, functionPointer) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.AddEvent(element, eventName, functionPointer): argument (0) [element] must be of type string or object");
		else if (this.isString(element)) Event.observe($(element), eventName, functionPointer, false);	
		else Event.observe(element, eventName, functionPointer, false);	
	},
	
	/**
	 * Remove an event from the element
	 */
	RemoveEvent : function(element, eventName, functionPointer) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.RemoveEvent(element, eventName, functionPointer): argument (0) [element] must be of type string or object");
		else if (this.isString(element)) Event.stopObserving($(element), eventName, functionPointer, false);	
		else Event.stopObserving(element, eventName, functionPointer, false);	
	},
	
	/**
	 * Append css class
	 * TODO: support both ID and element as the first argument
	 */
	AppendCSSClass : function(element, className) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.AppendCSSClass(element, className): argument (0) [element] must be of type string or object");
		if (!this.isString(className)) this.Print("Amblique.AppendCSSClass(element, className): argument (1) [className] must be of type string");
		
		if (this.isString(element)) element = $(element);
		
		element.addClassName(className);
	},
	
	/**
	 * Remove css class
	 * TODO: support both ID and element as the first argument
	 */
	RemoveCSSClass : function(element, className) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.RemoveCSSClass(element, className): argument (0) [element] must be of type string or object");
		if (!this.isString(className)) this.Print("Amblique.RemoveCSSClass(element, className): argument (1) [className] must be of type string");
	
		if (this.isString(element)) element = $(element);
		
		element.removeClassName(className);
	},
	
	/**
	 * ASP.NET 2.0 Client-Side Validation RELATED Functions
	 *
	 * Note: A validator group does not represent ASP.NET validator group attribute
	 *
	 * FIXME: Calling of SwitchValidatorGroups should be dynamic - i.e., it should see DOM for
	 * which validator groups should be turned on and etc.
	 */
	
	// Enable all validators on the page *USE WITH CARE* 
	EnableAllValidators : function() {
		if (Page_Validators) {
			var i = 0;
			for (i = 0; i < Page_Validators.length; i++) {
				var element = (this.isString(Page_Validators[i])) ? $(Page_Validators[i]) : Page_Validators[i];
				this.Print(element.id + ": true");
				element.enabled = true;
			}
		}
	},
	
	// Disable all validators on the page *USE WITH CARE*
	DisableAllValidators : function() {
		if (Page_Validators) {
			var i = 0;
			for (i = 0; i < Page_Validators.length; i++) {
				var element = (this.isString(Page_Validators[i])) ? $(Page_Validators[i]) : Page_Validators[i];
				this.Print(element.id + ": false");
				element.enabled = false;
			}
		}
	},
	 
	// Associate a mutuallly exclusive pair of control groups, so if one is enabled, the other is disabled
	// It turns all elements in elementArray1 on, others off.
	SwitchValidatorGroups : function(elementArray1, elementArray2, validateNow) {
		try {
			// FIXME: Temporary hack to bypass object reference being passed as the first argument
			if (arguments.length == 3 && typeof(elementArray1) == "object" && !elementArray1.length) {
				this.Print("There are 3 arguments with 1st argument as an object");
				elementArray1 = arguments[1];
				elementArray2 = arguments[2];
				validateNow = false;
			} else if (arguments.length == 4) {
				this.Print("There are 4 arguments");
				elementArray1 = arguments[1];
				elementArray2 = arguments[2];
				validateNow = argument[3];
			} else {
				this.Print("arguments.length: " + arguments.length);
			}
		
			var i = 0;
			for (i = 0; i < elementArray1.length; i++) {
				var element = (this.isString(elementArray1[i])) ? $(elementArray1[i]) : elementArray1[i];
				this.Print(element.id + ": true");
				element.enabled = true;
			}
			
			for (i = 0; i < elementArray2.length; i++) {
				var element = (this.isString(elementArray2[i])) ? $(elementArray2[i]) : elementArray2[i];
				this.Print(element.id + ": false");
				element.enabled = false;
			}
			
			this.Print("validateNow: " + validateNow);
			if (validateNow) {
				var element = (this.isString(elementArray1[0])) ? $(elementArray1[0]) : elementArray1[0];
				var ValidationGroup = (this.isString(element.validationGroup)) ? element.validationGroup : "";
				this.Print("ValidationGroup: " + ValidationGroup);
				
				// Validate the group now
				Page_ClientValidate(ValidationGroup);
			}
		} catch (ex) {
			this.Print(ex.description);
		}
	},
	
	// Disable a single validator
	DisableValidator : function(element) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.DisableValidator(element): argument (0) [element] must be of type string or object");
		
		if (this.isString(element)) element = $(element);
		
		element.enabled = false;
	},
	
	// Enable a single validator
	EnableValidator : function(element) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.EnableValidator(element): argument (0) [element] must be of type string or object");
		
		if (this.isString(element)) element = $(element);
		
		element.enabled = true;
	},
	
	// Toggle a single validator
	ToggleValidator : function(element) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.ToggleValidator(element): argument (0) [element] must be of type string or object");
		
		if (this.isString(element)) element = $(element);
		if (element.enabled == null) element.enabled = true;
		
		element.enabled = (element.enabled == true) ? false : true;
	},
	
	/**
	 * Get Position of an element
	 *
	 * FIXED: Use prototype library
	 */
	GetPosition : function (event) {
        try {
            event = event || window.event;
            var cursor = {x: 0, y: 0};

            cursor.x = Event.pointerX(event);
            cursor.y = Event.pointerY(event);
            
            return cursor;
        } catch (ex) {
            alert(ex.description);
        }
    },
	
	/**
	 * Toggle display (css) of an element
	 */
	ToggleDisplay : function(element) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.ToggleDisplay(element): argument (0) [element] must be of type string or object");
		if (this.isString(element)) element = $(element);
		
		if (element.style.display == "none")
			element.style.display = "block";
		else
			element.style.display = "none";
	},
	
	/**
	 * Toggle visibility (css) of an element
	 */
	ToggleVisibility : function(element) {
		if (!this.isStringOrObject(element)) this.Print("Amblique.ToggleVisibility(element): argument (0) [element] must be of type string or object");
		if (this.isString(element)) element = $(element);
		
		if (element.style.visibility == "hidden")
			element.style.visibility = "visible";
		else
			element.style.visibility = "hidden";
	},
	
	/**
	 * Unobtrusive popup message
	 *
	 * element: element to show
	 * message: to show
	 * event: event object
	 */
	ToggleInformationPopup : function(element, message, event, below) {
	    if (!this.isStringOrObject(element)) this.Print("Amblique.ToggleInformationPopup(element): argument (0) [element] must be of type string or object");
	    if (this.isString(element)) element = $(element);
	    
	    element.innerHTML = message;
	    var cursor = this.GetPosition(event);

	    cursor.x += 10;
	    if (below) {
            cursor.y += 15;
	    } else {
	        cursor.y -= (element.getHeight() + 15);
	        cursor.x -= (element.getWidth() + 15);
	    }
	    
	    element.style.top = cursor.y + "px";
	    element.style.left = cursor.x + "px";
	    this.ToggleDisplay(element);
	},
	
	MoveInformationPopup : function(element, event, below) {
	    if (!this.isStringOrObject(element)) this.Print("Amblique.MoveInformationPopup(element): argument (0) [element] must be of type string or object");
	    if (this.isString(element)) element = $(element);
	    
	    var cursor = this.GetPosition(event);

	    cursor.x += 10;
	    if (below) {
            cursor.y += 15;
	    } else {
	        cursor.y -= (element.getHeight() + 15);
	    }
	    
	    element.style.top = cursor.y + "px";
	    element.style.left = cursor.x + "px";
	},
	
	/**
	 * Wireup textboxes to its default button
	 *
	 * e: event passed on from the textbox
	 * element: default button (input button)
	 */
	DefaultButton : function(event, element) {
    	if (!this.isObject(event)) this.Print("Amblique.DefaultButton(event, element): argument (0) [e] must be of type object");
	    if (!this.isStringOrObject(element)) this.Print("Amblique.DefaultButton(event, element): argument (1) [element] must be of type string or object");
	    
	    if (this.isString(element)) element = $(element);
	    
        //Event.element(event).blur();
        //Event.element(event).focus();
	    
        if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) { 
            event.returnValue = false; 
            event.cancel = true; 
            element.click(); 
            return false; 
        } else {
            return true;
        }
	},
	
	/**
	 * Open window
	 */
	OpenImageWindow : function(ImageURL) {
	    if (ImageURL && ImageURL != "")
	        window.open("ImageView.htm?" + ImageURL, "Image", "status=0, toolbar=0, location=0, menubar=0, directories=0, scrollbars=1");
	    
	    return false;
	},
	
	/**
	 * Round Number to given decimal points
	 *
	 * number:  number to round
	 * radix:   decimal places
	 */
	RoundNumber : function(number, radix) {
	    var newnumber = number;
	    if (number > 8191 && number < 10485) {
		    number = number - 5000;
		    newnumber = Math.round(number * Math.pow(10, radix)) / Math.pow(10, radix);
		    newnumber = newnumber + 5000;
	    } else {
		    newnumber = Math.round(number * Math.pow(10, radix)) / Math.pow(10, radix);
	    }
	    return newnumber;
	},
	
	/**
	 * Print to console or alert. Mainly used for Exception display
	 * during debugging
	 */
	Print : function(message) {
		if (this._DEBUG) {
			try {
				if (console) console.debug(message);
			} catch (ex) {
				alert(message);
			}
		}
	}
}