
function write(msg)
{
    return;
    if($("outputdiv") != null)
        $("outputdiv").innerHTML += msg + "<br>";
}


/**
Das Objekt das alle Screens enthält. 
**/

function Text(divid)
{
    this.screens = new Array();         // liste mit allen screens
    this.sourceContainer = $(divid);    // der div der den ursprungstext enthält
    this.copy = "";			// eine kopie des ursprungstextes
    this.text = "";
    
    // lade den ursprungstext und teile ihn auf
    this.load = function()
    {
           
        // if no source is set but only the text, denn create own source with the text
        if(this.sourceContainer == null && this.text != null && this.text.length > 0)
        {
         	this.sourceContainer = document.createElement("div");
         	this.sourceContainer.style.visibility = "hidden";
         	this.sourceContainer.style.position = "absolute";
         	this.sourceContainer.innerHTML = this.text;
         	
         	//document.appendChild(this.sourceContainer); // proplem in moz
        }
        
        // wenn quelle vorhanden
        if(this.sourceContainer != null)
        {
            this.copy = this.sourceContainer.innerHTML;
        	 
            // foreach screen	
            for(var i=0;i<this.screens.length;i++)
            { 
            	// apply source
                this.screens[i].sourceContainer = this.sourceContainer;
                // load text into screen
                this.screens[i].load();
               
                // falls nicht der ganze text hineingepasst hat, füge den rest zum nächstfolgenden screen
                if(this.screens[i].restHTML != null && i<this.screens.length-1)
                     this.screens[i+1].prevHTML = this.screens[i].restHTML;
                  
                // wenn am schluss immer noch text vorhanden ist... 
                if(this.screens[i].restHTML != null && i==this.screens.length-1){
                     // füge diesen in der letzen spalte der letzen area hinzu    
                     var lastarea =  this.screens[i].areas[this.screens[i].areas.length-1];
                     var h = lastarea.columnContainer.offsetHeight;
                  
                     lastarea.columns[lastarea.columns.length-1].innerHTML += this.screens[i].restHTML;    
                     //alert(lastarea.columns[lastarea.columns.length-1].innerHTML);  
                 }
		
            }
        }  
        
        this.showScreen(0);
    }  
    
    /* lösche alle texte */
    this.clear = function()
    {
        for(var i=0;i<this.screens.length;i++)
        { 
          for(var j=0;j<this.screens[i].areas.length;j++)
          { 
               this.screens[i].areas[j].clear();
          }
        }
        
        if(this.sourceContainer != null && this.copy != null)
        	this.sourceContainer.innerHTML = this.copy;
        	
       	this.sourceContainer = null;
    }  
    
    
    this.showScreen = function(index)
    { 
    
         for(var i=0;i<this.screens.length;i++)
            if(this.screens[i].container != null)
                this.screens[i].container.style.display = "none";
         
         if(this.screens[index].container != null)
            this.screens[index].container.style.display = "block";
    }
}

/**
Das Screen-Objekt, das mehrere Areas enthält. 
**/
function Screen(divid)
{
    this.sourceContainer = null;    // der div der den ursprungstext enthält
    this.container = $(divid);      // der div der den screen darstellt
    this.areas = new Array();       // alle areas dieses screens
    this.width = 0;                 // breite des screens
    this.height = 0;                // hoehe des screens
    this.prevHTML = null;	    // der htmltext, der aufgeteilt werden muss	
    this.restHTML = null;	    // der htmltext, der noch übrigbleibt nachdem kein platz mehr vorhanden ist
    
    this.load = function()
    {
        write("Screen.load()--> start");
        
        // für jede area des screens
        for(var i=0;i<this.areas.length;i++)
        { 
            // füge quelle hinzu und fülle area mit text
            this.areas[i].sourceContainer = this.sourceContainer;
            this.areas[i].generateColumns(); 
            
            // erstes element soll nie padding oder margin haben
            if(i>0)
            {
               if(this.areas[i].columns[this.areas[i].columns.length-1] != null)
               {
                  if(this.areas[i].columns[this.areas[i].columns.length-1].firstChild != null)
                  {
                    this.areas[i].columns[this.areas[i].columns.length-1].firstChild.style.paddingTop = "0px";
                    this.areas[i].columns[this.areas[i].columns.length-1].firstChild.style.marginTop = "0px";
                  }
               }
            }
            
            // falls nicht der ganze text hineingepasst hat, füge den rest zur nächstfolgenden area
            if(this.areas[i].restHTML != null && i<this.areas.length-1)
                this.areas[i+1].prevHTML = this.areas[i].restHTML;
                
            // if last area comes, put the last rest to the restHTML of the screen
            if(i == this.areas.length-1)
                this.restHTML = this.areas[i].restHTML;
        }
       
        
      

        write("Screen.load() --> end");
    }
   
}


function Area(divid, settingsIn)
{
    this.sourceContainer = null;        // der div der den ursprungstext enthält
    this.numColumns = 0;                // anzahl der spalten in der area
    this.columnWidth = 0;               // breite der spalten
    this.width = 0;                     // breite der area
    this.height = 0;                    // hoehe der area
    this.settings = settingsIn;         // einstellungen für diese area
    this.columnContainer = $(divid);    // div der area umgibt
    this.divid = divid;                 // id dieses divs
    this.restHTML = null;               // htmlcode der übriggeblieben ist
    this.prevHTML = null;               // htmlcode von der vorhergehenden area
    this.columns = new Array();
    
    
    	//IE6 doesn't support HTMLElement prototyping. IE7 probably won't too. Let's aim for IE8! *sigh*	
	//But thank you, www.quirksmode.org!
	this.getStyle = function (element,stylePropW3,stylePropIE) {
		var y = null;
		if (element.currentStyle)
			y = element.currentStyle[stylePropIE];
		else if (window.getComputedStyle && document.defaultView.getComputedStyle(element,null)) {
			y = document.defaultView.getComputedStyle(element,null).getPropertyValue(stylePropW3);
		}
		return y;
	}
	
	
	
    this.clear = function()
    {
        if(this.columnContainer != null)
            this.columnContainer.innerHTML = "";
        this.restHTML = null;
        this.prevHTML = null;
    }
    
    
    this.generateColumns =  function()
    {
    	// hole div der die spalten enthält
        if(this.columnContainer == null)
            this.columnContainer = $(this.divid);
            
        if(this.columnContainer == null)  
            return;
            
        // initialisiere die settings
        if(this.settings == null)
            this.settings = new AreaSettings();
            
        // wenn quelle vorhanden
        if(this.sourceContainer != null)
        {
            if (this.settings.numberOfColumns!=null) {
			    //Use specified number of columns
			    this.numColumns=this.settings.numberOfColumns;
		}	else {
			    //Calculate the number of columns that can be added, based on width.
			    this.numColumns=Math.floor(this.columnContainer.offsetWidth/(this.sourceContainer.offsetWidth)); //baseColumn.getStyle('width') gives wrong value in Opera
	    }
        }
        
 /*       var clearingNode=document.createElement('span');
		clearingNode.style.display="block";
		clearingNode.style.clear="both";
		clearingNode.style.zoom="1"; //yet another work-around for a certain obsolete browser.
		this.columnContainer.appendChild(clearingNode); */
       
        
      
        
        //Calculate the available width for one column (offsetWidth-15 because of possible scrollbar)
		var availableWidth=Math.floor((this.columnContainer.offsetWidth-(this.numColumns*14))/this.numColumns);
		
		//Add new columns
		for (i=0;i<this.numColumns;i++) {
			this.columnContainer.insertBefore(this.sourceContainer.cloneNode(false),this.columnContainer.firstChild);
		}
		
		// set className of columns
		for(i=0;i<this.columnContainer.childNodes.length;i++)
		    this.columnContainer.childNodes[i].className = "columnized";
		    
		// set minimum height
	   	var minHeight = this.columnContainer.offsetHeight;
		
		
		
		// get all columns
		var columns=this.columnContainer.getElementsByTagName('div');
		
		write("Erzeugte Spalten: " + columns.length);
		write("Breite pro Spalte: = " + availableWidth + " Pixel");
		write("Mindesthöhe der Spalten: = " + minHeight + " Pixel<br>");
		
		this.columns = columns;
		
		
			
		
        	// foreach column
		for (i=0;i<columns.length;i++) 
		{
		    
			// hole spalte
			var currentColumn=columns.item(i);
			
			// setze erlaubte breite
			currentColumn.style.width=availableWidth+'px';
			
			// get the rest of the htmltext of previous area
			if(i == 0 && this.prevHTML != null)
		        	currentColumn.innerHTML = this.prevHTML;
			
			// debugging
			
			
			//Cut/paste blocks from the baseColumn to the current column, while the
			//current column has not reach the minHeight
			while (currentColumn.offsetHeight<minHeight && this.sourceContainer.hasChildNodes()) 
			{
			    write("Aktuelle Breite: " + currentColumn.offsetWidth + "px (maximal:" + availableWidth + "px)");
			    write("Aktuelle Höhe: " + currentColumn.offsetHeight + "px (maximal:" + minHeight + "px)");
			    write("Quelle hat noch " + this.sourceContainer.childNodes.length + " Kinder");
				
				if (this.sourceContainer.firstChild.nodeType==1) { //Node.ELEMENT_NODE Doesn't work in ^%@$#@$!!! IE6
					currentColumn.appendChild(this.sourceContainer.firstChild);
				} else {
					this.sourceContainer.removeChild(this.sourceContainer.firstChild);
				}
			}
					
			
			//Some elements can be split and wrapped to the next column
		
			var lastChild=currentColumn.lastChild;
			
			var nextColumn=columns.item(i+1);
			
			var a = false;
			if(nextColumn == null)
		        {
		            nextColumn = document.createElement("div");
		            document.appendChild = nextColumn;
		            a = true;
		          
		        }
			if(lastChild != null && lastChild.nodeName != null)
			    switch (lastChild.nodeName.toLowerCase()) {
				    case "p": 
					    new ParapgraphWrapper(currentColumn,lastChild,nextColumn,minHeight);
					    break;
				    case "ul":
					    break;
				    case "ol":
					    new ListWrapper(currentColumn,lastChild,nextColumn,minHeight);					
					    break;	
    						
    				
			    }
			
			//Move headings at the bottom to next column. (this implies a proper usage of headings!)
			new HeadingWrapper(currentColumn,nextColumn);

		
			if(a) 
			  this.restHTML = nextColumn.innerHTML;
			  
			
		}
		
		for(var i=0;i<this.columnContainer.childNodes.length;i++)
		{
			this.columnContainer.childNodes[i].style.visibility = "visible";
			//this.columnContainer.childNodes[i].style.position = "relative";
		}
    
    }
    
 
}


/**
 * Settings for an area. Width of Columns, Number of Columns, priorities,...
 *
 */
function AreaSettings()
{
    this.numberOfColumns = 2;
    this.columnWidth = 200;
    this.forceColumnSize = false;
    this.forceColumnNumber = true;
}

/**
 * Manche Paragraphen bzw. Elemente können zwischen zwei Spalten aufgesplittet werden,
 * wenn sie am Schluss einer Spalte sind. Diese Methode macht das mit Paragraphen.
 */
function ParapgraphWrapper(sourceColumnIn, sourceParagraphIn, destinationColumnIn, heightIn) {
	
	
	this.sourceColumn=sourceColumnIn;
	this.height=heightIn;
	
	/**
	* Recursively loops over given <source>, moving text from <source> to <dest>
	* until the column height is less or equal to the target height.
	*
	* Preconditions: <source> and <dest> are element nodes.
	*/
	this.processElement=function (source,dest) {
		var lastSourceChild;
	
		while (lastSourceChild=source.lastChild) {
		    
			if (lastSourceChild.nodeType==1) {
				//Make a shalow clone copy of this element to the destination
				//node, to preserve styles and attributes.
				var newDest=lastSourceChild.cloneNode(false);
				dest.insertBefore(newDest,dest.firstChild);	
							
				//recursively process this node.
				if (this.processElement(lastSourceChild,newDest)) {
					return true;
				}							
			} else if (lastSourceChild.nodeType==3) {
				//Wrap this text node..
				if (this.wrapTextNode(lastSourceChild,dest)) {
					//..and return when the target has been reached.
					return true;
				}
			}
			
			//This node has been cleaned out. Remove it.
			source.removeChild(lastSourceChild);
		} 
				
		return false;
	}
	
	/**
	* Cuts words at the end of <source>, until the column height
	* is less or equal to target-height.
	* Cut words are then placed into <dest>
	*
	* Preconditions: <source> is a text node. <dest> is an element node.
	*/
	this.wrapTextNode=function (source,dest) {	
		var sourceText=source.nodeValue;
		
		//Split the text at spaces.
		var sourceTextAray=sourceText.split(/\s/);
		var destTextArray=new Array();
		
		//Keep removing words form the source until the column fits.
		while (this.sourceColumn.offsetHeight>this.height && sourceTextAray.length>0) {
			destTextArray.push(sourceTextAray.pop());
			source.nodeValue=sourceTextAray.join(' ');
		}
		
		//Add spaces at the front and end, if there are spaces in the original.
		var newText=(/^\s/.test(sourceText)?' ':'') + (destTextArray.reverse().join(' ')) + (/\s$/.test(sourceText)?' ':'');
		
		//Put the text into the destination node in the next column.
		dest.insertBefore(document.createTextNode(newText),dest.firstChild);		
		
		//return true if the target has been reached.
		return this.sourceColumn.offsetHeight<=this.height;
	}

	//Duplicate the current paragraph by shallow copy
	destinationColumnIn.insertBefore(sourceParagraphIn.cloneNode(false),destinationColumnIn.firstChild);	
	
	this.processElement(sourceParagraphIn,destinationColumnIn.firstChild);
	
	//check if the origal paragraph is emtpy
	if (sourceParagraphIn.offsetHeight==0) { //Check to see if normalized text is "" would be better..
		//Yes it's empty. Remove the empty paragraph.
		this.sourceColumn.removeChild(sourceParagraphIn);		
	}
}

/**
 *
 *
 */
function ListWrapper(sourceColumnIn, sourceListIn, destinationColumnIn, heightIn) {
	//Duplicate the current paragraph by shallow copy
	var newList=sourceListIn.cloneNode(false);
	
	destinationColumnIn.insertBefore(newList,destinationColumnIn.firstChild);
		
	//Loop over all elements in this list.
	while (currentElement=sourceListIn.lastChild) {
		if (sourceColumnIn.offsetHeight<=heightIn) {
			break;
		}
		
		if (currentElement.nodeName.toLowerCase()=='li') {
			newList.insertBefore(currentElement,newList.firstChild);			
		} else {		
			//remove the last element.
			sourceListIn.removeChild(currentElement);
		}
	}
		
	//Count current number of items.
	var numItems=1;
	var elementList=sourceListIn.childNodes;
	//count remaining items.
	for (var i=0;i<elementList.length;i++) {
		if (elementList[i].nodeName.toLowerCase()=='li') {
			numItems++;
		}
	}
	
	newList.start=numItems;
	
	//check if the origal list is emtpy
	if (sourceListIn.offsetHeight==0) { //Check to see if normalized text is "" would be better..
		//Yes it's empty. Remove the empty list.
		sourceColumnIn.removeChild(sourceListIn);		
	}
}


/**
 * Header that are lonely at the end of a column (or header + img)
 * will be pushed to the next one.
 */
function HeadingWrapper(currentColumn,nextColumn) {
	//Wrap a heading, if there was one. 
	if(currentColumn.lastChild != null)
		if (/^h[1-6]$/i.test(currentColumn.lastChild.nodeName)) {			
			nextColumn.insertBefore(currentColumn.lastChild,nextColumn.firstChild);	
		} 
	
	/*else if (/^h[1-6]$/i.test(currentColumn.childNodes[currentColumn.childNodes.length-2].nodeName) && /^img$/i.test(currentColumn.lastChild.nodeName)) {
	    nextColumn.insertBefore(currentColumn.lastChild,nextColumn.firstChild);
	    nextColumn.insertBefore(currentColumn.lastChild,nextColumn.firstChild);
	}  */
}
