/*
	Form and Dom funcitons, do not put any other functions here
	<script>
*/

/*********************************************************************
'***    Program: getElementsByTagWithClass( node, tagName, className )
'***    Type: Function
'***
'***    Function: returns an array of nodes found on specified node based on Tag Name and Class
'***
'***    Parameters: 
			node - node where to look for elements
			tagName - name of tag to find
			className - class name to filter by
'***        
'***    Returns: array of elements
'***    Remarks: none
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 4/28/08
'*********************************************************************/
function getElementsByTagNameWithClass( node, tagName, className ) {

	var elements = node.getElementsByTagName(tagName);
	var arrNodes = new Array(0);
	
	for (var k=0; k<elements.length; k++){
	
		if (elements[k].className == className) {
			// found, increase count
			arrNodes.push(elements[k]);
		}
	}
	return arrNodes;
}

/*********************************************************************
'***    Program: addLoadEvent( func )
'***    Type: Function
'***
'***    Function: safely adds a new load event
'***
'***    Parameters: 
			func - refernce to function which to call onload
'***        
'***    Returns: void
'***    Remarks: none
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 4/28/08
'*********************************************************************/
function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} 
	else {
		window.onload = function() {
		  oldonload();
		  func();
		}
	}
}


/*********************************************************************
'***    Program: prepareAllInputsForHints()
'***    Type: Function
'***
'***    Function: prepares all inputs to show hints
'***
'***    Parameters: objId - pass object id to prepare inputs only for this specific block (usually used when content loaded via ajax)
'***        
'***    Returns: void
'***    Remarks: none
'***
'***    Created by: dimab
'***    Changed by: sergeyh
'***    Last change: 05/25/2011
'*********************************************************************/
function prepareAllInputsForHints(objId) {
	if(typeof(objId) != "string")
	    objId = null;
	// get all input objects, add onfocus/onblur
	prepareInputsForHints("input", objId);
	prepareInputsForHints("select", objId);
	prepareInputsForHints("textarea", objId);
}


/*********************************************************************
'***    Program: prepareInputsForHints()
'***    Type: Function
'***
'***    Function: prepares all inputs to show hints
'***
'***    Parameters: tag - prepare hints for specified tagName
'***                objId - prepare inputs in specified container (if not set - will be used all document)
'***        
'***    Returns: void
'***    Remarks: use this function as callback function with setting specific objId (result container) when data is loaded via ajax
'***
'***    Created by: dimab
'***    Changed by: sergeyh
'***    Last change: 05/10/2011
'*********************************************************************/
function prepareInputsForHints( tag, objId ) {
	// get all input objects, add onfocus/onblur
	
	var obj = document;
	if(objId != null)
        obj = document.getElementById(objId);
	
	var inputs = obj.getElementsByTagName(tag);
	for (var i=0; i<inputs.length; i++){
		// test to see if the hint span exists first
		if (inputs[i].parentNode.getElementsByTagName("span")[0]) {

			// the span exists!  on focus, show the hint
			addListener(inputs[i], "focus", showHint);

			// when the cursor moves away from the field, hide the hint
			addListener(inputs[i], "blur", hideHint);
		}
		else {
			addListener(inputs[i], "blur", setValid);
		}
		
		// if object has hint atribure, attach additional events
		if (inputs[i].className == "valueHint") {
			addListener(inputs[i], "focus", hideValueHint);
			addListener(inputs[i], "blur", showValueHint);

			// initialize object while working on it
			showValueHintForObject(inputs[i]);
		}
		
	}
}



/*********************************************************************
'***    Program: hideHint( object )
'***    Type: Function
'***
'***    Function: hides hint showing on input/select/text area
'***
'***    Parameters: 
			e - event FF only
'***        
'***    Returns: void
'***	Remarks: designed to be used only onblur event of input with hint
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 12/21/08
'*********************************************************************/
function hideHint( e ) {
	var obj = getEventSource( e );
	var parentNd = obj.parentNode;
	
	var hint = getElementsByTagNameWithClass(parentNd, "span", "hint")[0];
	if (hint == null) 
		return;
		
	hint.style.display = "none";
	setValid();
}


/*********************************************************************
'***    Function: shows hint showing on input/select/text area
'***
'***    Parameters: 
			e - event FF only
'***        
'***    Returns: void
'***	Remarks: designed to be used only onfocus event of input with hint
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 12/21/08
'*********************************************************************/
function showHint( e ) {
	var obj = getEventSource( e );
	var parentNd = obj.parentNode;
	var hint = getElementsByTagNameWithClass(parentNd, "span", "hint")[0];
	if (hint == null)
	    return;
	var input = this;
	hint.style.display = "inline";
    
    var ie = 0;
    var styleLeft = "";
    
    // find fieldset's left
    if (window.navigator.userAgent.indexOf("MSIE 8") >= 0) {
		styleLeft = (ie + obj.offsetLeft + obj.offsetWidth + 15) + "px";
    }
    else if (window.navigator.userAgent.indexOf("MSIE") >= 0) {
    	var ieHint = getElementsByTagNameWithClass(parentNd, "span", "ieHint")[0];

		if (ieHint != null)
		    ie = ieHint.offsetLeft + 15;
		else
			ie = input.offsetLeft + input.offsetWidth + 15;
		styleLeft = ie + "px";
	}
	else {
		styleLeft = (ie + input.offsetLeft + input.offsetWidth + 15) + "px";
	}
	
    hint.style.left =  styleLeft;
}

/*********************************************************************
'***    Function: sets object to valid class
'***
'***    Parameters: none
'***    Returns: void
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 12/3/08
'*********************************************************************/
function setValid( e ) {
	var obj = getEventSource( e );
	
	//this is necessary
	if (obj == null)
	    return;
    
	if (obj.className == "invalidField") {
		window.setTimeout( "setValidById( '" + obj.id + "')", 5000 );
	}
}
/*********************************************************************
'***    Function: sets object to valid class by id
'***    Returns: void
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 12/4/08
'*********************************************************************/
function setValidById( id ) {
	var obj = document.getElementById( id );
	if (obj != null ) {
		 obj.className = "validField";
	}
}

/*********************************************************************
'***    Function: displays a validation alert (div) on the form and sets focus
'***		to the field
'***
'***    Parameters: 
			objectId - id of object to highligh
			validationText - validation text to show
			errorDivId - id of error div to use when showing the messaage. default="errorMessage".
				this can be used to introduce a separate validation message per fieldset or section
'***        
'***    Returns: always returns false to simplify coding when validating forms
'***    Remarks: 
			Assumes and requires a div or other element with ID="errorMessage"
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 12/2/08
'*********************************************************************/
function validationAlert( objectId, validationText, errorDivId ) {
	// get objects
	if (errorDivId == null)
		errorDivId = "validationMessage";
	var input = document.getElementById(objectId);
	var errorElem = document.getElementById(errorDivId);

	// restyle
	if (errorElem != null) {
		errorElem.innerHTML = validationText;
		errorElem.className = "validationMessage";
		errorElem.style.visibility = "visible";
		errorElem.style.display = "block";
		errorElem.scrollIntoView(false);
	}

	if (input != null) {
		input.className = "invalidField";
		input.focus();
	}
	return false;
}
/* this function is used when data is transferred via ajax, so on success event should hide message */
function hideValidationMessage(errorDivId){
    if (errorDivId == null)
		errorDivId = "validationMessage";
    
    var errorElem = document.getElementById(errorDivId);
	
	if(errorElem != null){
	    errorElem.innerHTML = "";
	    errorElem.style.display = "none";
	}
}

/*********************************************************************
'***    Function: shows promopt text in an object (input) which is stored in attribute hint
'***		but only if value is empty
'***
'***    Parameters: 
'***		e - event FF only
'***                
'***    Returns: void
'***
'***    Created by: dimab
'***    Changed by: 
'***    Last change: 12/21/2008
'*********************************************************************/
function showValueHint( e ) {
	var obj = getEventSource( e );
	showValueHintForObject(obj);
}
function showValueHintForObject( obj ) {
	// show text
    var promptText = obj.getAttribute("alt");

    //alt may not be defined, set to empty string
    promptText = (promptText != null) ? promptText : "";
        
	if (obj.value == "")
	    obj.value = promptText;

}
/*********************************************************************
'***    Function: hides promopt text in an object (input) normally onblur
'***		but only if value is empty
'***
'***    Parameters: 
'***		e - event FF only
'***                
'***    Returns: void
'***
'***    Created by: dimab
'***    Changed by: 
'***    Last change: 12/21/2008
'*********************************************************************/
function hideValueHint( e ) {
	var obj = getEventSource( e );

	// hide text
	var promptText = obj.getAttribute("alt");
	if (obj.value == promptText)
		obj.value = "";
}

/*********************************************************************
'***    Function: adds even to a specified element
'***
'***    Parameters: 
'***		element - ref to any element
			type    - standard event name without "on" for IE
			expression - ref to fn
			bubbling - true to bubble events
'***                
'***    Returns: true if success
'***	Remarks:
			you MUST use getEventSource() function to get reference to object that raised event
			example: addListener(document.body, "load", activateUserName);
			this adds listener to onLoad even of document and will call function activateUserName
'***
'***    Created by: internet source
'***    Changed by: dimab
'***    Last change: 12/21/2008
'*********************************************************************/
function addListener(element, type, expression, bubbling){	
	if (bubbling == null) 
		bubbling = false;

	if(element.addEventListener)	{ // Standard		
		element.addEventListener(type, expression, bubbling);
		return true;
	} else if(element.attachEvent) { // IE
		element.attachEvent('on' + type, expression);
		return true;
	} else return false;
}



/*********************************************************************
'***    Function: returns reference to an object which caused current event
'***
'***    Parameters: 
'***		e - event (FF only) for other browsers this is null.
'***                
'***    Returns: object
'***	Remarks:
			1. designed to be used only within events
			2. if you hook events using addListener, use this function to get reference to the 
			object that caused current event.
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 12/21/2008
'*********************************************************************/
function getEventSource( e ) {
	if (e) if (e.target) return e.target; // FF

	var source = null;

	if (this == window) {
	    if (window.event == null)
	        return null; // not within an event
	    source = window.event.srcElement; // IE
	} else {
	    source = this;  // Others
	}
	return source;
}

/*********************************************************************
'***    Function: calculates offsetX when it's not available (FF does not support it)
'***
'***    Parameters: 
			e - event used to calculate offsetX
'***        
'***    Returns: integer. offset x of event target
'***    Remarks: none
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 5/26/09
'*********************************************************************/
function getOffsetX(obj, e) {
	if (!obj.offsetParent)
		return 0;
	
	var parent = obj.offsetParent;
	var intOffsetX = obj.offsetLeft;

	while (parent) {
		intOffsetX += parent.offsetLeft;
		parent = parent.offsetParent;
    }
    if (e == null || e.pageX == null ) return intOffsetX;
	    
	return e.pageX - intOffsetX;
}
/* walks objects in offset stack, calculates offsetLeft */
function getOffsetLeft(obj) {
		
	if (!obj.offsetParent)
		return 0;
		
	var parent = obj.offsetParent;
	var intOffsetX = obj.offsetLeft;

	while (parent) {
		intOffsetX += parent.offsetLeft;
		parent = parent.offsetParent;
	}
	return intOffsetX;
}
/* walks objects in offset stack, calculates offsetTop */
function getOffsetTop(obj) {
		
	if (!obj.offsetParent)
		return 0;
		
	var parent = obj.offsetParent;
	var intOffsetX = obj.offsetTop;

	while (parent) {
		intOffsetX += parent.offsetTop;
		parent = parent.offsetParent;
	}
	return intOffsetX;
}


/*uses one function to calculate element offset position
calculate element offset, return Offset as object w/offsetTop,offsetLeft props*/
function getElementOffsetPosition(obj) {
    //create an object to contain offset values
    var objOffset = { offsetTop: 0, offsetLeft: 0 };
    
    if (obj == null)
        //return object offset
        return offset;
    
    if (obj.offsetParent) {
        var top = 0, left = 0;
        
        left = obj.offsetLeft;
        top = obj.offsetTop;
        
        //calculate offset position
        while (obj) {
            left += obj.offsetLeft;
            top += obj.offsetTop;
            obj = obj.offsetParent;
        }
        
        objOffset.offsetLeft = left;
        objOffset.offsetTop = top;
    }
    
    //return object offset
    return objOffset;
}

/*********************************************************************
'***    Function: shows bubble 
'***
'***    Parameters: 
    e - curent event object
    element - current object calling the event
        - needed as event source is null when called within ajax
    say - html which is displayed in bubble. must be well formed
    pos - where to show bubble. 
    "auto" (default) - calculates best position where to show bubble
    "left" - always shows bubble on left of current object
    "right" - always shows bubble on right of current object
				
'***        
'***    Returns: void
'***    Remarks: none
'***	Use example

addListener(document.getElementById("t1"), "mouseover", function (e) {showBubble( e, 'this is a test <b>of the Bubble</b>')});
addListener(document.getElementById("t2"), "mouseover", function (e) {showBubble( e, 'of course, use it <b>carefully!</b></br> here is a <a href=\'/jobseekerx/\'>link</a> to where you want to go')});
		
or 

onmouseover="showBubble(event, 'this is a bold test <b>bubble</b>')"
onmouseover="showBubble(event, 'this is a bold test <b>bubble</b>', 'right')"

'***    Created by: dimab
'***    Changed by: niloa
'***    Last change: 07/20/09
'*********************************************************************/
function showBubbleForElement(e, element, say, pos, linger, initialDelayMs) {

    if (linger == null)
        linger = true;
        
	if (initialDelayMs == null)
		initialDelayMs = getDefaultBubbleInitialDelay();
	
	bblInfo = getBubbleInfoForEvent(e, element, say, pos);
	bblInfo.linger = linger;

	var now = new Date();
	bblInfo.initialDelayExpires = now.valueOf() + initialDelayMs - 50; // allow 50ms for buffer

	// attach onmouseout event (if empty) to ensure that bubble gets hidden
	if (element != null) {
	    var OnMouseOutDef = element.onmouseout;
	    if (OnMouseOutDef == null)
	        element.onmouseout = function() { phaseOutBubble(element); };
	}
	
	setTimeout( "showBubbleFromInfo()", initialDelayMs );
}


/*********************************************************************
'***    Function: shows bubble 
'***
'***    Parameters: 
			e - curent event object
			say - html which is displayed in bubble. must be well formed
			pos - where to show bubble. 
				"auto" (default) - calculates best position where to show bubble
				"left" - always shows bubble on left of current object
				"right" - always shows bubble on right of current object
				
'***        
'***    Returns: void
'***    Remarks: none
'***	Use example

		addListener(document.getElementById("t1"), "mouseover", function (e) {showBubble( e, 'this is a test <b>of the Bubble</b>')});
		addListener(document.getElementById("t2"), "mouseover", function (e) {showBubble( e, 'of course, use it <b>carefully!</b></br> here is a <a href=\'/jobseekerx/\'>link</a> to where you want to go')});
		
		or 

		onmouseover="showBubble(event, 'this is a bold test <b>bubble</b>')"
		onmouseover="showBubble(event, 'this is a bold test <b>bubble</b>', 'right')"

'***    Created by: dimab
'***    Changed by: niloa
'***    Last change: 7/20/09
'*********************************************************************/
function showBubble(e, say, pos, linger, initialDelayMs ) {
	if (initialDelayMs == null)
		initialDelayMs = getDefaultBubbleInitialDelay();
	bblInfo = getBubbleInfoForEvent(e, null, say, pos);
	bblInfo.linger = linger;

	var now = new Date();
	bblInfo.initialDelayExpires = now.valueOf() + initialDelayMs - 50; // allow 50ms for buffer
	
	setTimeout( "showBubbleFromInfo()", initialDelayMs );
}
// always shows bubble on left
function showBubbleOnLeft( e, say, linger, initialDelayMs ) {
	return showBubble(e, say, "left", linger, initialDelayMs);
}
// always shows bubble on right
function showBubbleOnRight( e, say, linger, initialDelayMs ) {
	return showBubble(e, say, "right", linger, initialDelayMs);
}
// hides bubble
function hideBubble() {
	var hint = document.getElementById("bubbleHint");
	hint.style.display = "none";
}

// hides bubble, but only if id matches id of obj for which bubble was shown last
function hideBubbleForId(id) {
	if (bblInfo == null)
		return;

    if (bblInfo.source.id == id) {
        if (bblInfo.isInUse) {
            // re-schedule
            setTimeout("hideBubbleForId('" + id + "')", getDefaultBubbleLingerDelay());
            return;
        }
        hideBubble();
    }
}
// hides bubble, but only if element matches id of obj for which bubble was shown last
function hideBubbleForElement( element ) {
	if (bblInfo == null)
		return;
    if (bblInfo.source == element) {
        if (bblInfo.isInUse) {
            // re-schedule
            setTimeout(function() { hideBubbleForElement(element); }, getDefaultBubbleLingerDelay());
            return;
        }    
        hideBubble();
    }
}


/*********************************************************************
'***    Function: shows bubble 
'***
'***    Parameters: 
        e - curent event object
        url - url to request with ajax call
        pos - where to show bubble. 
        "auto" (default) - calculates best position where to show bubble
        "left" - always shows bubble on left of current object
        "right" - always shows bubble on right of current object

'***    Returns: void
'***    Remarks: none
'***	Use example

addListener(document.getElementById("t1"), "mouseover", function (e) {showBubbleAjax( e, '/Components/SomeComponent.asp')});

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 6/10/09
'*********************************************************************/
function showBubbleAjax(e, url, pos) {
	showBubble(e, "<div class='loading'></div>", pos, true);

	var func = function(transport) {
		if (bblInfo != null) {
			bblInfo.content = transport.responseText;
			showBubbleFromInfo();
		}
	}
	AjaxGetWithCallback(url, "bubbleText", "failed to retrieve data...", func);
}
function showBubbleAjaxRight(e, url) {
    return showBubbleAjax(e, url, "right");
}
function showBubbleAjaxLeft(e, url) {
    return showBubbleAjax(e, url, "left");
}


// adds bubble text to an object by ID
function addBubbleTextToObject(id, text, pos, hideOnOut, timeToShowBubble) {
	addBubbleToElementById( id, text, pos, ! hideOnOut );
    return true;
}

/*********************************************************************
'***    Function: getActionLinksTemplateContainerElem
'***
'***    Parameters: 
'***    objectType - parameter corresponding to business object type integer value
        - this param is required if a page contains multiple action links column
        - consult /Compiled Help/SE3.chm file (SE_OBJECT_TYPE Public enumeration)
        - use the object type constant that correspond to action links on page
'***    Returns: string
'***    Remarks: 
'***        objectType is required if the page will contain multiple bubble action column
'***        
'***    Created by: niloa
'***    Changed by: 
'***    Last change: 07/20/2009
'*********************************************************************/
function getActionLinksTemplateContainerElem(objectType) {
    var doc = window.document;

    //default template container element
    objectType = (objectType == null) ? "" : objectType;

    //default template container id
    //- when multiple action links exist in a single page, objectType must be passed
    //- create a unique element id by appending objectType to containerId
    var containerId = "actionLinkTemplate";
        containerId += (objectType != "") ? "_" + objectType : "";

    //1. get template text container element
    var obj = doc.getElementById(containerId);

    //2. check templateText container element exist
    if (obj != null)
        return obj; //return reference to the object

    //3. element does not exist yet, create and return object reference
    else {
        //element should be a span not hidden element to avoid sending data accross network
        obj = doc.createElement('span');

        //set a unique id, to templateText container element
        obj.setAttribute('id', containerId);

        //set display=none (hide element)
        obj.style.display = 'none';

        //must add the required element to body
        doc.body.appendChild(obj);
    }

    return obj;
}

/*********************************************************************
'***    Function: getActionLinksTemplateForCurrentPage
'***
'***    Parameters: 
'***        objectType - parameter corresponding to business object type integer value
            - this param is required if a page contains multiple action links column
            - consult /Compiled Help/SE3.chm file (SE_OBJECT_TYPE Public enumeration)
            - use the object type constant that correspond to action links on page
'***    Returns: string
'***    Remarks: 
'***        objectType is required if the page will contain multiple bubble action columns
'***        
'***    Created by: niloa
'***    Changed by: 
'***    Last change: 07/29/2009
'*********************************************************************/
function getActionLinksTemplateForCurrentPage(objectType) {
    var result = new String("");

    if (objectType == null)
        objectType = "";

    //1. get template text container element
    var obj = getActionLinksTemplateContainerElem(objectType);

    //at this point object must exist (albeit empty), 
    //get the template text from the container element
    result = (obj != null) ? String(obj.innerHTML) : "";

    // 2. if template text empty, get the template text from server
    if (result != "")
        return result;
    
    var objError = null;

    //NOTE: this a synchronous (i.e. non-asynchronous) server request which is different from asynchronous,
    //synchronous request will block subsequent statements until server request operation is complete, where
    //asynchronous requests does execute subsequent statements and will not wait for request to complete
    var url = "/Components/GetActionLinksTemplate.asp";
    var settings = null;
    var params = "objectType=" + objectType;
    //set object with action links template text
    try {
        settings = {
            url: url,
            type: 'get',
            async: false,
            data: params,
            success: function(data, textStatus, xhr) {
                result = new String(xhr.responseText);
                //set the template text in the container obj
                if (obj != null)
                    obj.innerHTML = result;
            },
            error: function(xhr, textStatus, errorThrown) {
                //if error occurs, set error info
                objError = new Error("Request to retrieve action links template failed.", "function getActionLinksTemplateForCurrentPage");
            }
        };
        jQuery.ajax(settings);
    }
    catch (ex) {
        settings = {
            method: 'get',
            asynchronous: false,
            parameters: params,
            onSuccess: function(transport) {
                result = String(transport.responseText);
                //set the template text in the container obj
                if (obj != null)
                    obj.innerHTML = result;
            },
            onFailure: function(transport) {
                //if error occurs, set error info
                objError = new Error("Request to retrieve action links template failed.", "function getActionLinksTemplateForCurrentPage");
            }
        };
        new Ajax.Request(url, settings);
    }
    finally {
        settings = null;
    }
    
    //3. if object is not null, this means an error occurred, so throw the error
    if (objError != null)
        throw objError;
    
    return result;
}

/*********************************************************************
'***    Function: showBubbleWithActionsForCurrentPage
'***
'***    Parameters: 
'***        e - event object
'***        element - object when event occurred
'***        objectID - database objectID (e.g. ResumeID, CoverLetterID,...)
'***        objectType - parameter corresponding to business object type integer value
            - this param is required if a page contains multiple action links column
            - consult /Compiled Help/SE3.chm file (SE_OBJECT_TYPE Public enumeration)
            - use the object type constant that correspond to action links on page
'***    Returns: string
'***    Remarks: 
'***        objectType is required if the page will contain multiple bubble action column
'***        
'***    Created by: niloa
'***    Changed by: dimab
'***    Last change: 10/06/2009
'*********************************************************************/
function showBubbleWithActionsForCurrentPage(e, element, objectID, objectType) {
    var templateText = new String("");
    
    //1. try to get action links template
    try {
        //get action link template text
        templateText = getActionLinksTemplateForCurrentPage(objectType);
    }
    catch (ex) {
        //1.2 if error occurs let user know that we cannot show links
        templateText = "Oops. Unable to show action links.";
    }
    
    // attach onmouseout event (if empty) to ensure that bubble gets hidden
    if ((element == null) && (typeof (element) == "object"))
        return;
    
	var OnMouseOutDef = element.onmouseout;
	if (OnMouseOutDef == null)
		element.onmouseout = function(){phaseOutBubble(element);};
    
    // 2.1 replace #ObjectID# in Template with value of ID, save result as BubbleText
    templateText = String(templateText.replace(/#ObjectID#/gim, objectID));

    // 2.2 call showBubble passing replaced text bubbleText as bubble
    showBubbleForElement(e, element, templateText, null, true);
}

/* BUBBLE V2 functions */

/*********************************************************************
'***    Function: bubble info object
'***
'***    Parameters: none
'***        
'***
'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function bubbleInfo() {
	this.left = "0px";
	this.top  = "0px";
	this.hintClass = "hint";
	this.content = "";
	this.cancel = false;
	this.linger = false;
	this.source = null;
	this.initialDelayExpires = 0;
	this.toString = bubbleInfoToString;
	this.isInUse = false; // indicates if user is mousing over bubble
}
/* 
	function: converts bubble info to string
*/
function bubbleInfoToString() {
	var s = "left=" + this.left + "\n top=" + this.top + "\n hintClass=" + this.hintClass + "\n html=" + this.content + "\n cancel=" + this.cancel +"\n linger=" + this.linger;
	return s;
}

/*********************************************************************
'***    Function: calculates bubble positioning and retuns bubble info 
			object populated with positioning info
'***
'***    Parameters: see showBubbleForElement for info
			
'***    Returns: instance of bubbleInfo or null
'***    Remarks: none

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function getBubbleInfoForEvent(e, element, sayHtml, pos) {
    if (e == null)
        e = window.event;

    if (e == null) // nothing to do
        return null;
    
    var doc = window.document;
    var nav = navigator.userAgent;
    var isOldIE = (nav.indexOf("MSIE") >= 0 && nav.indexOf("MSIE 8") == -1);
    var isGecko = (nav.indexOf("Gecko") >= 0);
    var isFF = (nav.indexOf("Firefox") >= 0);
        
    if (pos == null)
        pos = "auto"; // default value of param

    var hint = doc.getElementById("bubbleHint");
    if (hint == null)
		return null;
		 
    var hintClass = "hint";

    //must set bubble display to block prior to calling offsetWidth
    //hint.offsetWidth will return 0 if element display block is none
    hint.style.left = "-2000px";
    hint.style.display = "block";

    //if element is null, get event source instead
    var obj = (element == null) ? getEventSource(e) : element;
    
    var styleLeft = e.clientX;
    var styleTop = e.clientY;
    
    //if element is passed, calculate offset for it
    //this is necessary especially for IE (w/o it bubble will not appear on first try)
    if (element != null) {
        //calculate element offset, return Offset as object with offsetTop and offsetLeft properties
        var objOffset = getElementOffsetPosition(obj);

        //get element Offset properties
        styleTop = objOffset.offsetTop
        styleLeft = objOffset.offsetLeft;
        objOffset = null;
    }

    var intOffsetWidth = obj.offsetWidth;
    var intClientWidth = obj.clientWidth;
    if (isOldIE) // old ie uses OffsetWidth instead
        intClientWidth = intOffsetWidth;

    // get offsetX (ff does not support, calculate for it)
    var intOffsetX = 0;
    if (typeof (e.offsetX) == "number")
        intOffsetX = e.offsetX;
    else
        intOffsetX = getOffsetX(obj, e);
    
    // page scroll fix
    var shiftTop = 0;
    var shiftLeft = 0;
    
   if( element == null ){
        var htmlObj = doc.getElementsByTagName("html")[0];

        if (isGecko && ! isFF) // Gecko based browsers, use body instead
           htmlObj = doc.getElementsByTagName("body")[0];

        if (htmlObj != null) {
            shiftTop = htmlObj.scrollTop;
            shiftLeft = htmlObj.scrollLeft;
        }
   }
        
    // calc position if auto
    if (pos == "auto")
        pos = intOffsetX < intClientWidth / 2 ? "left" : "right";

    var shift = Math.max(intOffsetWidth - intOffsetX, 10);
    //calculate left position
    if (pos == "right") {
        styleLeft = styleLeft + 10 + shift + shiftLeft
    }
    else { // left
        styleLeft = styleLeft - (10 + hint.offsetWidth + intClientWidth) + shiftLeft + shift;
        hintClass = "hint left";
    }
	styleTop = styleTop - 10 + shiftTop;
    
	var bi = new bubbleInfo();
	bi.hintClass = hintClass;
	bi.left = styleLeft + "px";
	bi.top = styleTop + "px";
	bi.content = sayHtml;
	bi.source = obj;
	return bi;    
}

/*********************************************************************
'***    Function: prevents bubble appearnce or hides bubble if showing
'***
'***    Parameters: none
			
'***    Returns: void
'***    Remarks: none

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function stopBubble() {
	if (bblInfo == null)
		bblInfo = new bubbleInfo();
	bblInfo.cancel = true;
	hideBubble();
}

/*********************************************************************
'***    Function: returns default linger delay in ms
'***
'***    Parameters: none
			
'***    Returns: integer
'***    Remarks: none

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function getDefaultBubbleLingerDelay() {
	return 7000;
}
/*
	same as above for initial delay
*/
function getDefaultBubbleInitialDelay() {
	return 1000;
}

/*********************************************************************
'***    Function: phases bubble out  by id after a specified interval
'***
'***    Parameters: 
			elemId - id of element to use when hiding
			lingerDelayMs - overwrite delay. (optional)
			
'***    Returns: void
'***    Remarks: if bubble was created for obj with different id, bubble will not hide

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function phaseOutBubbleById( elemId, lingerDelayMs ) {
	if (lingerDelayMs == null)
		lingerDelayMs = getDefaultBubbleLingerDelay();
			
	if (isBubbleVisible())
		setTimeout("hideBubbleForId('" + elemId + "')", lingerDelayMs);
	else
		stopBubble();
}
/*****************
'***    Function: same as above, but uses element instance instead of id
******************/
function phaseOutBubble( elem, lingerDelayMs ) {
	if (lingerDelayMs == null)
		lingerDelayMs = getDefaultBubbleLingerDelay();
			
	if (isBubbleVisible())
		setTimeout(function (){hideBubbleForElement(elem);}, lingerDelayMs);
	else
		stopBubble();
}

/*********************************************************************
'***    Function: determines if bubble is currently visible
'***
'***    Parameters: none
			
'***    Returns: boolean
'***    Remarks: none

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function isBubbleVisible() {
    var hint = document.getElementById("bubbleHint");
    if (hint == null)
		return false;
    return (hint.style.display == "block" && hint.style.visibility == "visible");
}

/*********************************************************************
'***    Function: shows bubble using page level bubbleInfo object 
'***
'***    Parameters: none
			
'***    Returns: boolean
'***    Remarks: bubbleInfo instance must be set by calling showBubble or showBubbleForElement

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function showBubbleFromInfo() {
	if (bblInfo == null)
		return;
		
	if (bblInfo.cancel)
		return;

    var now = new Date();
    if (bblInfo.initialDelayExpires > now.valueOf()) {
        // not time to show yet. check back in 1 sec
        setTimeout("showBubbleFromInfo()", 1000);
        return; 
    }

    var hint = document.getElementById("bubbleHint");
    if (hint == null)
		return;
	var hintText = document.getElementById("bubbleText");

    hint.className = bblInfo.hintClass;
    hint.style.position = "absolute";
    hint.style.left = bblInfo.left;
    hint.style.top = bblInfo.top;			    
    hint.style.display = "block";
	hint.style.visibility = "visible";
		
	// hide/show close btn depending on bubble type
	var closeBtn =  document.getElementById("bubbleClose");
	if (closeBtn != null)
		closeBtn.style.display= (bblInfo.linger == true ? "block" : "none");
		
    // show hint
    hintText.innerHTML = bblInfo.content;
}

/*********************************************************************
'***    Function: adds necessary events to element to show bubble using specified html
'***
'***    Parameters: 
			elementInstance, - instance of DOM element obj
			sayHtml - html to use in bubble. must be well formed
			pos - (optional) "left", "right", "auto"=default
			linger - if true bubble stays for a while after user moves mouse away from object that created bubble
					 if false, bubble disappears immediately upon mouse out
			
'***    Returns: void
'***    Remarks: none

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function addBubbleToElement(elementInstance, sayHtml, pos, linger) {
    if (linger == null)
        linger = true;
    addListener(elementInstance, "mouseover", 
		function(e) {
			var src = getEventSource(e);
			if (src != null && src.id == elementInstance.id) //show only for specified id
				showBubbleForElement(e, elementInstance, sayHtml, pos, linger)
		})
		
	if ( ! linger )
        addListener(elementInstance, "mouseout", stopBubble);
	else
		addListener(elementInstance, "mouseout", function(e) {phaseOutBubble(elementInstance);});
}
/*********************************************************************
'** 	function: same as addBubbleToElement, but done using id
********************************************************************/
function addBubbleToElementById(elementId, sayHtml, pos, linger) {
    if (linger == null)
        linger = true;
        
	var elementInstance = document.getElementById(elementId);
	if (elementInstance == null)
		return;
		
    addListener(elementInstance, "mouseover", 
		function(e) {
			var src = getEventSource(e);
			if (src != null && src.id == elementId) //show only for specified id
				showBubbleForElement(e, null, sayHtml, pos, linger)
		})
		
	if ( ! linger )
        addListener(elementInstance, "mouseout", stopBubble);
	else
		addListener(elementInstance, "mouseout", function(e) {phaseOutBubbleById(elementId);});
}

function bubbleMouseOver() {
    if (bblInfo == null)
        return;
    bblInfo.isInUse = true;
}
function bubbleMouseOut() {
    if (bblInfo == null)
        return;
    bblInfo.isInUse = false;
}

/*********************************************************************
'***    Function: shows enlarged image in bubble when user crosshair focused on object
'***
'***    Parameters: 
'***            e - event
'***			filePath - path to image file for this account
'***            lngThubnailSize - max size (in px) for enlarged image in bubble
'***
'***    Returns: void
'***    Remarks: none
'***
'***    Created by: sergeyh
'***    Changed by: sergeyh
'***    Last change: 11/30/2010
'*********************************************************************/
function showImgInBubble(e, filePath, lngThubnailSize){
    // size of enlarged photo
    lngThubnailSize = parseInt(lngThubnailSize);
    if(isNaN(lngThubnailSize) || lngThubnailSize <= 0)
        lngThubnailSize = 200;
    
    // compose image html
    filePath = "/Scripts/Thumbnail.asp?f=" + filePath + "&amp;s=" + lngThubnailSize;
    var enlargedPhoto = '<img src="' + filePath + '"/>';
    
    // set hint width to max thumbnail size
    var hint = document.getElementById("bubbleHint");
    if(hint != null)
        hint.style.width = lngThubnailSize + "px";
    
    // show enlarged image
    showBubble(e, enlargedPhoto, "right");
}


/*********************************************************************
'***    Function: debugging funciton. add element with id "tell" and print using "
'***
'***    Parameters: 
			what - text to print
			append - true = info is appened
			
'***    Returns: void
'***    Remarks: none

'***    Created by: dimab
'***    Changed by: dimab
'***    Last change: 10/6/09
'*********************************************************************/
function tell( what, append ) {
	if (append == null)
		append = false;
		
	var elem = document.getElementById("tell");
	if (elem == null)
		return;
	
	if (append)
		elem.innerHTML += "; " + what;
	else
		elem.innerHTML = what;
}

// page instance of bbl info
bblInfo = null;
// add call to onload event
addLoadEvent(prepareAllInputsForHints);

