/*
sg layout
a javascript to layout text in multiple columns in DOM compatible browsers
this system was first created for the article text on IHT.com (The International Herald Tribune)

author
- - - 
john weir
john@smokinggun.com
more info at http://www.smokinggun.com
Thanks to Juerg Lehni {www.vectorama.org} {www.scratchdisk.com} for helping me finish this, improving some methods, and testing.

copyright
- - - - - -
Copyright (C) 2001 John Weir  (www.smokinggun.com)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
A copy of the license may be found at www.smokinggun.com/perm/gnu.php
or www.fsf.org (Free Software Foundation)
*/

var ART_HEIGHT_MIN = 100; //minium height the View can be
var ART_HEIGHT_MAX = 400; //maximiun height for View, set to 0 if there is no limit, set = to ART_HEIGHT_MIN to make the view non scaleable

var NAVIGATION_AREA = 460; //Number of pixels used by navigation or non article text
							// this variable should be detected at initialization, but is not yet

var LINE_HEIGHT_MOD = .2;  	// the line height ='s the font_size (see below) * LINE_HEIGHT_MOD + font_size
var MAX_LINE_HEIGHT = .5;	// the modifier can adjust itself in the event of a roudning error

var ORIGINAL_LINE_HEIGHT_MOD = LINE_HEIGHT_MOD;

var CONTENTS = "pageContents";  // name of HTML element containing the text body
var VIEWER = "textParent"; //name of HTML element to hold column(s)
var IMG_VIEWER = "imageViewer"; //name of HTML element to hold images(s)

var IMG_INLINE = false; //set to true if images should appear inline, more processor intesive
					//!! Not implemented yet
					
var COLUMN_NUM = 2; // base mode for the number of columns present

var font_size = 11; //base font-size
var font_size_MAX = 26;
var font_size_MIN = 9;


//  # # #


var oddObjArray = new Array(); //tracks all child nodes in article for odd sized type and images

var line_height = font_size*LINE_HEIGHT_MOD; // column hieghts are deteremined by the line height, this is the critical variable
var column_position = 0; // page position
var column_height_total = 0; // ??

var bodyNode; // body tag id should fix this and id the body by getElementsByTagName

var viewer_height = 0; // height of the text viewer
allImagePositions = new Array();
allParagraphPositions = new Array();

// feste Höhe des Viewers
var CONCRETE = 375;

// short for getElementById
function gId(o){return document.getElementById(o);}

// this is work around a bug in early version of the Mozilla engine(in Netscape 6.0)
// the bug does not track object offsets properly
// this method should be called when the fonts are resized, or any other
// event which would affect offsets
function st_imageCount()
	{
	var obj = gId("at0");
	var allImages = obj.getElementsByTagName("img");
	
	for (var imgCounter = 0; imgCounter < allImages.length; imgCounter++)
		{
		allImagePositions[imgCounter] = Math.abs(allImages[imgCounter].offsetTop);
		}
	
	for (var colCounter = 0; colCounter < COLUMN_NUM; colCounter++)
		{
		var obj = gId("at"+colCounter);
		var allImages = obj.getElementsByTagName("img");
		
		for (var imgCounter = 0; imgCounter < allImages.length; imgCounter++)
			{
			allImages[imgCounter].style.height = "0px";
			}
		
		}
	
	}

//places positions of paragraphs into an array
 function st_paragraphCount()
	{
	var obj = gId("at0");
	var allParagraphs = obj.getElementsByTagName("p");
	
	nsFix = 0;
	
	for (var pCounter = 0; pCounter < allParagraphs.length; pCounter++)
		{
		//Netscape 6.01(and probably lower) starts the first paragraph out at a number other than
		//0, although it should be 0, this is a fix for that problem
		if (pCounter == 0) nsFix = Math.abs(allParagraphs[pCounter].offsetTop);
		allParagraphPositions[pCounter] = Math.abs(allParagraphs[pCounter].offsetTop)-nsFix;
		}
	}	
	

// controls display of images	
function st_displayImages()
	{
	//var imgOut = ""; //this string contains the HTML the be written out to create the images
	
	var obj = gId("at0");
	var allImages = obj.getElementsByTagName("img");
	
	
	var start = Math.abs(-1*(viewer_height*(column_position)));
	var end = Math.abs((viewer_height*(COLUMN_NUM+column_position)));
	var imgOut = "";//start+" | "+end+"<br><br>";
	
	for (var imgCounter = 0; imgCounter < allImages.length; imgCounter++)
		{	
			var tempTop = allImagePositions[imgCounter];
			var imgObj = allImages[imgCounter];
			
			/*
			This is a fix for mozilla, but appears to have been fixed in Mozilla version .9.4 (or earlier)
			Since the offsetTop seems to be adjusted based also on the parent's position
			*/
			
			var comment = start+" | "+end+" | "+tempTop;
			
			window.status = comment +" "+(tempTop >= start && tempTop <= end);
			
			//an image has been found
			if (tempTop >= start && tempTop <= end)
				{
			
				if (!IMG_INLINE)
					{
					//you will want to alter this to fit your layout needs
					imgOut += "<div><img src=\""+allImages[imgCounter].src+"\"><br>"+allImages[imgCounter].getAttribute('custom')+"</div>";
					}
				if (IMG_INLINE)
					{
					
					allImages[imgCounter].style.width="100px";
					allImages[imgCounter].style.height="100px";
					}
				}
		}
	// draw the images
	if (!IMG_INLINE)
		{
		gId(IMG_VIEWER).style.display = "none"
		gId(IMG_VIEWER).innerHTML = imgOut;
		gId(IMG_VIEWER).style.display = "block"

		}
	
	}

// makes sure that a paragraph starts on the first line, to be flush with the top
// this currently is buggy in layouts with more than 2 columns

function st_alignParagraphs()
	{
	var paragraphOffset = 0;
	for (var c = 0; c < COLUMN_NUM; c++)
		{
		
		var column = gId("at"+c);
		var allParagraphs = column.getElementsByTagName("p");
		
		// offset the column for any previous out of alignment paragraphs
		column.style.top =  (parseInt(column.style.top)-paragraphOffset)+"px";
		
		var start = Math.abs(-1*(viewer_height*(c+column_position)))+1-paragraphOffset;
		var end = start+line_height;

		for (var pCounter = 0; pCounter < allParagraphs.length; pCounter++)
			{	
				var pTop = allParagraphPositions[pCounter]-paragraphOffset;//Math.abs(allImages[imgCounter].offsetTop);
				var imgObj = allParagraphs[pCounter];
				
				//a paragraph is within the range
				if (pTop >= start && pTop <= end)
					{
					//adjust the top of the active column
					column.style.top = ((parseInt(column.style.top)-line_height))+"px";
					
					// increase the global paragraphOffset
					paragraphOffset = paragraphOffset+line_height;
					
					// for debugging
					//allParagraphs[pCounter].style.color = "#FF0000";					
					}
			} 
		}
	
		
	}

/* returns the height, in pixels of object */

function st_getHeight(o)
	{
	if (o == "w") 
		{
		o = gId("bodyNode")
		if (window.innerHeight) return window.innerHeight
		else return parseInt(o.offsetHeight)
		}
	else
	{
	o = gId(o);
	if (o.offsetHeight) return o.offsetHeight;
	}}


/* setup 
	creates the columns

*/	
	
function st_columnSetup()
	{
	p = gId(VIEWER);
	p.innerHTML = "";
	column_position = 0;
	
	var o = gId(CONTENTS)
	
	for (i=0; i < COLUMN_NUM; i++)
		{
		
		var aT = document.createElement("div");
		aT.setAttribute("id","at"+i)
		aT.setAttribute("className","stText");
		aT.setAttribute("class","stText");
		aT.innerHTML = o.innerHTML;
		
		if (document.all) var cur = "hand"
		else  var cur = "pointer"
		if (i == 0 || i == COLUMN_NUM-1)	
			{
			aT.style.cursor = cur;
			aT.onclick = st_columnClick;
			aT.onmouseover = st_columnOver;
			aT.onmouseout = st_columnOut;
			}
		
		aT.style.display = "block";
		p.appendChild(aT);
		}
	}
	
/* creates a div for printing
this is a cludge for now since a pure css solution is not working on both moz and safari */

function st_printColumnSetup()
	{
	
	var o = gId(CONTENTS)
	
	var aT = document.createElement("div");
	aT.setAttribute("id","printPane")
	aT.innerHTML = o.innerHTML;				
	
	// if you don't have a body node named bodyNode, change the below
	gId("bodyNode").appendChild(aT);

	}


/* 
	lays out the columns 
	this is fired when ever the type faces change, "pages" turned, or window resized
*/	
	
function st_columnLayout()
	{	
    viewer_height = CONCRETE;
	// viewer_height = st_getHeight(VIEWER);                                                                                                                                                                                      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!               
	for (var i = 0; i < COLUMN_NUM; i++)

		{				
		o = gId("at"+i);
		st_moveColumnLeftPosition(i);
		if (viewer_height > 2*line_height) o.style.top = -1*(viewer_height*(i+column_position))+"px";
		}
	tC = column_height_total/viewer_height; 
	tP = Math.ceil(tC); 
	tPos = (column_position+COLUMN_NUM)/COLUMN_NUM; 
	o = gId("P")

	st_alignParagraphs();
	
	// if the current page is > than the total pages
	if ((Math.round(tPos)) > (Math.ceil(tP/COLUMN_NUM)))
		{
		st_screenPrevious();
		}
	//customize you page number here
	o.innerHTML = ""+(Math.round(tPos))+"/"+(Math.ceil(tP/COLUMN_NUM));
	
	st_displayImages();
	
	}
	

// adjust the column height to the line height to avoid cropping a column mid line

function st_columnSnapHeight(m) 
	{
	if (m == null) m =0;
	
	var h = st_getHeight("w");
	/*
	A bug is occuring with ART_HEIGHT_MIN and MAX
	if(h < ART_HEIGHT_MIN) h = ART_HEIGHT_MIN;
	if(h > ART_HEIGHT_MAX && ART_HEIGHT_MAX > ) h = ART_HEIGHT_MAX;
	*/
	
	s = line_height*Math.round((h-m)/line_height)
	
	if (s < line_height*1) s = line_height*1
	return s;
	}
	
	
function st_columnSetHeight()
	{
	if (COLUMN_NUM > 1)
	{
	if (gId(CONTENTS) != null)
		{
		// gId(VIEWER).style.height = st_columnSnapHeight(NAVIGATION_AREA)+"px";
        gId(VIEWER).style.height = CONCRETE+"px";
		// column_height_total = st_getHeight("at1");	viewer_height = st_getHeight(CONTENTS)                                                                                                                                                                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!    
        column_height_total = st_getHeight("at1");	viewer_height = CONCRETE
		while ((viewer_height*(column_position+COLUMN_NUM-1)) > column_height_total && column_position > 0)column_position= column_position-1
			st_columnLayout()
			}
	}}
	
	
function st_screenNext()
	{
	// viewer_height = st_getHeight(VIEWER)                                                                                                                                                                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!    
    viewer_height = CONCRETE
	if ((viewer_height*(column_position+COLUMN_NUM)) < column_height_total)column_position= column_position+COLUMN_NUM;
	st_columnLayout();
	}
	
function st_screenPrevious()
	{
	column_position= column_position-COLUMN_NUM;
	if (column_position < 0) column_position = 0
	st_columnLayout()
	}

//returns the event object
function st_getEventObj(e) {
	if (e == null) e = event;
	if (e.srcElement) obj = e.srcElement;
	else obj = e.target;

	var count = 0;
	do {
	obj = obj.parentNode;
	} 
	while ((obj.id == null || obj.id == "") && count++ < 2); //work around for Moz
	 
	return obj;
	}


// for interface highlighting
// you will want to customize these two method
function st_over(direction)
	{
	obj = document.getElementById("page"+direction);
	obj.style.color = "#fff"
	}
	
function st_out(direction)
	{
	obj = document.getElementById("page"+direction);
	obj.style.color = "#ccc"
	
	}

// called when the mouse is over the column
// add events like navigation button changes here
function st_columnOver(e)
	{
	// if there is more than one column
	if (COLUMN_NUM > 1)
		{
		var cur = document.all ? "hand" : "pointer";
		obj = st_getEventObj(e);
		if (obj.id.indexOf("0") > -1) // if the first column is moused over
			{
			var hilite = (column_position > 0);
			obj.style.cursor = hilite ? cur : "default";
			if (hilite) 
				try {st_over("previous");}
				catch(error){}
			}

		if (obj.id.indexOf(COLUMN_NUM-1) > -1) //if the last column is moused over
			{
			var hilite = ((viewer_height*(column_position+COLUMN_NUM)) <
			column_height_total);
			obj.style.cursor = hilite ? cur : "default";
			if (hilite) 
				try {st_over("next");}
				catch(error){};
			}
		}
	}
	
function st_columnOut(e)
	{
	// if there is more than one column
	if (COLUMN_NUM > 1)
		{
		
		obj = st_getEventObj(e);
		if (obj.id.indexOf("0") > -1) // if the first column is moused out
			{
			try {st_out("previous");}
				catch(error){}
			}

		if (obj.id.indexOf(COLUMN_NUM-1) > -1) //if the last column is moused out
			{
	   		try {st_out("next");}
				catch(error){}
	   		}
  		}
	}


// called when a column has been clicked on
// routes event to appropriate method, or cancles if user is clicking a link or copying text

/*
function st_columnClick(e)
	{
	if (e != null) event = e;
		if (event.srcElement) obj = event.srcElement;
		else obj = event.target;
	
	if (obj.nodeName.toLowerCase() == "a" || obj.parentNode.nodeName.toLowerCase() == "a")
		{
		// route to the link; //
		if (obj.nodeName.toLowerCase() == "a") document.location = obj.getAttribute("href");
		if (obj.parentNode.nodeName.toLowerCase() == "a") document.location = obj.parentNode.getAttribute("href");
		}
		
	// object clicked is not a link
	
	else
		{
		//parse through the parent objects looking for an object with an id
		// this needs to be improbed to detect only objects with an id of "at"
		var tcounter = 0;
		if (obj.id == null || obj.id == "")
			{
			do {
				obj = obj.parentNode;
				}			
			while ((obj.id == null || obj.id == "") && tcounter < 10);
			}
		
		// if there is more than one column		
		if (COLUMN_NUM > 1)
			{
			// if the first column is clicked
			if (obj.id.indexOf("0") != -1) st_screenPrevious();
			
			//if the last column is clicked
			if (obj.id.indexOf(COLUMN_NUM-1) != -1) st_screenNext();
			}
		
		// different method will need to be used for single column mode
		
		if (COLUMN_NUM == 1)
			{
			
			}
		}
	}
*/

function st_columnClick(e)
	{
	if (e == null) e = event;
	var obj = e.srcElement ? event.srcElement : e.target;
	if (obj.nodeName.toLowerCase() == "a" || obj.parentNode.nodeName.toLowerCase() == "a") return true;
	// object clicked is not a link
	// if there is more than one column
	if (COLUMN_NUM > 1)
		{
		obj = st_getEventObj(e);
		// if the first column is clicked
		if (obj.id.indexOf("0") != -1) st_screenPrevious();
		
		//if the last column is clicked
		if (obj.id.indexOf(COLUMN_NUM-1) != -1) st_screenNext();
		}
	}



//moves the column into horizontal position
function st_moveColumnLeftPosition(i)
	{
	o = gId("at"+i)
	o.style.left = (i*(parseInt(o.offsetWidth)+10))+"px"
	}



var loop_counter = 0; //used to check for possible infinite loop 

function st_fontSetSize(TEMP_LINE_HEIGHT_MOD)
	{
	line_height = Math.round(font_size+(LINE_HEIGHT_MOD*font_size));
	
	// st_getHeight("aT0")/line_height should be an integer
	// otherwise you will get an offset error	
	
	for (var i = 0; i < COLUMN_NUM; i++) 
		{ 
		o = gId("at"+i);
		o.style.fontSize = font_size+"px";
		o.style.lineHeight = line_height+"px" 
		}
	
	//set paragraph margins
	tObject = gId(VIEWER);
	
	var o = gId("stStyle");
	
	//ie version
	if (document.styleSheets[0].addRule != null)
		{
		document.styleSheets[1].rules.item(0).style.marginBottom =  line_height+"px";
		}
	else if (o.sheet != null)
		{
		o.sheet.cssRules[0].style.marginBottom = line_height+"px";
		}
	else //no stylesheet found
		{
		var o = gId(VIEWER);
		allParagraphs = o.getElementsByTagName("p");
		for (var i= 0; i < allParagraphs.length; i++)
			{
			allParagraphs[i].style.marginBottom = line_height+"px";
			}
		}
	
	// if there is a rounding error in the line height then adjust the LINE_HEIGHT_MOD

	while ((st_getHeight("at0")/line_height) - Math.round(st_getHeight("at0")/line_height) != 0)
		{
		loop_counter++;
		if (loop_counter > 10) 
			{
			//alert("loop_error");
			break;
			}
	
		LINE_HEIGHT_MOD = LINE_HEIGHT_MOD+.1;
		if (LINE_HEIGHT_MOD > MAX_LINE_HEIGHT) LINE_HEIGHT_MOD = ORIGINAL_LINE_HEIGHT_MOD;
		st_fontSetSize();
		}
		
	st_paragraphCount();		
	st_imageCount();

	st_columnSetHeight();
	}
	
function st_fontLarger()
	{
	font_size = font_size+2;
	if (font_size > font_size_MAX) {font_size = font_size_MAX;}
	st_fontSetSize();
	}
	
function st_fontSmaller()
	{
	font_size = font_size-2;
	if (font_size < font_size_MIN) font_size = font_size_MIN;
	st_fontSetSize();
	}

function st_init()
	{
	
	if (document.createElement != null)
		{
		bodyNode = gId("bodyNode");
	
		if (gId(CONTENTS) != null)
			{
			//Mac IE like CONTESTS to have the stText style
			gId(CONTENTS).setAttribute("class","stText");
			gId(CONTENTS).setAttribute("className","stText");
			
			
			st_printColumnSetup();
			st_columnSetup();
	
			st_columnSetHeight(); 
			st_fontSetSize(); 
			
			st_columnLayout();
			
			//modified this line on 14.12.2004 to support printing
			gId(CONTENTS).setAttribute("class","stHidden");
			
			gId(CONTENTS).setAttribute("display","none");
			
			}
		
		document.onmousemove = st_NetscapeFix;
		
		
		window.onresize = st_columnSetHeight;
		}
	try	
		{
		try {
		gID("navbar").onmouseover = showHomePage;
		gID("navbar").onmouseout = hideHomePage;
		gID("navbar").onclick = goNavLink;
		}
	catch(err){}
	
		}
	catch(error)
		{
		}
	}
	

/* netscape fix  */	
	
function st_NetscapeFix()
	{
	st_columnSetHeight();
	document.onmousemove = null;
	}

// adds a new style to hide the source text
function st_preload()
	{
	document.writeln("<style type=\"text/css\">");
	document.writeln("#"+CONTENTS+" {display:none}");
	//set images to 0 in size in the VIEWER
	document.writeln("#"+VIEWER+" img {	display:inline; 	height:0px; 	width:0px;");
	document.writeln("</style>");
	}

st_preload();

window.onload = st_init; 

