// ==UserScript==
// @name           Ogame's overview improver
// @namespace      ogame.fr
// @description    Modify overview appearence to make it more readable, adds to overview sum for all ressources in transit (http://ogame.spiderou.net)
// @include        http://uni*.ogame.fr/game/index.php?page=overview*
// ==/UserScript==

// TODO
// Add attacker name / icon to message

// LastMod : 2009-05-29 : new view

// Interface to des/activate new view
var new_view = GM_getValue('new_view',true) ;
if (new_view) {
	str_new = '* ' ;
	str_old = '' ;
} else {
	str_new = '' ;
	str_old = '* ' ;
}
GM_registerMenuCommand(str_old+"Normal view",function(){GM_setValue('new_view',false);});
GM_registerMenuCommand(str_new+"New view",function(){GM_setValue('new_view',true);});

// Player's planets
var planetList = xpath('//SELECT').snapshotItem(0);
var current_planet = -1 ;
var players_planets = new Array() ;
for( var i = 0 ; i < planetList.options.length ; i++ ) {// Let search which planet is selected
	var planet_cut = new Array() ;
	planet_cut = planetList.options[i].innerHTML.split('\t\t\t\t  ') ; // Cut that one
	players_planets[i] = planet(strip(planet_cut[1]),strip(planet_cut[0])) ;
	if( planetList.options[i].selected )
		current_planet = i ;// Player's current planet's index
}

// Default ressources values
var myels = xpath('//td/font') ;
var M = str2int(myels.snapshotItem(0).firstChild.nodeValue) ;
var C = str2int(myels.snapshotItem(1).firstChild.nodeValue) ;
var D = str2int(myels.snapshotItem(2).firstChild.nodeValue) ;
var final_res = new ressources(M,C,D) ; // Ressources for current planet after all fleets back
var dest_res = new ressources(0,0,0) ; // Ressources currently arriving on current planet
var total_res = new ressources(0,0,0) ; // Ressources currently on travel
// Other vars
var nbflto = 0 ;
var nbflfrom = 0 ;

//Parse spans
var i = 0 ;
var next = true ;
var firsttime = true ;
do {
	i++
	var mycell = document.getElementById('bxx'+i) ;
	if ( mycell ) {
		var current_row = mycell.parentNode.parentNode ;
		var current_fleet = new fleet(current_row.cells[1]) ;
		if (current_fleet.to) {
			total_res.add(current_fleet.ressources) // Add ressources in this fleet to total
			if ( current_fleet.to.pos == players_planets[current_planet].pos ) { // This fleet goes to current planet
				if ( current_fleet.to.type == players_planets[current_planet].type ) { // Exactly the same destination
					nbflto++ ;
					dest_res.add(current_fleet.ressources) ;
				}
			}
			if ( current_fleet.from && ( current_fleet.from.pos == players_planets[current_planet].pos ) ) { // This fleet parts from current planet
				if ( current_fleet.from.type == players_planets[current_planet].type ) // Exactly the same destination
					nbflfrom++ ;
			}
		}

		if ( new_view ) {
			if ( firsttime ) { // Transform current line to make it container of a new table, that will have new lines
				firsttime = false ;
				var newtable = document.createElement('table') ;
				newtable.width = '100%' ;
				var newrow = newtable.insertRow(0) ; // At the begining
				var timer_cell = current_row.cells[0] ;
				var container_cell = current_row.cells[1] ;
				newrow.appendChild(timer_cell) ; // Move first cell to new row
				for ( j in container_cell.childNodes )
					if ( container_cell.childNodes[j] )
						if ( container_cell.childNodes[j].nodeType == 1 )
							container_cell.removeChild(container_cell.childNodes[j]) // Remove actual content
				container_cell.colSpan = 4 ; // enlarge
				container_cell.style.padding = 0 ;
				container_cell.appendChild(newtable) ; // Add new table
			} else {
				var newrow = newtable.insertRow(-1) ; // A the end
				newrow.appendChild(current_row.cells[0]) ;
				current_row.parentNode.removeChild(current_row) ; // Removing current line
			}
			// THs
				// First is timer, done just before
				// An arrow showing direction of the mission
			var myth = appendTHCell(newrow,current_fleet) ;
			switch ( current_fleet.direction ) {
				case -1 :
					myth.innerHTML = '<-' ;
					break;
				case 0 :
					myth.innerHTML = '<->' ;
					break;
				case 1 :
					myth.innerHTML = '->' ;
					break;
			}
				// Ships of the mission
			var myth = appendTHCell(newrow,current_fleet) ;
			myth.innerHTML += current_fleet.ships_disp ;
			if ( myth.firstChild.color )
				myth.firstChild.removeAttribute('color') ;
			if ( current_fleet.from ) {
				// "from" coordinates
				var myth = appendTHCell(newrow,current_fleet) ;
				myth.appendChild(current_fleet.from.link) ;
				// Image for destination type
				var myth = appendTHCell(newrow,current_fleet) ;
				appendtypeimage(myth,current_fleet.from) ;
			} else {
				// Empty cells
				appendTHCell(newrow,current_fleet) ;
				appendTHCell(newrow,current_fleet) ;
			}
				// "to" coordinates
			var myth = appendTHCell(newrow,current_fleet) ;
			myth.appendChild(current_fleet.to.link) ;
				// Image for destination type
			var myth = appendTHCell(newrow,current_fleet) ;
			appendtypeimage(myth,current_fleet.to) ;
				// Ressources
			var myth = appendTHCell(newrow,current_fleet) ;
			myth.innerHTML = current_fleet.ressources.disp() ;
		}
	} else
		next = false ;
} while ( next )

// Display results
if ( dest_res.total() > 0 ) {
	final_res.add(dest_res) ;
	addrow('Current planet res.','To : '+dest_res.disp(),'Final : '+final_res.disp()) ;
}
if ( ( nbflto > 0 ) || ( nbflfrom > 0 ) )
	addrow('Current planet flt.','To : '+nbflto,'From : '+nbflfrom) ;
if ( total_res.total() > 0 )
	addrow('Total',total_res.disp()) ;
addrow('Transit') ; // Title for this section

/* ======================================== [ SPECIFIC FUNCTIONS ] ========== */
// Append a TH to a TR passed in parameter, applying him style of 2nd parameter
function appendTHCell(row,fleet) {
	var myth = document.createElement('TH') ;
	myth.noWrap = true ;
	myth.className = fleet.className ;
	myth.title = fleet.mission ;
	row.appendChild(myth) ;
	return myth ;
}
// Append an image to a node, image source depending on type of 2nd parameter
function appendtypeimage(appendto,planet) {
	var myimg = document.createElement('img') ;
	myimg.width = 22 ;
	myimg.title = planet.name ;
	switch ( planet.type ) {
		case 1 :
			myimg.src = 'http://ogame.spiderou.net/skin/planeten/small/s_normaltempplanet05.jpg' ;
			break ;
		case 2 :
			myimg.src = 'http://ogame.spiderou.net/skin/planeten/debris.jpg' ;
			break ;
		case 3 :
			myimg.src = 'http://ogame.spiderou.net/skin/planeten/small/s_mond.jpg' ;
			break ;
		default :
			alert('Unknown type : '+planet.type) ;
	}
	// Border depending on planet's owner
	myimg.style.border = '1px solid black' ; // By default : anyone else
	for ( var i in players_planets ) { // global var
		if ( planet.pos == players_planets[i].pos ) { // It's in player's planets list
			if ( ( i == current_planet ) && ( players_planets[i].type == planet.type ) ) { // It's current planet
				myimg.style.border = '1px solid white' ;
				break ;
			} else { // It's not current planet
				myimg.style.border = '1px solid grey' ;
				if ( planet.type == players_planets[i].type ) { // Just for it does that once
					myimg.addEventListener('click',function(evt) {
						planetList.selectedIndex = evt['target'].getAttribute('select_index') ;
						unsafeWindow.haha(planetList) ;
					},false) ;
					myimg.setAttribute('select_index',i) ; // Img is used to store index
				}
			}
		} // It's in player's planets list
	}
	appendto.appendChild(myimg) ;
	return myimg ;
}
/* =================================================== [ CLASSES ] ========== */
function planet(pos,name) {
	var regex_planet = /planète (.*)/ ;
	var regex_cdr = /Champ de débris/ ;
	var regex_lune_a = /(.*)\(Lune\)/ ;
	var regex_lune_b = /lune/ ;
	// Attributes
	var mymatch = pos.match(/^\[(\d)\:(\d{1,3})\:(\d{1,2})\]$/)
	if ( mymatch ) {
		// Position
		var a_planet = new Object ;
		a_planet.pos = pos ;
		a_planet.galaxy = mymatch[1] ;
		a_planet.system = mymatch[2] ;
		a_planet.position = mymatch[3] ;
		a_planet.link = document.createElement('A') ;
		a_planet.link.href = 'javascript:showGalaxy('+a_planet.galaxy+','+a_planet.system+','+a_planet.position+')' ;
		a_planet.link.innerHTML = a_planet.pos ;
		// Name
		a_planet.type = 1 ; // Planet by default (for "current planet", it's best choice, as moon are detected)
		a_planet.name = name ;
		name = regex_oneshot(name,/ la\s*(.*)/) ;
		if (name.match(regex_cdr)) {
			a_planet.type = 2 ;
			a_planet.name = 'champs de débrits' ;
		} else if ( name.match(regex_lune_a) ) {
			a_planet.type = 3 ;
			a_planet.name = strip(regex_oneshot(name,regex_lune_a)) ;
		} else if ( name.match(regex_lune_b) ) {
			a_planet.type = 3 ;
			a_planet.name = 'lune' ;
		} else if ( name.match(regex_planet) ) {
			a_planet.type = 1 ;
			a_planet.name = strip(regex_oneshot(name,regex_planet)) ;
		}
		return a_planet ;
	} else
		return false ;
}
function ressources(M,C,D) {
	// Attributes
	this.M = str2int(M) ;
	this.C = str2int(C) ;
	this.D = str2int(D) ;
	// Methods
	this.total = function() { // Returns sum of all ressources
		return this.M+this.C+this.D ;
	}
	this.dispone = function(disp,val,unit) {
		if ( val > 0 ) {
			if ( disp != '' )
				disp += ', ' ;
			disp += qty_format(val) + unit ;
		}
		return disp ;
	}
	this.disp = function() { // Returns a string for display
		disp = '' ;
		disp = this.dispone(disp,this.M,'M') ;
		disp = this.dispone(disp,this.C,'C') ;
		disp = this.dispone(disp,this.D,'D') ;
		if ( disp == '' )
			disp = 'n/a' ;
		return disp ;
	}
	this.add = function(added) { // Adds a 'ressources' object to current
		this.M += added.M ;
		this.C += added.C ;
		this.D += added.D ;
	}
}
function fleet(td) { // Gets a fleet-span and create a 'fleet' object
	//GM_log(debug_xml_element_new(td,'')) ;

	/* Tentative de solutionnage des attaques groupées */
	var nb_span = 0 ;
	for ( i in td.childNodes )
		if ( td.childNodes[i].nodeType == 1 )
			if ( td.childNodes[i].nodeName == "SPAN" ) {
				nb_span++ ;
/*
<th colspan="3">
	<span class="attack">
		Une de vos 
		<a href="#" onmouseover='return overlib("<font color=white><b>Grand transporteur 20<br>Vaisseau de bataille 20<br></b></font>");' onmouseout="return nd();" class="ownattack">
			flottes
		</a>
		<a href="#" title="Grand transporteur 20Vaisseau de bataille 20">
		</a>
		 venant de la  L2 2 patxy (Lune) 
		<a href="javascript:showGalaxy(2,336,6)" ownattack="">
			[2:336:6]
		</a>
		 atteint la planète ATLANTIS 
		<a href="javascript:showGalaxy(2,330,6)" ownattack="">
			[2:330:6]
		</a>
		. Elle a pour mission: Attaquer
		</span>
	<br>
	<br>
	<span class="federation">
		Une de vos 
		<a href="#" onmouseover='return overlib("<font color=white><b>Sonde espionnage 1<br></b></font>");' onmouseout="return nd();" class="ownfederation">
			flottes
		</a>
		<a href="#" title="Sonde espionnage 1">
		</a>
		venant de la  L2 2 patxy (Lune) 
		<a href="javascript:showGalaxy(2,336,6)" ownfederation="">
			[2:336:6]
		</a>
		atteint la planète ATLANTIS 
		<a href="javascript:showGalaxy(2,330,6)" ownfederation="">
			[2:330:6]
		</a>
		. Elle a pour mission: Attaque groupée
	</span>
	<br>
	<br>
</th>
*/

				var span = td.childNodes[i] ;
				var borderstyle = span.style.backgroundColor ; // Backup
				span.style.backgroundColor = 'red' ; // To see in alerts wich one is beeing analyzed
				this.className = span.className ;
				var classes = span.className.split(' ') ; // array of classes
				var childs = span.childNodes ;
				// --- [ Methods ] ---------------------------------------------------------
				this.setmission = function(newmission) { // Method for verifying there is no 2 mission definition
					/*if ( this.mission ) { // Shouldn't happen
						alert('Mission changed from '+this.mission+' to '+newmission) ;
					}*/
					this.mission = newmission ;
				}
				// --- [ Attributes ] ------------------------------------------------------
				// Get mission and direction
				if ( classes.length > 2 )
					alert('Wrong class number : '+classes.length)
				this.own = false ;
				for ( classnum in classes ) { // For all classes of current span (theorically 2 classes : 1 for mission ; 1 for direction)
					var aclass = classes[classnum] ; // Class itself
					switch(aclass) {
						// Direction cases
						case 'flight':
							this.direction = 1 ;
							break;
						case 'holding':
							this.direction = 0 ;
							break;
						case 'return':
							this.direction = -1 ;
							break;
						// Other are mission cases
						default:
							if ( aclass.indexOf('own') >= 0 ) {
								this.setmission(aclass.slice(3)) ; // Remove "own" in mission
								this.own = true ;
							} else {
								this.setmission(aclass) ;
							}
							if ( this.mission == 'missile' ) {
								//alert('blah') ;
								this.direction = 1 ; // No direction information for this mission
							}
					}
				}
				// here we should have mission and direction
				if ( ( ! this.direction ) && ( this.direction != 0)) {
					GM_log('No direction, set to flight') ;
					this.direction = 1 ;
				}
				if ( ( ! this.mission ) && ( this.mission != '' )) {
					GM_log('No mission, set to none') ;
					this.mission = '' ;
				}
				// Get ships
				if ( ! this.ships_disp )
					this.ships_disp = '' ;
				if ( ! this.ships )
					this.ships = '' ;
				var overlib = childs[1].getAttribute('onmouseover') ;
				if ( overlib != null ) { // We have a "onmouseover", it's a oonventionnal fleet, let's read it to know composition
					var overlib_a = overlib.split('("') ;
					var overlib_b = overlib_a[1] ;
					var overlib_c = overlib_b.split('")') ;
					this.ships_disp += overlib_c[0] ;
					this.ships += childs[2].title ;
				} else { // no "onmouseover", it's a missile attack, let's read the node to get missiles and primary target
					var nbmissiles = 0 ;
					var target = 'no target' ;
					var mymatch = childs[0].nodeValue.match(/\((.*)\)/) ;
					if ( mymatch ) {
						nbmissiles = parseInt(mymatch[1]) ;
						var mymatch = childs[4].nodeValue.match(/ cible primaire (.*)./) ;
						if ( mymatch ) {
							target = mymatch[1] ;
						} else
							alert('Incorrect element : '+childs[4].nodeValue) ;
					} else
						alert('Incorrect element : '+childs[0].nodeValue) ;
					var s = '' ;
					if ( nbmissiles > 1 )
						s = 's'
					this.ships += nbmissiles+' missile'+s+' -> '+target ;
					this.ships_disp += this.ships ;
				}
				// Get planets
				for ( var i = 0 ; i < ( childs.length - 1 ) ; i++) { // For each node
					if ( childs[i].firstChild && ( childs[i].firstChild.nodeType == 3 ) ) { // having a textNode as a child
						var a_planet = planet(childs[i].firstChild.nodeValue,childs[i-1].nodeValue) ; // Try to convert it into a planet
						if ( a_planet ) { // If it worked
							if ( this.to )
								this.from = this.to ;
							this.to = a_planet ; // Let's store it as source or destination, depending on case
						}
					}
				}
				// Get ressources
				var lastchild = childs[childs.length-1] ;
				if ( lastchild.title ) {
					words = lastchild.title.split(' ') ;
					this.ressources = new ressources(words[2],words[4],words[6]) ;
				} else
					this.ressources = new ressources(0,0,0) ;
			
				//alert(this.mission+' * '+this.direction+' + '+this.ressources.disp()+' - '+this.from.pos+' -> '+this.to.pos) ;
			
				span.style.backgroundColor = borderstyle ; // Restore
			}
}
/* =================================================== [ METHODS ] ========== */
/* ------------------------------------------------ [ PROCEDURES ] ---------- */
function addrow(title,txt,txt2) {
	// find main table
	var tableList = document.getElementsByTagName("TABLE") ;
	var handle = tableList[6] ;
	// add new row and cell
	if ( handle.rows[1].childNodes[1].colSpan == 1 ) // 2nd line is "Heure du serveur"
		var newRow = handle.insertRow(2) ; // Add on next line 
	else // 2nd line is probably "N nouveaux messages", 3rd will be "Heure du serveur"
		var newRow = handle.insertRow(3) ; // Add on line after next
	var newTitle = newRow.insertCell(0) ;
	newTitle.className="c" ;
	newTitle.appendChild(document.createTextNode(title)) ;
	if ( txt)
		if ( txt2 ) {
			var newCell = document.createElement('TH') ;
			newRow.appendChild(newCell) ;
			newCell.colSpan = 2 ;
			newCell.appendChild(document.createTextNode(txt)) ;
			var newCell = document.createElement('TH') ;
			newRow.appendChild(newCell) ;
			newCell.colSpan = 2 ;
			newCell.appendChild(document.createTextNode(txt2)) ;
		} else {
			var newCell = document.createElement('TH') ;
			newRow.appendChild(newCell) ;
			newCell.colSpan = 3 ;
			newCell.appendChild(document.createTextNode(txt)) ;
		}
	else // if ( txt )
		newTitle.colSpan = 4 ;
}
/* ------------------------------------------------- [ FUNCTIONS ] ---------- */
function regex_oneshot(str,regex) {
	var name_cut = regex.exec(str) ;
	if ( name_cut )
		return name_cut[1];
	else
		return str ;
}
/*                                                        [ HTML ]            */
function xpath(query) {
	return document.evaluate(query,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null) ;
}
/*                                                       [ TYPES ]            */
function str2int(str) {
	if ( str.replace ) // If param is a string
		return parseInt(str.replace(/\./g,'')) ; // Removes dots, parses as int
	else // If param isn't a string
		return str ; // Hope it's an int
}
function qty_format(value) {
	var units = new Array('','k','M','G','T') ;
	var unit = 0 ; // Unit of the value, index in previous array, by default ''
	var next = true ;
	while ( value > 1000 ) {
		value = Math.round(value/100)/10 ;
		unit++ ;
	}
	return value + ' ' + units[unit] ;
}
function strip(str) { // Removes all type of spaces from the string (space, tab, carriage return, newline ...)
	return str.replace(/\f/g,'').replace(/\n/g,'').replace(/\r/g,'').replace(/\t/g,'').replace(/\v/g,'') ;
}
function debug_xml_element_new(node,prefix) {
// Fonction de d�bug : retourne une chaine indiquant la structure de l'objet XML pass� en param�tre
// La fonction est r�cursive et doit �tre appel�e avec un pr�fixe pour l'affichage, de pr�f�rence, mettre une chaine vide
	var result ='';
	if ( node.nodeType )
		switch (node.nodeType) {
/*
    * Node.ATTRIBUTE_NODE == 2 (nœud attribut)
    * Node.CDATA_SECTION_NODE == 4 (nœud de section CDATA)
    * Node.ENTITY_REFERENCE_NODE == 5 (nœud de référence à une entité)
    * Node.ENTITY_NODE == 6 (nœud d'entité)
    * Node.PROCESSING_INSTRUCTION_NODE == 7 (nœud d'instruction de traitement)
    * Node.DOCUMENT_TYPE_NODE == 10 (nœud de type de document)
    * Node.DOCUMENT_FRAGMENT_NODE == 11 (nœud de fragment de document)
    * Node.NOTATION_NODE == 12 (nœud de notation) 
*/
			case 1: // (nœud élément)
				var childs = node.childNodes ;
				result += prefix + '{' + node.nodeName + '}' ;
				if ( node.nodeValue != null )
					result += '(' + node.nodeValue + ')' ;
				result += '\n' ;
				if ( childs.length > 0 ) {
					for( var i = 0 ; i < childs.length ; i++) {
						child = childs.item(i) ;
						result += debug_xml_element_new(child,prefix+'\t('+i+')') ;
					}
				}
				break;
			case 3: // (nœud texte)
				result += prefix + '"' + strip(node.nodeValue) + '"\n' ;
				break;
			case 8: // (nœud de commentaire)
				result += prefix + '<!-- ' + strip(node.nodeValue) + '-->\n' ;
				break;
			case 9: // (nœud de document)
				break;
			default:
				result += prefix + 'unknown node type ' + node.nodeType + '\n'
		}
	else
		result = node ;
	return result ;
}
function debug(node) {
	alert(debug_xml_element_new(node,'')) ;
}
