// cometbird tabgroup.js

var CometbirdTabGroup = 
{
	hasOpenTabNow		: false,
	currentAddTab		: null,
	nextType			: null,
	nextParent			: null,
	
	tabColorList		: ['rgb(243,243,99)', 'rgb(145,211,112)', 'rgb(200,138,189)', 'rgb(119,112,211)', 'rgb(255,30,30)'],
	selectTabColorList	: ['rgb(256,256,209)', 'rgb(220,241,209)', 'rgb(242,227,240)', 'rgb(217,215,242)', 'rgb(255,208,208)'],
	colorIndex			: 0,
	
	autoTabMove			: false,
	isSessionRestore	: false,

	isBgLoad			: true,
	
	// how to open a tab
	sourceTypes : [
	{ d: 5, 	n: "goup_up",               			t: "related" }, 
	{ d: 4, 	n: "diggerLoadURL",         			t: "related" }, 
	{ d: 3, 	n: "mlb_common_Utils_openUrlInNewTab",   t: "related" }, 
	{ d: 3, 	n: "activateLinks",         			t: "related" }, 
	{ d: 3, 	n: "gotoHistoryIndex",     			t: "related" }, 
	{ d: 3, 	n: "BrowserBack",           			t: "related" }, 
	{ d: 3, 	n: "BrowserForward",        			t: "related" },
	{ d: 3, 	n: "BrowserReloadOrDuplicate", 			t: "related" },
	{ d: 2, 	n: "BrowserSearch_search",  			t: "related" },
	{ d: 3, 	n: "handleLinkClick",       			t: "related" }, 
	{ d: 1, 	n: "webdeveloper_generateDocument", 		t: "related" }, 
	
	{ d: 5, 	n: "BM_onCommand",          			t: "newtab" }, 
	{ d: 5, 	n: "ondragdrop",            			t: "newtab" }, 
	{ d: 4, 	n: "middleMousePaste",      			t: "newtab" },
	{ d: 4, 	n: "BrowserLoadURL",        			t: "newtab" }, 
	{ d: 4, 	n: "handleCommand",         			t: "newtab" },
	{ d: 2, 	n: "BrowserOpenTab",        			t: "newtab" },
	{ d: 2, 	n: "delayedOpenTab",        			t: "newtab" },
	{ d: 2, 	n: "BrowserLoadURL",        			t: "newtab" },
	{ d: 2, 	n: "handleCommand",         			t: "newtab" },
	{ d: 3, 	n: "doSearch",              			t: "newtab" },
	{ d: 2, 	n: "doSearch",              			t: "newtab" }, 
	{ d: 1, 	n: "removeTab",            			t: "newtab" },
	
	{ d: 4, 	n: "openReleaseNotes",      			t: "unrelated" },
	
	{ d: 1, 	n: "sss_undoCloseTab",      			t: "sessionrestore", 	m: true }, 
	{ d: 1, 	n: "sss_restoreWindow",     			t: "sessionrestore", 	m: true }
    ],
	
	addMethodHook : function( hook ) 
	{
        try 
		{
            if ( hook[1] )
                eval( hook[1] + "=" + hook[0] );

            var code = eval( hook[0] + ".toString()" );
            
            for (var i = 2; i < hook.length; ) 
			{
                var newCode = code.replace(hook[i++], hook[i++]);
                if (newCode == code)
				{
                    CometBirdFile.writeLog("Method hook of \"" + hook[0] + "\" had no effect, when replacing:\n" + uneval(hook[i - 2]) + "\nwith:\n" + uneval(hook[i - 1]));
                }
                else 
				{
                    code = newCode;
                }
            }
            
            eval(hook[0] + "=" + code);
        }
        catch (ex) 
		{
			CometBirdFile.writeLog ("Method hook of \"" + hook[0] + "\" failed with exception:\n" + ex, ex);
        }
    },

	prependMethodCode : function(methodname, codestring) 
	{
        CometbirdTabGroup.addMethodHook([methodname, null, '{', '{' + codestring]);
    },

    appendMethodCode : function(methodname, codestring) 
	{
        CometbirdTabGroup.addMethodHook([methodname, null, /\}$/, codestring + '}']);
    },

    wrapMethodCode : function(methodname, startcode, endcode) 
	{
		CometbirdTabGroup.addMethodHook([methodname, null, '{', '{' + startcode, /\}$/, endcode + '}']);
    },
	
	preInit : function()
	{
	try{
		CometbirdTabGroup.sourceTypes.sort( function __compareSourceDepths(a, b) { return b.d - a.d; } );

		CometbirdTabGroup.addMethodHook([
            'gBrowser.addTab',
            null,
            't.dispatchEvent(evt);',
            'if (CometbirdTabGroup.sourceTypes.length) { \
                evt.stack = [ arguments.callee ]; \
                evt.stackDepth = 0; \
                while (evt.stackDepth < CometbirdTabGroup.sourceTypes[0].d) { \
                    var prev = evt.stack[evt.stackDepth].caller; \
                    if (prev) { \
                        evt.stack.push(prev); \
                        evt.stackDepth++; \
                    } \
                    else { \
                        break; \
                    } \
                } \
            } \
            $&'
        ]);
        
        var relatedTabSources = [
            'nsContextMenu.prototype.openLinkInTab',
            'nsContextMenu.prototype.openFrameInTab',
            'nsContextMenu.prototype.viewBGImage',
            'nsContextMenu.prototype.addDictionaries',
		//	'handleLinkClick'
        ];
		
        if ('viewMedia' in nsContextMenu.prototype) // [Fx3.5+]
            relatedTabSources.push('nsContextMenu.prototype.viewMedia');
        else // [Fx3-]
            relatedTabSources.push('nsContextMenu.prototype.viewImage');
        
        var newTabSources = [
        ];
        
        var unrelatedTabSources = [
            'BrowserSearch.loadAddEngines'
        ];
        
		var sessionrestoreTabsSources = [
			'undoCloseTab',
			'CometBirdUndoClose.undoCloseTab'
		];
		
        // Process all simple related tab sources:
        for each (var s in relatedTabSources) 
		{
			CometbirdTabGroup.wrapMethodCode(s, 'CometbirdTabGroup.addingTab("related"); try {', '} finally { CometbirdTabGroup.addingTabOver(); }');
        }
        
        // Process all simple new tab sources:
        for each (var s in newTabSources) 
		{
            CometbirdTabGroup.wrapMethodCode(s, 'CometbirdTabGroup.addingTab("newtab"); try {', '} finally { CometbirdTabGroup.addingTabOver(); }');
        }
        
        // Process all simple unrelated tab sources:
        for each (var s in unrelatedTabSources) 
		{
            CometbirdTabGroup.wrapMethodCode(s, 'CometbirdTabGroup.addingTab("unrelated"); try {', '} finally { CometbirdTabGroup.addingTabOver(); }');
        }
		
		// Process all simple sessionrestore tab sources:
        for each (var s in sessionrestoreTabsSources) 
		{
            CometbirdTabGroup.wrapMethodCode(s, 'CometbirdTabGroup.addingTab("sessionrestore"); try {', '} finally { CometbirdTabGroup.addingTabOver(); }');
        }
		
        // And a sometimes related, sometimes unrelated tab source:
        CometbirdTabGroup.wrapMethodCode(
            'nsBrowserAccess.prototype.openURI',
            'CometbirdTabGroup.addingTab(aContext == Components.interfaces.nsIBrowserDOMWindow.OPEN_EXTERNAL ? "unrelated" : "related"); try {',
            '} finally { CometbirdTabGroup.addingTabOver(); }'
        );
		
		this.setSeamonkeyContainerBg(true);

	}catch(e){CometBirdFile.writeLog(e);}
	},
	
	setSeamonkeyContainerBg:function(yes)
	{
	var clrPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch).getCharPref("extensions.clrtabs.bgpicpath");
	//var clrPrefs =	Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch).getCharPref("extensions.clrtabs.bgpicpath");
	var ss = new Array();
	var ss = document.styleSheets;
	colorfulTabs.cl("attempting function")
	for (var i=0; i < ss.length; i++)
		{
		switch (ss[i].href)
			{
			case 'chrome://clrtabs/skin/clrtabs-seamonkey.css':
				var clrSS = ss[i];
				break;
			}
		}
	try
		{
		if(yes)
			{
			//alert(clrSS.cssRules[3].selectorText)
			clrSS.cssRules[3].style.setProperty('background-image',"url("+clrPrefs+")" ,'important' ); 
			clrSS.cssRules[3].style.setProperty('background-repeat', "repeat","important");
			}
		else
			{
			clrSS.cssRules[3].style.setProperty('background-image',"url('chrome://clrtabs/skin/seamonkey-bg.png')" ,'important' );
			clrSS.cssRules[3].style.setProperty('background-repeat',"repeat-x" ,'important' );
			}
		}
	catch(e)
		{
		dump("\nctlog:\terror in function colorfulTabs.setSeamonkeyContainerBg "+e);
		}
	},
	
	addingTab : function( type ) 
	{
        try 
		{
			if ( !CometbirdTabGroup.checkTabGroupEnable() )
				return;

			CometBirdFile.writeLog ("add-tab-type: " + type);
			CometbirdTabGroup.nextType = type;
			
			CometbirdTabGroup.isSessionRestore = false;
			if ( type == "sessionrestore" )
			{
				CometbirdTabGroup.isSessionRestore = true;
				CometbirdTabGroup.nextParent = null;
				return;
			}
			
			if ( type == "unrelated" || type == "newtab" )
			{
				CometbirdTabGroup.nextParent = null;
				return;
			}

            CometbirdTabGroup.nextParent = gBrowser.selectedTab;
        }
        catch (ex) 
		{
			CometBirdFile.writeLog ("error: add-tab"+ex);
        }
    },
    
    addingTabOver : function() 
	{
	try{
		if ( !CometbirdTabGroup.checkTabGroupEnable() )
			return;
			
		CometBirdFile.writeLog("--addingTabOver--");
		if ( !CometbirdTabGroup.hasOpenTabNow )
		{
			CometbirdTabGroup.nextParent = null;
			return;
		}
		CometbirdTabGroup.hasOpenTabNow = false;
			
		if ( CometbirdTabGroup.currentAddTab == null || CometbirdTabGroup.nextParent == null )
		{
			CometbirdTabGroup.nextParent = null;
			return;
		}
			
		if ( CometbirdTabGroup.isSessionRestore )
		{
			CometbirdTabGroup.isSessionRestore = false;
			return;
		}
			
		// set parent info
		CometBirdFile.writeLog("tab-over: svae parent info!");
		var pid = CometbirdTabGroup.nextParent.getAttribute( "cometbird_tab_id" );
		var gid = CometbirdTabGroup.nextParent.getAttribute( "cometbird_tab_gid" );
		var color = CometbirdTabGroup.nextParent.getAttribute( "cometbird_tab_color" );
		
		CometbirdTabGroup.currentAddTab.setAttribute( "cometbird_tab_pid", pid );
		CometbirdTabGroup.currentAddTab.setAttribute( "cometbird_tab_gid", gid );
		CometbirdTabGroup.currentAddTab.setAttribute( "cometbird_tab_color", color );
		CometbirdTabGroup.setColor(CometbirdTabGroup.currentAddTab, color);
		
		// set color
		CometbirdTabGroup.updateTabsColor();
		
		CometbirdTabGroup.currentAddTab = null;
		CometbirdTabGroup.nextParent = null;
		CometbirdTabGroup.nextType = null;
	}catch(e){CometBirdFile.writeLog("tab-over"+e);}
	}, 
	
	checkTabGroupEnable : function()
	{
		// check if enable
		var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
        var prefs = prefService.getBranch("");
		
		if ( !prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent") )// false
		{
			return false;
		}
		
		if ( prefs.getBoolPref("browser.enhancement.tabgroup.enable") )
			return true;
		else
			return false;
	},
	
	initTabs : function()
	{
		if ( !CometbirdTabGroup.checkTabGroupEnable() )
			return;
		
		CometBirdFile.writeLog("initTabs");
		var tab_count = gBrowser.mTabContainer.itemCount;
		for ( var i=0; i<tab_count; i++ )
		{
			var tab = gBrowser.mTabs[i];

			// tab-id
			if ( tab.getAttribute("cometbird_tab_id") == "" )
			{
				var tab_id = "tab-id-" + CometBirdUtility.createGuid();
				tab.setAttribute( "cometbird_tab_id", tab_id );
			}
			
			// tab-gid
			if ( tab.getAttribute("cometbird_tab_gid") == "" )
			{
				var tab_gid = "tab-gid-" + CometBirdUtility.createGuid();
				tab.setAttribute( "cometbird_tab_gid", tab_gid );
			}
			
			// tab-color
			//if ( tab.getAttribute("cometbird_tab_color") == "" )
			//{
			//	var tab_color = "tab-color-default";
			//	tab.setAttribute( "cometbird_tab_color", tab_color );
			//}
		}
	},
	
	init : function(event)
	{
	try{
		if ( event.originalTarget != document )
			return;
		window.removeEventListener("load", CometbirdTabGroup.init, false);
		
		// init restore attributes
		var ss = window.navigator.userAgent.toLowerCase().indexOf('seamonkey')>=0?Components.classes["@mozilla.org/suite/sessionstore;1"].getService(Components.interfaces.nsISessionStore):Components.classes["@mozilla.org/browser/sessionstore;1"].getService(Components.interfaces.nsISessionStore);
		if ( ss )
		{
			ss.persistTabAttribute( "cometbird_tab_id" );
			ss.persistTabAttribute( "cometbird_tab_pid" );
			ss.persistTabAttribute( "cometbird_tab_gid" );
			ss.persistTabAttribute( "cometbird_tab_color" );
		}
		
		// init tab event
		//var container = gBrowser.tabContainer;
		window.addEventListener("TabOpen", CometbirdTabGroup.TabAdded, false);
		window.addEventListener("TabMove", CometbirdTabGroup.TabMoved, false);
		window.addEventListener("TabClose", CometbirdTabGroup.TabRemoved, false);
		window.addEventListener("TabSelect", CometbirdTabGroup.TabSelect, false);
		
		document.addEventListener( "SSTabRestoring", CometbirdTabGroup.tabGroupRestore, false );
		
		// pre-init
		CometbirdTabGroup.preInit();
	}catch(e){CometBirdFile.writeLog(e);}
	},
	
	release : function()
	{
		//var container = gBrowser.tabContainer;
		window.removeEventListener("TabSelect", CometbirdTabGroup.TabSelect, false); 
		window.removeEventListener("TabOpen", CometbirdTabGroup.TabAdded, false);
		window.removeEventListener("TabMove", CometbirdTabGroup.TabMoved, false);
		window.removeEventListener("TabClose", CometbirdTabGroup.TabRemoved, false); 
		
		document.removeEventListener( "SSTabRestoring", CometbirdTabGroup.tabGroupRestore, false );
	},
	
	TabSelect : function()
	{
		try{
			CometBirdFile.writeLog( "TabSelect" );
			
			// update color
			CometbirdTabGroup.updateTabsColor();
		}catch(e){CometBirdFile.writeLog(e);}
	},
	
	TabAdded : function( event )
	{
	try{
		CometBirdFile.writeLog( "TabOpen");
		
		if ( !CometbirdTabGroup.checkTabGroupEnable() )
			return;
			
		if ( CometbirdTabGroup.isSessionRestore )
		{
			CometBirdFile.writeLog( "open-SessionRestore now!" );
			return;
		}
		
		// init tabs
		CometbirdTabGroup.initTabs();
		
		var curTab = event.originalTarget;
		if ( !curTab )
			return;
			
		CometbirdTabGroup.currentAddTab = null;
		CometbirdTabGroup.hasOpenTabNow = false;
		if ( CometbirdTabGroup.nextType == "related" )
		{
			CometBirdFile.writeLog("tab-open-related!");
			CometbirdTabGroup.hasOpenTabNow = true;
			CometbirdTabGroup.currentAddTab = curTab;
			CometbirdTabGroup.nextType = null;
		}
	}catch(e){CometBirdFile.writeLog(e);}
	},
	
	TabMoved : function( event )
	{
		try{
			CometBirdFile.writeLog( "TabMoved" );
			
			if ( !CometbirdTabGroup.checkTabGroupEnable() )
				return;
			
			if ( CometbirdTabGroup.isSessionRestore )
			{
				CometBirdFile.writeLog( "move-SessionRestore now!" );
				return;
			}
			
			var curTab = event.target;
			if ( !curTab )
				return;

			// update move tab
			CometbirdTabGroup.updateMoveTab( curTab );
		}catch(e){CometBirdFile.writeLog(e);}
	},
	
	updateMoveTab : function( curMoveTab )
	{
	try{
		var tab_count = gBrowser.mTabContainer.itemCount;
		var current_index = 0;
		for ( var i=0; i<tab_count; i++ )
		{
			var tab = gBrowser.mTabs[i];
			if ( tab == curMoveTab )
			{
				var preTab = gBrowser.mTabs[i-1];
				if ( !preTab )// the first tab
					return;
				
				if ( preTab.getAttribute("cometbird_tab_gid") !=  curMoveTab.getAttribute("cometbird_tab_gid")
					&& preTab.getAttribute("cometbird_tab_color") == '' )// not in a group
				{
					var newTabGid = "tab-gid-" + CometBirdUtility.createGuid();
					curMoveTab.setAttribute("cometbird_tab_gid", newTabGid); 
					curMoveTab.setAttribute("cometbird_tab_color",	''); 
					CometbirdTabGroup.setColor(curMoveTab, '');
					return;
				}
				
				// has the same color as previous	
				curMoveTab.setAttribute("cometbird_tab_pid", preTab.getAttribute("cometbird_tab_pid") ); 
				curMoveTab.setAttribute("cometbird_tab_gid", preTab.getAttribute("cometbird_tab_gid") ); 
				curMoveTab.setAttribute("cometbird_tab_color", preTab.getAttribute("cometbird_tab_color") ); 
				CometbirdTabGroup.setColor(curMoveTab, preTab.getAttribute("cometbird_tab_color"));
				break;
			}
		}
		
		// set color
		CometbirdTabGroup.updateTabsColor();
	}catch(e){
		// when the move to the first positon
		CometBirdFile.writeLog(e);
		var newTabGid = "tab-gid-" + CometBirdUtility.createGuid();
		curMoveTab.setAttribute("cometbird_tab_gid", newTabGid); 
		curMoveTab.setAttribute("cometbird_tab_color", ''); 
		CometbirdTabGroup.setColor(curMoveTab, '');
		}
	},
	
	TabRemoved : function( event )
	{
	try{
		CometBirdFile.writeLog( "TabRemoved" );
		
		// update color
		CometbirdTabGroup.updateTabsColor();
	}catch(e){CometBirdFile.writeLog(e);}
	},
	
	updateTabsColor : function()
	{
	try{
		CometBirdFile.writeLog( "--updateTabsColor--" );
		if ( !CometbirdTabGroup.checkTabGroupEnable() )
			return;
			
		var tab_count = gBrowser.mTabContainer.itemCount;
		if ( tab_count == 1 )
		{
			// clear color
			if ( gBrowser.mTabs[0].getAttribute("cometbird_tab_color") != '' )
			{
				gBrowser.mTabs[0].setAttribute("cometbird_tab_color", '');
				CometbirdTabGroup.setColor(gBrowser.mTabs[0], '');
			}				
			return;
		}
		
		// seg into group
		var tabGroup = [];
		tabGroup.push( gBrowser.mTabs[0] );
		for ( var i=1; i<tab_count; i++ )
		{
			var tab = gBrowser.mTabs[i];
			if ( tab.getAttribute("cometbird_tab_gid") != "" && tab.getAttribute("cometbird_tab_gid") == gBrowser.mTabs[i-1].getAttribute("cometbird_tab_gid") )
			{
				tabGroup.push( tab );
			}
			else
			{
				// set color for pre-group first
				CometbirdTabGroup.setColorForGroup( tabGroup );
				
				// begin new group
				while ( tabGroup.length > 0 )
					tabGroup.pop();
					
				tabGroup.push( tab );
			}
		}
		
		// set color for last group
		CometbirdTabGroup.setColorForGroup( tabGroup );
	}catch(e){CometBirdFile.writeLog(e);}
	},
	
	setColor:function(tab, tabClr)
	{
		// for(var i=0; i<gBrowser.mTabs.length;++i)
		// {
			// if(tab == gBrowser.mTabs[i])
			// {
			// alert('set tab ' + i + ' color: ' + tabClr);
			// break;
			// }
		// }
		if(tabClr == '')
			tab.style.setProperty('background-image',	'','important');
		tabClr = tabClr - 0;
		if(tabClr >= 0 && tabClr < CometbirdTabGroup.tabColorList.length)
		{
			var tabcolor;
			if(gBrowser.selectedTab == tab)
				tabcolor = CometbirdTabGroup.selectTabColorList[tabClr];
			else
				tabcolor = CometbirdTabGroup.tabColorList[tabClr];
			tab.style.setProperty('background-image',	'-moz-linear-gradient(' + tabcolor + ', ' + tabcolor + ')','important');
		}
	},
	
	setColorForGroup : function( tabGroup )
	{
	try{
		if ( tabGroup.length == 1 )
		{
			// clear color
			if ( tabGroup[0].getAttribute("cometbird_tab_color") != '' )
			{
				tabGroup[0].setAttribute("cometbird_tab_color", '' );
				CometbirdTabGroup.setColor(tabGroup[0], '');
			}				
			return;
		}
			
		if ( CometbirdTabGroup.colorIndex >= CometbirdTabGroup.tabColorList.length )
			CometbirdTabGroup.colorIndex = 0;
			
		var color = "tab-color-default";
		if ( tabGroup[0].getAttribute("cometbird_tab_color") == '' )// find none color in group, and allocate it
		{
			color = CometbirdTabGroup.colorIndex;
			CometbirdTabGroup.colorIndex++;
		}
		else
		{
			color = tabGroup[0].getAttribute("cometbird_tab_color");
		}
			
		for ( var i=0; i<tabGroup.length; i++ )
		{
			tabGroup[i].setAttribute("cometbird_tab_color", color );
			CometbirdTabGroup.setColor(tabGroup[i], color);
		}
	}catch(e){CometBirdFile.writeLog(e);}
	},
	
	clearTabsColor : function()
	{
		var tab_count = gBrowser.mTabContainer.itemCount;
		for ( var i=0; i<tab_count; i++ )
		{
			gBrowser.mTabs[i].setAttribute("cometbird_tab_color", '' );
			CometbirdTabGroup.setColor(gBrowser.mTabs[i], '');
		}
	},
	
	tabGroupRestore : function( event )
	{
	try{
		CometBirdFile.writeLog( "tabGroupRestore");

		// update color
		CometbirdTabGroup.updateTabsColor();
	}catch(e){CometBirdFile.writeLog("restore: "+e);};
	}
};

window.addEventListener( "load", CometbirdTabGroup.init, false );
window.addEventListener( "unload", CometbirdTabGroup.release, false );