
// ******* author Matthew Robinson *******

// ******* start GENERAL SETTINGS (these can be tweaked accordingly) *******

	var g_strParentID = "newsTicker"	// the id of the parent element
	var g_intMaxItems = 3;				// the maximum number of new items that the ticker should display
	var g_intTickerSmallPause = 25;		// scroll speed (timeout)
	var g_intTickerBigPause = 1500;		// pause length (timeout)
	
	var g_blnSlideOver = false;			// items at the top of the ticker can either be overlapped by the item
										// underneath or else simply vanish
	
// ******* end GENERAL SETTINGS *******

g_intMaxItems++;						// we increment this variable straight away


var g_objParent;						// holds a reference to our parent element
var g_arrOriginalHTML;					// holds the original HTML items (plus an additional wrapping paragraph)
var g_intParentTop;						// holds a reference to the current top coordinate of our parent element
var g_intIItem = 0;						// holds the index of the news item that the program is currently dealing with
var g_intItemsTotal;					// holds the total number of items in the original html page

var g_intTallestItemSize;				// holds the height of the tallest item

var g_blnPauseLoop = false;				// used to flag when the ticker is paused




// wait until the document has loaded before we execute any function
window.onload = function()
{
	
		if (!document.getElementById) { return false }
		if (!document.getElementsByTagName) { return false }
		
				
		

		
		g_objParent  = document.getElementById(g_strParentID);	// create a reference to our parent element
		
		
		g_arrOriginalHTML = f_GetOriginalHTML(g_objParent);		// load an array with all the innerHTML of each of our paragraph elements (which will include the new bottom reference element)
		g_intItemsTotal = g_arrOriginalHTML.length;

		
		/* ******* if there are either insufficent news items on the web page, or else fewer items than specified in g_strParentID,
		then we prevent the code from running any further than here ******* */
		if ((g_intItemsTotal <= 1) || (g_intItemsTotal < g_intMaxItems)) { return false }
		
		
					
		
		f_Main();

}









// ----------------------------------------------------------- f_Main() -------------------------------------------------------------
function f_Main()
{
		
	//monitor the position of the top of our parent element
	var intCheckParentTop = f_FindPosY(g_objParent);

	//we reload the whole ticker if the top coordinate of our parent element is altered
	if (g_intParentTop != intCheckParentTop)
	{
		f_Refresh();
		f_ClearTicker(g_objParent);
	}
	
	
	f_TickerLoop(g_objParent, g_arrOriginalHTML, g_intItemsTotal);
}
// .......................................................... end f_Main() .........................................................





function f_TickerLoop(objParent, arrOriginalHTML, intItemsTotal)	//this is the main control loop (controls function execution timing)
{
	

	if (g_blnPauseLoop) {  setTimeout(f_Main, g_intTickerSmallPause); return false};
	
	var blnItemAtTop = false;
	
	var arrVisibleDivs = objParent.getElementsByTagName('div');
	var intUBound = arrVisibleDivs.length;

	
	// ------- IF THE TICKER IS EMPTY....... -------
	if (intUBound <= 0)
	{

		//if the ticker is empty, then we build every single News Item so that we can establish the required height for our ticker
		for (var i=0; i<g_intItemsTotal;  i++)
		{
			var objNewDiv;
			var objBottomRef;
			
			if (i == 0)
			{
				objNewDiv = f_AddNewsItem(g_objParent, g_intParentTop, arrOriginalHTML[i], i);
				objBottomRef = f_CheckBottomRef(objNewDiv);
				g_intTallestItemSize = f_FindPosY(objBottomRef) - g_intParentTop;
			}
			else
			{
				var intLastItemBottom = f_FindPosY(objBottomRef);
				objNewDiv = f_AddNewsItem(g_objParent, intLastItemBottom, arrOriginalHTML[i], i);
				objBottomRef = f_CheckBottomRef(objNewDiv);
				var intTestHeight = f_FindPosY(objBottomRef) - intLastItemBottom;
				if (intTestHeight > g_intTallestItemSize)
				{
					g_intTallestItemSize = intTestHeight;
				}
			}
		
		
			f_RemoveElement(objNewDiv);
		}


		// once we have the hieght of the tallest item, we must rebuild the list (first few items as specified by g_intMaxItems)
		// and also set the height of the child paragraph elements to g_intTallestItemSize
		for (var i=0; i<g_intMaxItems - 1;  i++)
		{
			var objNewDiv;
			var objBottomRef;
			
			if (i == 0)
			{
				objNewDiv = f_AddNewsItem(g_objParent, g_intParentTop, arrOriginalHTML[i], i);
				objBottomRef = f_CheckBottomRef(objNewDiv);
			}
			else
			{
				var intLastItemBottom = f_FindPosY(objBottomRef);
				objNewDiv = f_AddNewsItem(g_objParent, intLastItemBottom, arrOriginalHTML[i], i);
				objBottomRef = f_CheckBottomRef(objNewDiv);
			}
		
			objNewDiv.style.height = g_intTallestItemSize + "px";
			var objChildPara = objNewDiv.getElementsByTagName('p');
			objChildPara[0].style.height = g_intTallestItemSize + "px";
		}

		
		//we've added and removed a few elements with the previous code, so we need to reload these variables
		arrVisibleDivs = objParent.getElementsByTagName('div');
		intUBound = arrVisibleDivs.length;

		
	
		//initialise the global incrementer so that the ticker will begin loading from the next available News Item
		g_intIItem = intUBound;


		//we can now calculate exactly how much space will be required to accomodate our elements no matter how large,
		//so we style our ticker container accordingly
		objParent.style.height = (g_intTallestItemSize * (g_intMaxItems )) + "px";

		
		// pause the ticker at the beginnning so that the user will have a chance to read the very first item
		setTimeout(f_Main, g_intTickerBigPause);
		return false;
	}



	// ------- IF THE TICKER IS ALREADY LOADED....... -------
	if (intUBound > 0)
	{
			
		for (var i=0; i<intUBound; i++)
		{	
			//get the current position of each div
			var intCurrPos = arrVisibleDivs[i].style.top.replace("px", "");
			
			//if the div has not yet reached the top of the ticker then we raise it by one pixel
			if (intCurrPos > g_intParentTop)
			{
				intCurrPos--;
				arrVisibleDivs[i].style.top = intCurrPos + "px";
				if (intCurrPos == g_intParentTop) { blnItemAtTop = true; }
				
				var intCurrHeight = arrVisibleDivs[i].style.height.replace("px", "");
				
				if (intCurrHeight < g_intTallestItemSize)
				{
					intCurrHeight++;
					arrVisibleDivs[i].style.height = intCurrHeight + "px";
					var objChildPara = arrVisibleDivs[i].getElementsByTagName('p');
					objChildPara[0].style.height = intCurrHeight + "px";
				}
			}
			else
			{	
					//check which style we're using to remove items from the top of the ticker
					if (!g_blnSlideOver) { arrVisibleDivs[i].style.visibility = "hidden"; }
					
					//if the div has reached the top of the ticker then we shrink it by one pixel
					var intCurrHeight = arrVisibleDivs[i].style.height.replace("px", "");
					intCurrHeight--;

					
					if (intCurrHeight > 0)
					{
						arrVisibleDivs[i].style.height = intCurrHeight + "px";
					
						if (intCurrHeight == (g_intTallestItemSize - 1))
						{
							
							var objBottomRef = f_CheckBottomRef(arrVisibleDivs[intUBound - 1]);
							var intBottomPos = f_FindPosY(objBottomRef);
							
							var objNewEl = f_AddNewsItem(g_objParent, intBottomPos - 1, arrOriginalHTML[g_intIItem], g_intIItem);
							objNewEl.style.height = "0px";
							

							
							g_intIItem++;
							
							if (g_intIItem >= g_intItemsTotal) { g_intIItem = 0; }
						}
					}
					else
					{
						f_RemoveElement(arrVisibleDivs[i]);
						arrVisibleDivs = objParent.getElementsByTagName('div');
						intUBound = arrVisibleDivs.length;
					}
					
			}
				
		}
	

	}


		
	if (blnItemAtTop) { setTimeout(f_Main, g_intTickerBigPause); }	
	else { setTimeout(f_Main, g_intTickerSmallPause); }
	
}







// ---------------------------------------------------------- f_Refresh() ----------------------------------------------------------
function f_Refresh()	// we use this sequence to update coordinates if the user resizes the text
{
	g_intParentTop = f_FindPosY(g_objParent);
	g_intIItem = 0;
}
// ........................................................ end f_Refresh() ........................................................







// -------------------------------------------------------- f_RemoveElement() -------------------------------------------------------
function f_RemoveElement(objEl) { if (objEl.parentNode)	{ objEl.parentNode.removeChild(objEl); } }
// ...................................................... end f_RemoveElement() .....................................................







// --------------------------------------------------------- f_AddNewsItem() --------------------------------------------------------
function f_AddNewsItem(objParent, intAppearance, strContent, intOriginalArrayIndex)
{
	var objNewDiv = document.createElement('div');
	
	objParent.appendChild(objNewDiv); 
		
	if (intAppearance != null) { objNewDiv.style.top = intAppearance + "px"; }
	objNewDiv.innerHTML = strContent;
	objNewDiv.id = intOriginalArrayIndex;
	objNewDiv.style.position = "absolute";
	objNewDiv.style.overflow = "hidden";
	
	
	//add events
	objNewDiv.onmouseover = function() { g_blnPauseLoop = true; };
	objNewDiv.onmouseout = function() { g_blnPauseLoop = false; };
	
	//add an element that we can use to reference the bottom coordinate of each News Item DIV
	f_AddBottomRef(objNewDiv);
	
	
	
	return objNewDiv;
}
// ....................................................... end f_AddNewsItem() ......................................................







// -------------------------------------------------------- f_ClearTicker() ---------------------------------------------------------
function f_ClearTicker(objParent) { objParent.innerHTML = ""; }
// ....................................................... end f_ClearTicker() ......................................................







// -------------------------------------------------------- f_CheckBottomRef() ------------------------------------------------------
function f_CheckBottomRef(objEl)		// returns an object reference to the dynamically inserted SPAN tag
{
	if (objEl.hasChildNodes)
	{
		var objChildren = objEl.childNodes;
		var intChildrenLength = objChildren.length;
		for (var iChild=0; iChild < intChildrenLength; iChild++)
		{
			if (objChildren[iChild].nodeName == 'SPAN') { return objChildren[iChild] }
		}
	}
}
// ....................................................... end f_CheckBottomRef() ...................................................







// ------------------------------------------------------------- f_FindPosY() -------------------------------------------------------
function f_FindPosY(objEl)			// finds the top co-ordinate of an element
{
	var intElTop = 0;
	
	while(objEl.offsetParent)
	{
		intElTop += objEl.offsetTop;
		objEl = objEl.offsetParent;
	}
		
	if (objEl.y)
	{
		intElTop += objEl.y;
	}


	return intElTop;
}
// ........................................................... end f_FindPosY() .....................................................







// -------------------------------------------------------------- f_GetHTML() -------------------------------------------------------
function f_GetOriginalHTML(objParent)		// returns an array containing the HTML content that forms our news items
{
	var objPara = objParent.getElementsByTagName('p');
	
	// find the number of P elements in our parent element
	var intUBound = objPara.length;
	
	// define an array that is large enough to hold the innerHTML from each of the P elements
	var arrNews = new Array(intUBound);
	
	for (var i=0; i < intUBound; i++)
	{
		arrNews[i] = "<p>" + objPara[i].innerHTML + "</p>";
	}
	
	return arrNews;
}
// ............................................................. end f_GetHTML() ....................................................







// ------------------------------------------------------------ f_AddBottomRef() ----------------------------------------------------
function f_AddBottomRef(objParent)
{
		//NOTE: remember that the parent, in this case, is the News Item DIV, as opposed to
		//the outer containing DIV
		var objNewEl = document.createElement('span');
		objParent.appendChild(objNewEl);
		objNewEl.style.className = 'bottomMarker';
		objNewEl.style.height = 0;
		objNewEl.style.width = 0;
		objNewEl.style.visibility = 'hidden';
	

}
// ........................................................... end f_AddBottomRef() .................................................













