// filesystem
//  a javascript file system client manager.
// @author kcowan@cytopia.cc
// REQUIRED: cytopia.cc/gnu/utils.js
// REQUIRED: cytopia.cc/js/menulib.js
//
//*************************************************************************************************
//
//*************************************************************************************
//  LICENSE AGREEMENT
//*************************************************************************************
/*
     This API 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, as long as this header remains in tact.
*/
//  
//*************************************************************************************
//GLOBALS
//***************************************************

var IMAGE_PATH = "../../images/";

var OPEN_IMAGE = IMAGE_PATH+"openFolder.gif";
var CLOSED_IMAGE = IMAGE_PATH+"folder.gif";
var PLUS_IMAGE = IMAGE_PATH+"plus.gif";
var MINUS_IMAGE = IMAGE_PATH+"minus.gif";

var FILESYSTEM_CONTENT_LAYER = "fileSystemRoot"; // layer where the folder output is rendered
var DOCUMENT_CONTENT_LAYER = "main_content";  // layer where the document content is rendered
var FOLDER_MARQUEE_LAYER = 'current_folder'; // layer where the currently selected folder is rendered

var ROOT_ID = "_root"; // default root id
var SHARED_ID = "_sharedItems"; // folder for shared items
var DEFAULT_INCREMENT = 12; // folder depth increment
var DEFAULT_STYLE_CLASS = "tableCellWhite"; //default style class

var FOLDER_ALT = "Click on a folder to view options";


var fileSystem = null;



// OBJECTS
//***************************************************

function FileSystem(){} // represents a file system manager

function Folder(){} // represents a folder item

function Document(){} // represents a document



// GET/SET 
//****************************************************

// PUBLIC
//***************************************************
function getFileSystem(){ return fileSystem; }
function setFileSystem(f){ fileSystem = f; }

function setSelectedFolder(folderId){ 
	getFileSystem().selectedFolder = folderId; 
	getFileSystem().latestFolder = getFileSystem().getFolderById(folderId);
}
function getSelectedFolder(){
	return getFileSystem().getFolderById(getFileSystem().selectedFolder);
}

function setFilesystemMarquee(folderName){

	ele = document.getElementById(FOLDER_MARQUEE_LAYER);

	if(ele)
	ele.innerHTML = folderName;

	return;
}


function getFolderById(folderId){
	fs = getFileSystem();
	if(fs != null){
		   
	 for(gfid=0; gfid<fs.folders.length; gfid++){
		if(fs.folders[gfid].id == folderId){
			//alert("found a match: "+fs.folders[gfid].name);
			return fs.folders[gfid];
		}
	 }
	}
	return false;
}

// FOR FILESYSTEM
//**************************************

function _folderExistCheck(folderId){
    iter = this.folders.iterator();
	while(iter.hasNext()){
		if(iter.next().id == folderId){
			//alert("found a folder" + iter.next().name);
			return true;
		}
	}
	return false;
}
function _getFolderById(folderId){
    iter = this.folders.iterator();
	while(iter.hasNext()){
		if(iter.next().id == folderId){
			return iter.next();
		}
	}
	return false;
}

function _FS_hasDocuments(){
	if(this.documents.length > 0){
		return true;
	} else {
		return false;
	}
}

function _FS_hasFolders(){
	if(this.folders.length > 0){
		return true;
	} else {
		return false;
	}
}

function _setDocumentsEnabled(bool){ this.documentsAreEnabled = bool; }
function _getDocumentsEnabled(){ return this.documentsAreEnabled; }

function _setCurrentSection(sec){ this.section = sec; }
function _getCurrentSection(){ return this.section; }

// FOR FOLDER
//**************************************
function traceFolder(folder){
	  
     if(folder.parentId != ROOT_ID){
         tmp.count++;
		 fold = getFolderById(folder.parentId);
		 if(fold.parentId != ROOT_ID){
		   traceFolder(fold);
		 }
	 }
     
	 return tmp.count;
}

function traceToParentFolder(folder){
	  
   try{
     if(folder.parentId != ROOT_ID){
         tmp.count++;
		 fold = getFolderById(folder.parentId);
		 tmp.parentList.push(fold.id);
		 if(fold.parentId != ROOT_ID){
		   traceToParentFolder(fold);
		 }
	 }
   }catch(anErr){
	   return tmp.count;
   }
     
	 return tmp.count;
}


function getDepth(folder){
	
    folder.depth = 0;

	if(folder.parentId == null){
          return 0;
	} else if(folder.parentId == ROOT_ID){
       return 1;
	} else {
      	tmp.count = 1;
	   return traceFolder(folder);
	}

}
function _getSpacerImage(){
  this.depth = getDepth(this);

 //alert("depth: "+this.depth);

  var width = Math.round(this.depth * DEFAULT_INCREMENT);
  if(width == 0){
	  return "&nbsp;";
  }
 return "<img src='../../images/clear.gif' height=1 width='"+width+"' border=0>";

}

function _getTreeLineImages(){
	this.depth = getDepth(this);
	var count = this.depth;
	if(count == 0){ count = 1; }

   prepend = "<img src='"+IMAGE_PATH;
   postpend = "' border=0 align=\"texttop\" >";
   tbuf = new StringBuffer();
    if(this.isLast){
		theImage = I_IMG;
	} else {
		theImage = I_IMG;
	}
   for(tc=0; tc<count; tc++){
	  if(tc == 0 || tc == 1){
		  tbuf.append("<img src='"+IMAGE_PATH+CLEAR_GIF+"' align=\"texttop\" height='"+ICON_HEIGHT+"' width='"+ICON_WIDTH+"' border=0>");
	  } else {
         tbuf.append(prepend+theImage+postpend);
	  }
   }
   return tbuf.toString();
}

function _getDocumentContent(){
     cbuffer = new StringBuffer();

	 return cbuffer.toString();

}
function _getFolderContent(){

     cbuffer = new StringBuffer();
	 cbuffer.append("    <div id='parent_"+this.id+"'>");
	 cbuffer.append("<table cellpadding=0 cellspacing=0 border=0> <tr class='"+DEFAULT_STYLE_CLASS+"'>");
	 cbuffer.append("<td>");
	 cbuffer.append(this.getSpacerImage());
	 cbuffer.append("</td><td nowrap>");
	 cbuffer.append("<img id='fimg_"+this.id+"' src='"+IMAGE_PATH+PLUS_IMAGE+"' border=0 onclick='doFolderExpand(\""+this.id+"\")' class=cursorhand >&nbsp;<img onclick=\"setSelectedFolder('"+this.id+"');showMenuSection('File_System')\" src='"+IMAGE_PATH+CLOSED_IMAGE+"' id='folder_"+this.id+"' border=0 class=cursorhand alt='"+FOLDER_ALT+"' >");
	 cbuffer.append("&nbsp;<a class='"+DEFAULT_STYLE_CLASS+"' href='javascript:getFileSystem().renderDocuments(\""+this.id+"\")'>"+this.name+"</a>&nbsp;");
	 cbuffer.append("</td></tr>");
	 cbuffer.append("<tr class='"+DEFAULT_STYLE_CLASS+"'><td colspan=2 nowrap>");
	 cbuffer.append("	  <div id='child_"+this.id+"' style='visibility:hidden' ></div>");
	 cbuffer.append("</td></tr></table>");
	 cbuffer.append("</div>");
	 this.isRendered = true;


	 return cbuffer.toString();

}


// ACTION METHODS
//****************************************************
    function doHideRecursive(folder){
		//alert("[do hide recursive] folder "+folder.name+" contents: "+folder.children.toString());
		if(folder.children.length>0){
			fiter = folder.children.iterator();
			while(fiter.hasNext()){
				fold = getFolderById(fiter.next());
				//alert("folder "+fold.name+"has: "+fold.children.length+" children... has children result: "+fold.hasChildren());
				  if(fold.hasChildren()){
                      childEle = document.getElementById("child_"+fold.id);
					  if(childEle){
				       childEle.style.visibility = "hidden";
					   childEle.style.display = "none";
					  }

					  doHideRecursive(fold);
				  }
				
			}
			
		}
	}

		function doHideChildren(folder){
			//alert("[doHideChildren: "+folder.name+" has: "+folder.children.length+" children");
			fs = getFileSystem();
		if(folder.hasChildren()){
			  for(dhc=0; dhc<folder.children.length; dhc++){
				fold = fs.getFolderById(folder.children[dhc]);
				childEle = document.getElementById("child_"+fold.id);
				if(!fold.hasChildren() && fold.isExpaned){
                  
				  childEle.style.visibility = "hidden";
				  childEle.style.display = "none";
				}else if(fold.hasChildren() && fold.isExpanded){
					//alert(fold.name+" has children and is expanded");
					childEle.style.visibility = "hidden";
					childEle.style.display = "none";
					doHideRecursive(fold);

				}
				//alert("folder: "+folder.name+" visible");

			  } // end for
			
		} // end if
	}
	function doShowRecursive(folder){
		if(folder.hasChildren() && folder.isExpanded){
			fiter = folder.children.iterator();
			while(fiter.hasNext()){
				fold = getFolderById(fiter.next());
				childEle = document.getElementById("child_"+fold.id);
				if(fold.hasChildren() && fold.isExpanded){
					//alert(fold.name+" [recursive] has children and is expanded");
                    
					childEle.style.visibility = "visible";
					childEle.style.display = "block";
					doShowRecursive(fold);
				} else if(fold.isExpanded){
                   
					childEle.style.visibility = "visible";
					childEle.style.display = "block";
				}
				
			}
			
		}
	}

		function doShowChildren(folder){
			fs = getFileSystem();
		if(folder.hasChildren()){
				for(dsc=0; dsc<folder.children.length; dsc++){
				fold = fs.getFolderById(folder.children[dsc]);
				childEle = document.getElementById("child_"+fold.id);
				if(fold.isExpaned){
                  
				  childEle.style.visibility = "visible";
				  childEle.style.display = "block";
				}
				if(fold.hasChildren() && fold.isExpanded){
					//alert(fold.name+" has children and is expanded");
					childEle.style.visibility = "visible";
					childEle.style.display = "block";
					doShowRecursive(fold);

				} // end if
				//alert("folder: "+folder.name+" visible");
			} // for
			
		}// end if has children
	}

    function loadDocuments(folderId){
	  try{
		buffer = new StringBuffer();
		iter = getFileSystem().documents.iterator();
		while(iter.hasNext()){
			if(iter.next().parentId == ""){
				iter.next().parentId = ROOT_ID;
			}
			if(iter.next().parentId == folderId){
				buffer.append(iter.next().getContent());
			}
		}

		ele = document.getElementById(DOCUMENT_CONTENT_LAYER);
		if(ele){ ele.innerHTML = buffer.toString(); }
	  }catch(anErr){
		  alert("an error occured loading documents: "+anErr.message);
		  return false;
	  }

		return true;
	}

	function doFolderExpand(id, loadDocs){
            tmp.currentFolderId = id;
			if(!loadDocs){
				loadDocs = true; // load by default
			}

			childEle = document.getElementById("child_"+id);
			parentEle = document.getElementById("parent_"+id);
			folderIcon = document.getElementById("folder_"+id);
			folderToggleImage = document.getElementById("fimg_"+id);
			fs = getFileSystem();

			folder = getFolderById(id);
			tmp.currentFolder = folder;
			setFilesystemMarquee(folder.name);
			//alert(childEle.style.visibility);
                
			if(childEle.style.visibility == "hidden"){
			   childEle.style.visibility = "visible";
			   childEle.style.display = "block";
			   folderIcon.src = OPEN_IMAGE;
			   folder.isExpanded = true;
			   folderToggleImage.src = MINUS_IMAGE;
			     // if(folder.hasChildren() && !folder.childrenRendered){
				   if(folder.hasChildren()){
					  folder.load();
				  } else if(folder.hasChildren()){
				     doShowChildren(folder);
				  }
                 if(loadDocs){
				  fs.renderDocuments(id);
				 }
			   } else if(childEle.style.visibility == "visible") {

                 
			     childEle.style.visibility = "hidden";
				 childEle.style.display = "none";
			     folder.isExpanded = false;
			     folderIcon.src = CLOSED_IMAGE;
			     folderToggleImage.src = PLUS_IMAGE;
				 
				  doHideChildren(folder);
				  
			   } // end else if

			  // alert(childEle.style.visibility);
	}


function _loadFolder(){

       childEle = document.getElementById("child_"+this.id);

       buffer = new StringBuffer();
	   citer = this.children.iterator();
	   //alert(this.children.length);
	   if(this.children.length > 0){
		   buffer.append("<table cellpadding=0 cellspacing=0 border=0>");
	   }
	   while(citer.hasNext()){
		  // alert("get folder by id: "+citer.next());
		  child = getFolderById(citer.next());
		  if(child.section == "All" || child.section == getFileSystem().getCurrentSection()){
           buffer.append("<tr><td class='"+DEFAULT_STYLE_CLASS+"' nowrap>");
		   buffer.append(child.getContent());
		   buffer.append("</td></tr>");
		  }
	   }
	    if(this.children.length > 0){
		   buffer.append("</table>");
	   }
	   this.childrenRendered = true;
	   //alert("loaded folder: "+this.name+" \r output: "+buffer.toString());
	   childEle.innerHTML = buffer.toString();
	   return true;
}

// RENDERING METHODS
//*******************************************************

// SECTION HEADER
//-----------------------------------------------------
function renderFileSystemHeader(){
     sectionBuffer = new StringBuffer();
	 sectionBuffer.append("");

	 sectionBuffer.append("<table width=\"100%\" border=0 cellspacing=0 cellpadding=0 >");
     sectionBuffer.append("<tr class=\"fileSystem\">");
     sectionBuffer.append("  <td nowrap>&nbsp;File System&nbsp;</td>");
	// sectionBuffer.append("  <td align=right nowrap>"+renderActionMapping(getActionMappingArray(section))+"&nbsp;&nbsp;</td>");
     sectionBuffer.append(" </tr>");
	 sectionBuffer.append("<tr class=fileSystem> ");
	 sectionBuffer.append("  <td align=left nowrap>");
	 sectionBuffer.append("        Viewing:&nbsp; <div id='current_folder'> </div>");
	 sectionBuffer.append("</td>");
     sectionBuffer.append(" </tr>");
     sectionBuffer.append(" </table> ");

	 return sectionBuffer.toString();

}

   // renderDocuments
   // retuns: void
   //----------------------------------------------------------
    function _renderDocuments(folderId){
        docBuffer = new StringBuffer();
        if(!getFileSystem().getDocumentsEnabled()){ // if documents not enabled, just set folder as selected.
			setSelectedFolder(folderId);
			folder = getFolderById(folderId);
			tmp.currentFolder = folder;
			tmp.currentFolderId = folderId;
			return; 
			}

		if(getFileSystem().documentsAreRemote){
			loadDocumentsRemote(folderId); // this method should be in the client library that manages remot document loading.
		} else {
			if(getFileSystem().hasDocuments()){
			  loadDocuments(folderId);
			}
		}
	}

// render
// returns: String / void: Sets Layer content
//------------------------------------------------------------------
function _render(){
	    buffer = new StringBuffer();
        buffer.append("<!-- filesystem -->");

	try{

	 //buffer.append("<table width=\"100%\" border=0 cellspacing=0 cellpadding=0 ><tr class=\"sectionHeader\"><td>File System</td></tr></table><br>");
	 buffer.append(renderFileSystemHeader());
      iter = this.folders.iterator();
	  //buffer.append();
	  while(iter.hasNext()){
          if(iter.next().id == ROOT_ID){
			  //alert("folder section: "+iter.next().section);
			  if(iter.next().section == "All" || iter.next().section == this.getCurrentSection()){
				  //alert("folder: "+ iter.next().name + " section: "+iter.next().section);
                 buffer.append(iter.next().getContent());
			  }
		  }
		  
	  }

     //alert("filesystem out: "+buffer.toString());

     outEle = document.getElementById(FILESYSTEM_CONTENT_LAYER);
	 outEle.innerHTML = buffer.toString();
	} catch(anErr){
        alert("an error occured while rendering: "+anErr.message);
	}

	 return buffer.toString();

}

function _showAll(){
	    buffer = new StringBuffer();
        buffer.append("<!-- filesystem -->");
		tmp.parentList = new Array();
		if(this.latestFolder != null){
		   traceToParentFolder(this.latestFolder);
		}
		//alert("latest folder: "+this.latestFolder.name);

	try{
		
		  doFolderExpand(ROOT_NODE_ID);
          tmp.parentList = tmp.parentList.reverse();
		for(sa=0; sa<tmp.parentList.length; sa++){
			//alert("showing: i-1="+sa+" "+tmp.parentList[sa]);
            doFolderExpand(tmp.parentList[sa], false);
		  
	     }

	  } catch(anErr){
        //alert("an error occured while showing all: "+anErr.message);
	  }

	 return buffer.toString();

}


// ADDITION/ASSOCIATION METHODS
//******************************************************

function _folderHasChildren(){
	 //alert("children: "+this.children.length);
	 if(this.children.length > 0){
		 return true;
	 } else {
		 return false;
	 }
}


function _associate(folder){
	
	iter = this.folders.iterator();
	isSuccess = false;
	while(iter.hasNext()){
		//alert("check for association: "+iter.next().id+" folder parent: "+folder.parentId);
		if(iter.next().id == folder.parentId){
			//alert("associate: "+folder.name+" to parent: "+iter.next().name);
			iter.next().children.push(folder.id);
			isSuccess = true;
		
		}
	}
	if(folder.id == ROOT_ID){ isSuccess = true; }

   return isSuccess;
}
function _addFolder(userId, folderId, parentId, name, isExpanded, section){

		folder = new Folder();
		folder.children = new Array();
		folder.id = folderId;
		folder.userId = userId;
		folder.name = name;
		folder.isExpanded = isExpanded;
		folder.parentId = parentId;
		folder.childrenRendered = false;
		folder.isRendered = false;
		folder.section = section;

		hasParent = this.associate(folder);
		if(hasParent){
			this.folders.push(folder);
		}
	return hasParent;
}

function _addDocument(userId, docId, parentId, name){
	doc = new Document();
	doc.userId = userId;
	doc.id = docId;
	doc.parentId = parentId;
	doc.name = name;
	this.documents.push(doc);


}



// INI METHODS
//******************************************************
function _iniFileSystem(useRemoteDocuments){

		this.folders = new Array();
		this.documents = new Array();
		this.selectedFolder = "_root";
		if(!useRemoteDocuments){
			useRemoteDocuments = false; // by default, the filesystem assumes use of the documents array
		}
		this.documentsAreRemote = useRemoteDocuments;
		this.documentsAreEnabled = true;// documents are enabled by default
		this.section = "All";
		this.latestFolder = null;
		setFileSystem(this);

}



// PROTOTYPE DEFINTIONS
//******************************************************

FileSystem.prototype.ini = _iniFileSystem;
FileSystem.prototype.render = _render;
FileSystem.prototype.showAll = _showAll;
FileSystem.prototype.addFolder = _addFolder;
FileSystem.prototype.addDocument= _addDocument;
FileSystem.prototype.associate = _associate;
FileSystem.prototype.getFolderById = _getFolderById;
FileSystem.prototype.renderDocuments = _renderDocuments;
FileSystem.prototype.hasDocuments = _FS_hasDocuments;
FileSystem.prototype.hasFolders   = _FS_hasFolders;
FileSystem.prototype.setDocumentsEnabled = _setDocumentsEnabled;
FileSystem.prototype.getDocumentsEnabled = _getDocumentsEnabled;
FileSystem.prototype.folderExists = _folderExistCheck;
FileSystem.prototype.setCurrentSection = _setCurrentSection;
FileSystem.prototype.getCurrentSection = _getCurrentSection;


Folder.prototype.hasChildren = _folderHasChildren;
Folder.prototype.getContent = _getFolderContent;
Folder.prototype.getSpacerImage = _getSpacerImage;
Folder.prototype.load           = _loadFolder;
Folder.prototype.getTreeLineImages = _getTreeLineImages;

Document.prototype.getContent = _getDocumentContent;



// DEBUG AND UTILITY
//********************************************************


