if( !ext_ma2ten ) var ext_ma2ten = new Object;
if( !ext_ma2ten.myBkmarks ) ext_ma2ten.myBkmarks = new Object;

Components.utils.import("resource://gre/modules/utils.js");

ext_ma2ten.myBkmarks = {
	folderSet: null,
	faviconService: null,
	chkFolders: null,
	incFolder: false,
	dispIcon: true,
	defIcon: true,
	openFolder: false,
	targetBlank: false,
	livemarks: false,

	makeTable: function(doc) {
			this.faviconService = Components.classes["@mozilla.org/browser/favicon-service;1"].getService(Components.interfaces.nsIFaviconService);

			this.folderSet = new Array(3);
			this.openFolder = nsPreferences.getBoolPref("extensions.mybookmarks.openfolder", false);
			this.targetBlank = nsPreferences.getBoolPref("extensions.mybookmarks.target_blank", false);
			this.dispIcon = nsPreferences.getBoolPref("extensions.mybookmarks.dispicon", true);
			this.defIcon = nsPreferences.getBoolPref("extensions.mybookmarks.deficon", false);
			this.incFolder = nsPreferences.getBoolPref("extensions.mybookmarks.incfolder", false);
			var ids = nsPreferences.copyUnicharPref("extensions.mybookmarks.checkedfolders", "");
			this.chkFolders = eval("["+ids+"]");
			this.livemarks = nsPreferences.getBoolPref("extensions.mybookmarks.livemarks", false);

//			this.digFolder(doc, PlacesUtils.bookmarksMenuFolderId, "");
			this.makeList(doc);

			var ncol = nsPreferences.getIntPref("extensions.mybookmarks.ncolunm", "3");
			var nlimit = nsPreferences.copyUnicharPref("extensions.mybookmarks.nlimit", "");
			if( nlimit == "" ) nlimit = 0;

			var i;
			var tr = doc.getElementsByTagName("tr")[0];
			var s = "\n<td class='column' id='c_0'></td>\n";
			for(i=1; i < ncol ;i++)
				s += "<td class='column' id='c_"+i+"'></td>\n";
			tr.innerHTML = s;
			var td = doc.getElementsByTagName("td");
			var h = new Array(ncol);
			var w = Math.floor(100/ncol);
			for(i=0; i < ncol ;i++) {
				td[i].setAttribute("width", w+"%");
				h[i] = 0;
			}

			var tmp=null, tmpLI=null;
			var limit = false;
			if( nlimit != "" ) {
				if( isNaN(Number(nlimit)) ) {
					tmp = document.createElement("table");
					tmp.innerHTML = "<tr><td width='"+w+"%'><div class='folder'><ul><li></li></ul></div></td></tr>";
					tmp.style.visibility = "hidden";
					var tr1 = tmp.firstChild.firstChild;
					var td1 = tr1.firstChild;
					document.body.appendChild(tmp);
					tmpLI = td1.firstChild.firstChild.firstChild;
				}
				else {
					nlimit = parseInt(nlimit);
					if( isNaN(nlimit) || nlimit <= 0 ) nlimit = "";
				}
			}

			for(i=0; i < 3 ;i++) {
				while( this.folderSet[i] && this.folderSet[i].length > 0 ) {
					var item = this.folderSet[i].shift();
					var hmin = h[0];
					var m = 0;
					for(var k=1; k < ncol ;k++) {
						if( h[k] < hmin ) {
							hmin = h[k];
							m = k;
						}
					}
					td[m].appendChild( item );
					if( nlimit != "" )
						this.widthLimit(item, nlimit, tmpLI);
					var cs = window.getComputedStyle(item, null);
					var gap = parseInt(cs.marginTop);
					h[m] = item.offsetTop + item.offsetHeight + gap;
				}
				this.folderSet[i] = null;
			}
			this.folderSet = null;
			this.chkFolders = null;
			if( tmp ) {
				document.body.removeChild(tmp);
				tmp = null;
			}
		},

	makeList: function(doc) {
		const defval = "'menu:true','toolbar:false','unfiled:false'";
		var pref = nsPreferences.copyUnicharPref("extensions.mybookmarks.targetlist", "");
		if( pref == "" )
			pref = "["+defval+"]";
		else
			pref = "[" + pref + "," + defval + "]";
		var targets = eval(pref);
		var exist = 0;
		for(var i=0; i < targets.length ;i++) {
			var elm = targets[i].split(":");
			if( elm[1] != "true" )
				continue;

			var id, title;
			switch(elm[0]) {
			case "menu":
				if( (exist & 1) ) continue;
				id = PlacesUtils.bookmarksMenuFolderId;
				title = "";//PlacesUtils.bookmarks.getItemTitle(id);
				exist |= 1;
				break;
			case "toolbar":
				if( (exist & 2) ) continue;
				id = PlacesUtils.toolbarFolderId;
				title = PlacesUtils.bookmarks.getItemTitle(id);
				exist |= 2;
				break;
			case "unfiled":
				if( (exist & 4) ) continue;
				id = PlacesUtils.unfiledBookmarksFolderId;
				title = PlacesUtils.bookmarks.getItemTitle(id);
				exist |= 4;
				break;
			default:
				continue;
			}
			this.folderSet[i] = new Array();
			this.digFolder(doc, this.folderSet[i], id, title);
		}
	},

	widthLimit: function(folder, nlimit, tmp) {
			var links = folder.getElementsByTagName("a");
			if( tmp ) {
				for(var i=0; i < links.length; i++) {
					tmp.innerHTML = "";
					tmp.appendChild( links[i].cloneNode(true) );
					tmp.style.width = "";
					var h1 = tmp.offsetHeight;
					tmp.style.width = nlimit;
					tmp.firstChild.style.display = "inline";
					var txt = tmp.firstChild.lastChild;
					var s = txt.nodeValue;
					var len = s.length;
					while(1) {
						var h = tmp.offsetHeight;
						if( h <= h1 ) break;
						len--;
						var ss = s.substr(0, len);
						ss = ss.replace(/\s+$/, "");
						len = ss.length;
						txt.nodeValue = ss + "...";
					}
					if( len < s.length ) {
						links[i].lastChild.nodeValue = txt.nodeValue;
						links[i].setAttribute("title", s);
					}
				}
			}
			else {
				for(var i=0; i < links.length; i++) {
					var s = links[i].lastChild.nodeValue;
					var len = 0;
					for(var j=0; j < s.length; j++) {
						len++;
						if( s.charCodeAt(j) > 255 ) len++;
						if( len > nlimit ) break;
					}
					if( len > nlimit ) {
						var ss = s.substr(0, j);
						ss = ss.replace(/\s+$/, "");
						links[i].lastChild.nodeValue = ss + "...";
						links[i].setAttribute("title", s);
					}
				}
			}
		},

//	getItemDescription: function(id) {
//			const DESCRIPTION_ANNO = "bookmarkProperties/description";
//			if( this.ANNO.itemHasAnnotation(id, DESCRIPTION_ANNO) ) {
//				return this.ANNO.getItemAnnotation(id, DESCRIPTION_ANNO);
//			}
//			return "";
//		},

	digFolder: function(doc, folderSet, folderId, title) {
			var flag = !this.incFolder;
			var i, id;
			for each (id in this.chkFolders) {
				if( id == folderId ) {
					flag = this.incFolder;
					break;
				}
			}
			var parentNode = PlacesUtils.getFolderContents(folderId).root;
			if( flag ) {
				var nodeTop = doc.createElement("div");
				nodeTop.setAttribute("class", "folder");
				nodeTop.setAttribute("id", "f_"+folderId);

				var nodeH = doc.createElement("h2");
				var txt = title;
				if( title == "" )
					txt = parentNode.title;
				txt = txt.replace('&', '&amp;', 'g');
				txt = txt.replace('<', '&lt;', 'g');
				txt = txt.replace('>', '&gt;', 'g');
				if( this.openFolder )
					nodeH.innerHTML = '<a href="#" onclick="openFolder('+"'folder_"+folderId+"');return false;\">"+txt+'</a>';
				else
					nodeH.innerHTML = txt;
				nodeTop.appendChild(nodeH);
				var br = doc.createTextNode("\n");
				nodeTop.appendChild(br);
				var nodeUL = doc.createElement("ul");
				nodeUL.setAttribute("id", "folder_"+folderId);

				for(i=0; i < parentNode.childCount; i++) {
					var childNode = parentNode.getChild(i);
					if (PlacesUtils.nodeIsBookmark(childNode)) {
						var id = childNode.itemId;
						var uri = childNode.uri;

						var item = doc.createElement("li");
						item.setAttribute("id", "a_"+id);
						var img = "";
						if( this.dispIcon ) {
							var dataSrc = "";
						  try {
						//	var favicon = faviconService.getFaviconImageForPage(uri);
							var favicon = this.faviconService.getFaviconForPage(PlacesUtils._uri(uri));
						//	if( this.defIcon || !/chrome:.+\/defaultFavicon.png/.test(favicon.spec) ) {
								var mimeType = {}
								var iconData = this.faviconService.getFaviconData(favicon, mimeType, {});
								dataSrc = "data:" + mimeType.value + ";base64," + btoa(String.fromCharCode.apply(null, iconData));
						//	}
						  } catch(e) {
							if( this.defIcon )
								dataSrc = "' name='defIcon'";
						  }
							if( dataSrc != "" )
								img = "<img class='favicon' src='" + dataSrc + "'>";
						}
						if( uri.match(/[^\\]"/) ) {
							uri = uri.replace(/"/g, "%22");
							uri = uri.replace(/'/g, "%27");
						}
						var s = childNode.title;
						s = s.replace('&', '&amp;', 'g');
						s = s.replace('<', '&lt;', 'g');
						s = s.replace('>', '&gt;', 'g');
						if( img == "" ) {
							item.setAttribute("class", "defnode");
						}
						else {
							item.setAttribute("class", "favnode");
						}
						item.innerHTML = '<a href="' + uri + '">' + img + s + "</a>";
						if( this.targetBlank )
							item.firstChild.setAttribute("target", "_blank");
						nodeUL.appendChild(item);
						nodeUL.appendChild(br);
					}
				}
				if( nodeUL.childNodes.length > 0 ) {
					nodeTop.appendChild(nodeUL);
					nodeTop.appendChild(br);
					folderSet.push(nodeTop);
				}
			}

			for(i=0; i < parentNode.childCount; i++) {
				var childNode = parentNode.getChild(i);
				if (PlacesUtils.nodeIsFolder(childNode)
					&& (this.livemarks || !PlacesUtils.nodeIsLivemarkContainer(childNode)) ) {
					var id = childNode.itemId;
					var uri = childNode.uri;
					if( title == "" )
						this.digFolder(doc, folderSet, id, childNode.title);
					else
						this.digFolder(doc, folderSet, id, title + " > " + childNode.title);
				}
			}
		},
//}
	aboutMyBookmarks: function () {
		var num = gBrowser.browsers.length;
		const aboutURI = "about:mybookmarks";
		var find = -1;
		for (var i=0; i < num; i++) {
			var tab = gBrowser.getBrowserAtIndex(i);
			if( tab.currentURI.spec == aboutURI ) {
				find = i;
				break;
			}
		}
		if( find < 0 || find == num )
			gBrowser.selectedTab = gBrowser.addTab(aboutURI);
		else {
			gBrowser.selectedTab = gBrowser.tabContainer.getItemAtIndex(find);
			gBrowser.reload();
		}
	},

	startup: function (){
		this.openMyBookmarks(document);
	},

	logA: function (msg) {
		dump("MyBM: "+msg + "\n");
	},

	getImageDataSrc: function (uri) {
		var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
		var channel = ioService.newChannelFromURI(ioService.newURI(uri, null, null));
		var inputStream = channel.open();
		var contentType = channel.contentType;
		var bis = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
		bis.setInputStream(inputStream);
		var data = "", bufSize = 0;
		while ( (bufSize = bis.available()) ) {
			data += bis.readBytes(bufSize);
		}
		bis.close();
		return data ? "data:" + contentType + ";base64," + btoa(data) : "";
	},

	openMyBookmarks: function (doc){
	  try {
		var sortable = nsPreferences.getBoolPref("extensions.mybookmarks.sortable", false);
		var style = nsPreferences.copyUnicharPref("extensions.mybookmarks.style", "");
		if( style == "" )
			style = nsPreferences.copyUnicharPref("extensions.mybookmarks.default_style", "");
		if( sortable ) {
			style += <style>
<![CDATA[
.ui-sortable-placeholder { border: 1px dotted black; visibility: visible !important; height: 50px !important; }
.ui-sortable-placeholder * { visibility: hidden; }
]]></style>;
		}
		doc.getElementsByTagName("style")[0].innerHTML = "\n"+style;

		var iconData = this.getImageDataSrc("chrome://mozapps/skin/places/defaultFavicon.png");

		this.makeTable(doc);

		// jquery-ui sortable interface
		if( sortable ) {
//		$(function() {
			var data = nsPreferences.copyUnicharPref("extensions.mybookmarks.layout", "");
			if( data && data != "" ) {
				var order = data.split(",");
				for(var i=0; i < order.length ;i++) {
					var folders = order[i].split("#");
					$("#"+folders[0]).append( $("#"+folders[1]) );
				}
			}

			$(".column").sortable({
				connectWith: ['.column']
				,distance: 8
				,handle: 'h2'
				,stop: function(){
					var data=[];
					$(".folder").each(function(i,v){
						data.push($(v).parent()[0].id+"#"+v.id);
					});
					nsPreferences.setUnicharPref("extensions.mybookmarks.layout", data.toString());
				}
			});
//	});
			$(".folder").addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all");
		}

		// export HTML file
		var aPath = nsPreferences.copyUnicharPref("extensions.mybookmarks.exportpath", "");
		if( aPath != "" ) {
			// new document for output
			var dtd = doc.implementation.createDocumentType("HTML", doc.doctype.publicId, doc.doctype.systemId);
			var saveDoc = doc.implementation.createDocument("http://www.w3.org/TR/1999","html",dtd);
			// clone Header tag
			var head = saveDoc.importNode( doc.getElementsByTagName("head")[0], true);
			// append favicon
			var favicon = head.getElementsByTagName("link")[0];
			favicon.setAttribute("href", this.getImageDataSrc("chrome://mybookmarks/skin/favicon.png"));
			// replace javascript
			doc.body.removeChild( doc.body.getElementsByTagName("script")[0] );
			var scripts = head.getElementsByTagName("script");
			for(var i=scripts.length-1; i >= 0 ;i--) {
				head.removeChild(scripts[i]);
			}
			var script = doc.createElement("script");
			script.setAttribute("type", "text/javascript");
			var code = <script>
<![CDATA[
	var defIcon;

	function init()
	{
		defIcon = new Image();
		defIcon.src = "<!defIcon!>";
		var elms = document.getElementsByName("defIcon");
		for(var i=0; i < elms.length; i++)
			elms[i].src = defIcon.src;
	}

	function openFolder(id)
	{
		var folder = document.getElementById(id);
		var links = folder.getElementsByTagName("a");
		for(var i=0; i < links.length ;i++) {
			window.open(links[i], links[i].innerHTML);
		}
	}
]]></script>;
			script.innerHTML = String(code).replace("<!defIcon!>", iconData);
			head.appendChild(script);
			var br = doc.createTextNode("\n");
			head.appendChild(br);
			var html = saveDoc.childNodes[1];
			html.appendChild(head);
			html.appendChild(br);
			// clone Body tag
			var abody = saveDoc.importNode(doc.body, true);
			abody.setAttribute("onload", "init()");
			var body_style = abody.getAttributeNode("style");
			if( body_style )
				abody.removeAttributeNode(body_style);
			html.appendChild(abody);

			var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
			file.initWithPath(aPath);
			var wbp = Components.classes['@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
			  .createInstance(Components.interfaces.nsIWebBrowserPersist);
			wbp.saveDocument(saveDoc, file, null, "text/html; charset=UTF-8", wbp.ENCODE_FLAGS_RAW, null);
		}

		var elms = doc.getElementsByName("defIcon");
		if( elms.length > 0 ) {
			var defIcon = new Image();
			defIcon.src = iconData;
			for each (var item in elms) {
				item.src = defIcon.src;
			}
	}
	  }
	  catch(ex) {
		dump(ex);
	  }
	}
}
