// ==UserScript==
// @name		    Travian Messages and Reports Helper
// @description	Transforms messages/reports pages  
// @include     http://*.travian.*/berichte.php*
// @include     http://*.travian3.*/berichte.php*
// @include     http://*.travian.*/nachrichten.php*
// @include     http://*.travian3.*/nachrichten.php*
// @exclude     http://forum.travian.*
// @exclude     http://www.travian.*
// @version     1.0
// ==/UserScript==
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** 
 * This script adds the following functions:
 *    - select all messages or reports displayed on current page with one click
 *    - delete reports based on type (all, attacks, trade...)
 *    - adds a shortcut for jumping to next page by pressing the space bar
 *    - adds extra information to battle reports, namely the resources needed 
 *      to rebuild lost troops and some statistics
 */

var DEF_UNDERSCORE = "_";
var DEF_PARTKEY_PREFIX = getServerName() + DEF_UNDERSCORE + getUserId() + DEF_UNDERSCORE;
var DEF_PARTKEY_REPORTSACTION = "reportsAction";
var DEF_GRAPHIC_PACK_PREFIX = "";

//tribes
var DEF_TRIBE_ROMAN = 0;
var DEF_TRIBE_GAUL = 1;
var DEF_TRIBE_TEUTON = 2;
var DEF_TRIBE_NATURE = 3;
var DEF_TRIBE_NATAR = 4;
var DEF_TRIBE_UNDISCLOSED = 5;

//troops cost (wood, clay, iron, wheat, crop usage)
var DEF_TROOPS_COST = new Array();
DEF_TROOPS_COST[DEF_TRIBE_ROMAN]  = [ [120,100,180,40,1], [100,130,160,70,1], [150,160,210,80,1], [140,160, 20,40,2], [550,440,320,100,3], [550,640,800,180,4], [ 900,360,500,70,3], [950,1350,600,90,6], [30750,27200,45000,37500,5], [5800,5300,7200,5500,1] ];
DEF_TROOPS_COST[DEF_TRIBE_GAUL]   = [ [100,130, 55,30,1], [140,150,185,60,1], [170,150, 20,40,2], [350,450,230,60,2], [360,330,280,120,2], [500,620,675,170,3], [ 950,555,330,75,3], [960,1450,630,90,6], [30750,45400,31000,37500,4], [5500,7000,5300,4900,1] ];
DEF_TROOPS_COST[DEF_TRIBE_TEUTON] = [ [ 95, 75, 40,40,1], [145, 70, 85,40,1], [130,120,170,70,1], [160,100, 50,50,1], [370,270,290, 75,2], [450,515,480, 80,3], [1000,300,350,70,3], [900,1200,600,60,6], [35500,26600,25000,27200,4], [7200,5500,5800,6500,1] ];
DEF_TROOPS_COST[DEF_TRIBE_NATURE] = [ [  0,  0,  0, 0,1], [  0,  0,  0, 0,1], [  0,  0,  0, 0,1], [  0,  0,  0, 0,1], [  0,  0,  0,  0,2], [  0,  0,  0,  0,2], [   0,  0,  0, 0,3], [  0,   0,  0, 0,3], [    0,    0,    0,    0,3], [   0,   0,   0,   0,5] ];
DEF_TROOPS_COST[DEF_TRIBE_NATAR]  = [ [  0,  0,  0, 0,0], [  0,  0,  0, 0,0], [  0,  0,  0, 0,0], [  0,  0,  0, 0,0], [  0,  0,  0,  0,0], [  0,  0,  0,  0,0], [   0,  0,  0, 0,0], [  0,   0,  0, 0,0], [    0,    0,    0,    0,0], [   0,   0,   0,   0,0] ];

//troops attributes (attack, infantry defense, cavalry defense, speed)
var DEF_TROOPS_ATTRIBUTES = new Array();
DEF_TROOPS_ATTRIBUTES[DEF_TRIBE_ROMAN]  = [ [40,35,50, 6], [30,65,35, 5], [70,40,25, 7], [ 0,20,10,16], [120, 65,50,14], [180,80,105,10], [ 60, 30, 75, 4], [ 75, 60, 10, 3], [ 50, 40, 30, 4], [  0, 80, 80, 5] ];
DEF_TROOPS_ATTRIBUTES[DEF_TRIBE_GAUL]   = [ [15,40,50, 7], [65,35,20, 6], [ 0,20,10,17], [90,25,40,19], [ 45,115,55,16], [140,50,165,13], [ 50, 30,105, 4], [ 70, 45, 10, 3], [ 40, 50, 50, 5], [  0, 80, 80, 5] ];
DEF_TROOPS_ATTRIBUTES[DEF_TRIBE_TEUTON] = [ [40,20, 5, 7], [10,35,60, 7], [60,30,30, 6], [ 0,10, 5, 9], [ 55,100,40,10], [150,50, 75, 9], [ 65, 30, 80, 4], [ 50, 60, 10, 3], [ 40, 60, 40, 4], [ 10, 80, 80, 5] ];
DEF_TROOPS_ATTRIBUTES[DEF_TRIBE_NATURE] = [ [10,25,10,20], [20,35,40,20], [60,40,60,20], [80,66,50,20], [ 50, 70,33,20], [100,80, 70,20], [250,140,200,20], [450,380,240,20], [200,170,250,20], [600,440,520,20] ];
DEF_TROOPS_ATTRIBUTES[DEF_TRIBE_NATAR]  = [ [ 0, 0, 0, 0], [ 0, 0, 0, 0], [ 0, 0, 0, 0], [ 0, 0, 0, 0], [  0,  0, 0, 0], [  0, 0,  0, 0], [  0,  0,  0, 0], [  0,  0,  0, 0], [  0,  0,  0, 0], [  0,  0,  0, 0] ];

// bounty each troop can carry, troops ordered by each tribe, tribe ordered by: romans, gauls, teutons
var DEF_TROOPS_BOUNTY_LOAD = new Array();
DEF_TROOPS_BOUNTY_LOAD[DEF_TRIBE_ROMAN]  = [ 40, 20, 50, 0, 100, 70, 0, 0, 0, 3000, 0 ];
DEF_TROOPS_BOUNTY_LOAD[DEF_TRIBE_GAUL]   = [ 30, 45, 0, 75,  35, 65, 0, 0, 0, 3000, 0 ];
DEF_TROOPS_BOUNTY_LOAD[DEF_TRIBE_TEUTON] = [ 60, 40, 50, 0, 110, 80, 0, 0, 0, 3000, 0 ];
DEF_TROOPS_BOUNTY_LOAD[DEF_TRIBE_NATURE] = [  0,  0,  0, 0,   0,  0, 0, 0, 0,    0, 0 ];
DEF_TROOPS_BOUNTY_LOAD[DEF_TRIBE_NATAR]  = [  0,  0,  0, 0,   0,  0, 0, 0, 0,    0, 0 ];

//troop type: infantry, cavalry or other (used when displaying attack value)
var DEF_TROOP_TYPE_INFANTRY = 0;
var DEF_TROOP_TYPE_CAVALRY = 1;
var DEF_TROOP_TYPE_OTHER = 2;

var DEF_TROOPS_TYPE = new Array();
DEF_TROOPS_TYPE[DEF_TRIBE_ROMAN] = [ DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER ];
DEF_TROOPS_TYPE[DEF_TRIBE_GAUL] = [ DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER ];
DEF_TROOPS_TYPE[DEF_TRIBE_TEUTON] = [ DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER ];
DEF_TROOPS_TYPE[DEF_TRIBE_NATURE] = [ DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER ];
DEF_TROOPS_TYPE[DEF_TRIBE_NATAR] = [ DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_INFANTRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_CAVALRY, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER ];
DEF_TROOPS_TYPE[DEF_TRIBE_UNDISCLOSED] = [ DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER, DEF_TROOP_TYPE_OTHER ];

//space for the field name information
var fields= [];

/** 
 * get the table containing the items (messages or reports)
 */ 
var itemsHtmlTable = null;
var tmpTables = document.getElementsByTagName('table');
for(var i=0; i<tmpTables.length; i++){
	if(tmpTables[i].className.indexOf('tbg') != -1){
		itemsHtmlTable = tmpTables[i];
		break;
	}
}
//now check if this table is the address book
if (itemsHtmlTable) {
  var tds = itemsHtmlTable.getElementsByTagName('td');
  for (var i=0;i<tds.length;i++) {
    if (tds[i].className.indexOf('addr')!=-1) {
      itemsHtmlTable = null;
      break;
      }
    }
  }

//gets the graphic pack path if it is active
getGraphicPackPathPrefix();

//gets the name of the resource fields
fields=getResourceFieldNames();

/**
 * note abote the href check in delete report by type section:
 *  
 * when deleting a report from any other page then main (berichte.php without the t param)
 * Travian server refreshes the page and instead of getting back to that report type page
 * it redirects the browser to main reports page. this interferes with auto deletion sequence
 * which is designed to delete reports of the given kind, then refresh the page with reports
 * of that kind and if still any exist, delete them, refresh the page, etc. since refreshing 
 * gets us back to main page we have to make sure that the URL check doesn't trigger the
 * action to stop. that is why we have:
 *    document.location.href.indexOf(load_ReportsAction()) > -1
 * instead of:
 *    document.location.href == load_ReportsAction
 * this, on the other hand, has the effect that when clicking to delete reports of any kind
 * (all button) and then skipping to any other report type page before the delete action
 * finishes, instead of canceling the action, the action will continue to execute.
 * yet, since chosing to delete all reports this doesn't really matter   
 */ 

if (isThisBattleReportPage()) {
  //if this is single item page, check if it's battle report and then add the additional info

  addBattleInfo();

} else if (itemsHtmlTable) {
  //if table exists add auto next page function and do the transformations
    
  //add a checkbox to quickly select all items
  addSelectAllCheckBox();
  //add a event listener for key down
  document.onkeydown = action_goToNextPage;
  
  //if this is reports page add delete by type buttons
  if (document.location.href.match("berichte.php")) {

    addDeleteReportByTypeButtons();
    
    //if we got here after pressing a delete by type button which refreshes the page
    //it means that a delete action is waiting to be executed
    if (exists_ReportsAction()) {
      if (load_ReportsAction().indexOf(document.location.href)>-1) {
        //if we are on the correct report type page, do the deletion
        deleteReportsOfGivenKind();
      } else {
        //if not, it's possible that the user canceled the action in browser so remove the action flag
        reset_ReportsAction();
        }
      }
    }

}

/**
 * adds a select all checkbox to messages/reports list
 * the code is different for reports and messages pages since they have
 * different items html table structures  
 */ 
function addSelectAllCheckBox() {
  var tableLength = itemsHtmlTable.rows.length-1;

	if (document.location.href.match("berichte.php") && !document.location.href.match('id=')) {
	  //this is for reports page

    //create the checkbox
		var chkbox = document.createElement('input');
		chkbox.type = 'checkbox';
		chkbox.id = 'selectallchkbox';
		chkbox.onclick = selectAllCheckBoxes;
		
		//table cell for the checkbox
		var newHeaderCell = document.createElement('td');
		newHeaderCell.width = 22;
		newHeaderCell.appendChild(chkbox);
    
    //append the table cell
    itemsHtmlTable.rows[tableLength].cells[0].colSpan = 1;
    itemsHtmlTable.rows[tableLength].insertBefore(newHeaderCell, itemsHtmlTable.rows[tableLength].cells[0]);
	
  } else if (document.location.href.match("nachrichten.php")) {
    //this is for messages page

    //create the checkbox
		var chkbox = document.createElement('input');
		chkbox.type = 'checkbox';
		chkbox.onclick = selectAllCheckBoxes;

    //add the checkbox to the table
		itemsHtmlTable.rows[tableLength].cells[0].appendChild(chkbox);

	}
}

/**
 * event handler for select all checkbox
 * first checks if the table is not empty, i.e. if first cell of the second 
 * table row contains an input tag (checkbox)
 * then iterates through table rows and sets checked property of each checkbox   
 */ 
function selectAllCheckBoxes() {

  if (itemsHtmlTable.rows[1].cells[0].firstChild.nodeName!='INPUT')
    return;

	value = event.srcElement.checked;
	for (var i = 1; itemsHtmlTable.rows[i]; i++) {
		itemsHtmlTable.rows[i].cells[0].firstChild.checked = value;
	}

}

/**
 * adds buttons that delete reports by type
 * button titles are fetched from links on all reports page so that they are displayed in server's language
 * buttons are added next to existing 'delete' button and because of limited space
 * their names are truncated to only first three letters of each report type name    
 */ 
function addDeleteReportByTypeButtons() {

  //this is already existing delete button which deletes only selected items
  var inputs = document.getElementsByTagName('input');
  var deleteButton = null;
  for (var i=0;i<inputs.length;i++) {
    if (inputs[i].className=='std') {
      deleteButton = inputs[i];
      break;
      }
    }

  //make sure we're not on a single report page
  if (!deleteButton)
    return;
  
  //fetch titles and add buttons with appropriate event handlers
  var td = deleteButton.parentNode;
  var as = document.getElementById('lmid2').getElementsByTagName('p')[0].getElementsByTagName('a');
  for (var i=0;i<as.length;i++) {
    var button = document.createElement('input');
    button.type = 'button';
    button.className = 'std';
    button.id = as[i].href;
    button.value = as[i].innerHTML.substr(0,3);
    button.onclick = action_deleteReports;
    td.appendChild(button);
    }
}

/**
 * deletes the reports of the given type on current and following pages (if any exist)
 */ 
function deleteReportsOfGivenKind() {
  //check if there are any reports by counting checkboxes
  if (itemsHtmlTable.rows[1].cells[0].firstChild.nodeName!='INPUT') {
    //if there are no more reports for deletion, remove the action and go back to all reports page
    reset_ReportsAction();
    document.location.href = document.getElementById('lmid2').getElementsByTagName('p')[0].getElementsByTagName('a')[0].href;
  } else {
    //delete everything on the current page
    document.getElementById('selectallchkbox').click();
    //this forces the form to submit and thus refreshes the page repeating the action until there are no more reports
    itemsHtmlTable.rows[itemsHtmlTable.rows.length-1].cells[1].getElementsByTagName('input')[0].click();
    }
}

/**
 * event listener for delete reports buttons
 * saves the action to delete reports of a certain type
 * then changes current page to the page with reports of that type where the deletion occurs   
 */ 
function action_deleteReports() {
  save_ReportsAction(this.id);
  document.location.href = this.id;
}

/**
 * event listener for next page shortcut functionality on space bar press
 */ 
function action_goToNextPage() {

  if(String.fromCharCode(event.keyCode)==" ") {
  
  	var DEF_CHAR_RAQUO = unescape('%BB');
  	//find an <a> with righ angle quotes char
  	var links = document.getElementsByTagName("a");
  	var i;
  	for(i=0; i<links.length; i++) {
  		if (links[i].innerHTML.indexOf(DEF_CHAR_RAQUO) == 0) {
        break;
        }
  	 }
  	if (i != links.length) {
  	  //now go to that page
      document.location.href = links[i].href;
      }
    
    //prevents browser from handling the space bar press (usually it's used to scroll down)
  	return false;
	}

}

/**
 * checks if the current page is a battle report details page
 * this is done by searching for a <td> with class="unit"
 */  
function isThisBattleReportPage() {
  
  var retVal = false;
  if (document.getElementById('lmid2').getElementsByTagName('table').length>1) {
    
    var trs = document.getElementById('lmid2').getElementsByTagName('table')[1].getElementsByTagName('tr');
    for (var i=0;i<trs.length;i++) {
      if (trs[i].className=='unit') {
        retVal = true;
        break;
        }
      }
    
  }
  
  return retVal;
  
  }

/**
 * adds additional information to the battle report such as cost of lost units
 * and some extra statistics (still haven't decided what) :)
 * 
 * there are multiple HTML structures of this page depending of type of battle
 * report (reinforcements were attacked, battle report with no return information,
 * battle report with none or many reinforcement tribes, etc.)
 * yet, the basic structure is the same: inside lmid2 is a table that contains
 * player details and attack time. inside it are multiple child table elements,
 * each containing information about single player's military losses (and possible bounty)
 * 
 * TODO: add support for translation of table titles
 * TODO: add total training time for lost troops (maybe)    
 */  
function addBattleInfo() {

  //get all the tables that hold military information for each player
  var tables = document.getElementById('lmid2').getElementsByTagName('table')[0].getElementsByTagName('table');
  var totalResLosses;
  var totalBounty;
  var attackersBounty = 0;    //holds info about how much resources the attacker got, this is later added to first defenders losses
  
  //transform each table
  for (var i=0;i<tables.length;i++) {

    //get tribe data, used to calculate troop information later
    var tribe = getTribeBySettlerImage(i);

    //add the transformations
    if (tables[i].rows.length>3) {
      transformBattleReport_addSurvivors(tables[i]);
      totalBounty = transformBattleReport_addBountySums(tables[i], tribe);
      if (i==0) attackersBounty=totalBounty;
      totalResLosses = transformBattleReport_addLostUnitsCost(tables[i], tribe);
      transformBattleReport_addTotals(tables[i], tribe, totalResLosses, totalBounty,(i==1)?attackersBounty:0, i==0);
      }
    }

  }

/**
 * adds a row with number of survived troops
 */ 
function transformBattleReport_addSurvivors(table) {
  var row = table.insertRow(4);
  var cell;
  for (var survived=0,cellc=table.rows[2].cells.length-1;cellc>0;cellc--) {
    cell = row.insertCell(0);
    survived = table.rows[2].cells[cellc].innerText - table.rows[3].cells[cellc].innerText;
    cell.appendChild(document.createTextNode(survived));
    if (survived==0)
      cell.className='c';
    }
  cell = row.insertCell(0);
  cell.appendChild(document.createTextNode('Survived'));
  }

/**
 * adds total bounty and success percent
 */ 
function transformBattleReport_addBountySums(table, tribe) {
  var bounty = getBountyRow(table);
  var bountyValues = new Array(0,0,0,0);
  var totalBounty = 0;
  
  if (bounty) {
    //calculate the total obtained bounty 
    var bountyValues = bounty.getElementsByTagName('td')[1].innerText.split(' ');
    for (var k=0;k<bountyValues.length;k++)
      totalBounty += parseInt(bountyValues[k]);
    
    //possible bounty depends of sent troops and their load capacity
    var possibleBounty = 0;
    for (var k=1;k<11;k++) {    //skip heroes
      possibleBounty += table.rows[4].cells[k].innerText * DEF_TROOPS_BOUNTY_LOAD[tribe][k-1];
      }
    var bountyValue = '  ['+totalBounty;
    if (possibleBounty!=0)
      bountyValue += ' / '+Math.round(totalBounty/possibleBounty*100)+'%';
    bountyValue += ']';
    bounty.getElementsByTagName('td')[1].appendChild(document.createTextNode(bountyValue));
    }
  
  return totalBounty;
  
  }
  
/**
 * adds total resource cost for lost troops
 */ 
function transformBattleReport_addLostUnitsCost(table, tribe) {
    var resLosses = new Array(0,0,0,0);
    var totalResLosses = 0;    
    var totalUnits = 0;
    var totalLost = 0;
    
    var row = table.insertRow(table.rows.length);
    row.className = 'cbg1';
    //calculate resource cost for lost troops
    for (var losses=0, k=1;k<11;k++) {
      totalUnits += parseInt(table.rows[2].cells[k].innerText);
      losses = parseInt(table.rows[3].cells[k].innerText);
      totalLost += losses;
      if (losses>0) {
        for (r=0;r<4;r++) {
          resLosses[r] += losses*DEF_TROOPS_COST[tribe][k-1][r];
          }
        }
      }
      
    //add the cell with images and cost values
    cell = row.insertCell(0);
    cell.colSpan = 11;
    cell.className = 's7';
    for (r=0; r<4; r++) {
      img = document.createElement('img');
      img.className = 'res';
      img.title = fields[r];
      img.src = DEF_GRAPHIC_PACK_PREFIX+'img/un/r/'+(r+1)+'.gif';
      cell.appendChild(img);
      cell.appendChild(document.createTextNode(resLosses[r]+' '));
      totalResLosses += resLosses[r];
      }
    //add total resource losses value
    var totalValue = ' ['+totalResLosses;
    if (totalUnits!=0)
      totalValue += ' / '+Math.round(totalLost/totalUnits*100)+'%';
    totalValue += ']';
    cell.appendChild(document.createTextNode(totalValue));
    //title cell, text is in server language
    cell = row.insertCell(0);
    cell.appendChild(document.createTextNode(table.rows[3].cells[0].innerText));
    
    return totalResLosses;
  }

/**
 * adds summary data (attack and defense strengths, resource gain/loss)
 * for attacker display separate attack values for infantry and cavalry
 * for defenders display only defence value  
 */ 
function transformBattleReport_addTotals(table, tribe, totalResLosses, totalBounty,attackersBounty, isAttacker) {
    row = table.insertRow(table.rows.length);
    row.className = 'cbg1';
    cell = row.insertCell(0);
    cell.colSpan = 11;
    cell.className = 's7';
    
    var strength = new Array(0,0,0);
    var troopType = 0;
    
    for (var i=1;i<11;i++) {
      if (isAttacker) {
        troopType = DEF_TROOPS_TYPE[tribe][i-1];
        strength[troopType] += table.rows[2].cells[i].innerText*DEF_TROOPS_ATTRIBUTES[tribe][i-1][0];
      } else {
        for (var j=0;j<2;j++) {
          strength[j] += table.rows[2].cells[i].innerText*DEF_TROOPS_ATTRIBUTES[tribe][i-1][j+1];
          }
      }
    }

    var title = 'defense';
    if (isAttacker) {
      title = 'attack';
      img = document.createElement('img');
      img.title = 'Infantry attack';
      img.src = DEF_GRAPHIC_PACK_PREFIX+'img/un/a/att_all.gif';
      cell.appendChild(img);
    }
    img = document.createElement('img');
    img.title = 'Infantry '+title;
    img.src = DEF_GRAPHIC_PACK_PREFIX+'img/un/a/def_i.gif';
    cell.appendChild(img);
    cell.appendChild(document.createTextNode(strength[0]+' '));

    if (isAttacker) {
      img = document.createElement('img');
      img.title = 'Cavalry attack';
      img.src = DEF_GRAPHIC_PACK_PREFIX+'img/un/a/att_all.gif';
      cell.appendChild(img);
    }
    img = document.createElement('img');
    img.title = 'Cavalry '+title;
    img.src = DEF_GRAPHIC_PACK_PREFIX+'img/un/a/def_c.gif';
    cell.appendChild(img);
    cell.appendChild(document.createTextNode(strength[1]+' '));
    
    
    var span = document.createElement('span');
    var result = totalBounty-totalResLosses-attackersBounty;
    span.className = (result<0)?'c2 b':'c1 b';
    img = document.createElement('img');
    img.src = DEF_GRAPHIC_PACK_PREFIX+'img/un/r/6.gif';
    img.title = 'Total resource losses'
    span.appendChild(img);
    span.appendChild(document.createTextNode(result));
    cell.appendChild(span);

    //title cell
    cell = row.insertCell(0);
    cell.appendChild(document.createTextNode('Total'));

  }

/**
 * iterates through table searching for row with bounty values
 * it is the row with 4 <img> tags
 */  
function getBountyRow(table) {
  var bounty = null;
  var trs = table.getElementsByTagName('tr');
  for (var j=0;j<trs.length;j++) {
    if (trs[j].className=='cbg1') {
      if (trs[j].getElementsByTagName('img').length==4) {
        bounty = trs[j];
        break;
        }
      }
    }
  return bounty;
}

/**
* gets the tribe name by looking at the gifs of the settlers
* pos - if multiple tribes are present, which one to get info about 
*/
function getTribeBySettlerImage(pos) {
  
  var imgs = document.getElementById('lmid2').getElementsByTagName('img');
  var settlerImgs = new Array();
  for (var i=0;i<imgs.length;i++) {
    if (imgs[i].src.indexOf('img/un/u/')!=-1 && imgs[i].src.indexOf('0.gif')!=-1)
      settlerImgs.push(imgs[i]); 
    }
  
  var imgNo = parseInt(settlerImgs[pos].src.substr(settlerImgs[pos].src.indexOf("0.gif") - 1, 2));

	switch (imgNo) {
		case 10: return DEF_TRIBE_ROMAN;
		case 20: return DEF_TRIBE_TEUTON;
		case 30: return DEF_TRIBE_GAUL;
		case 40: return DEF_TRIBE_NATURE;
		case 50: return DEF_TRIBE_NATAR;
		case 60: return DEF_TRIBE_UNDISCLOSED;
		default: alert("New tribe?!?!?"); return;
	}
}

/**
 * Gets current server name
 * used to differentiate users when saving settings  
 */
function getServerName() {
	return location.href.match(/([\w]+[.]travian([\d]?).[\w]+([.][\w]+)?)/i)[1];
}

/**
 * Gets the current player id from profile link
 * used to differentiate users when saving settings  
 */ 	
function getUserId() {
	var as = document.getElementsByTagName('a');
	var userID = null;
	for (var i=0;i<as.length;i++) {
    if (as[i].href.indexOf('spieler.php?uid=')!=-1) {
      userID = as[i];
      break;
      }
    }
	return getParamFromUrl(userID.href, "uid");
}

/**
 * getParamFromUrl
 * url - The string of the URL
 * urlParam - The param being searched in the URL
 */
function getParamFromUrl(url, urlParam) {
	var res = "&" + url.substring(url.indexOf("?") + 1); //exclude "?" and before that
	//first check if urlParam is not the only param and not the first param
	var searchStr = "&" + urlParam + "=";
	var pos = res.indexOf(searchStr);
	if (pos != -1) {
	  //now check if urlParam is the first parameter in URL
		res = res.substring(res.indexOf(searchStr) + searchStr.length);
		//check if there are more parameters following the urlParam and strip them
		var moreParams = res.indexOf("&");
		if (moreParams != -1) {
		 	res = res.substring(0, moreParams);
		}
		//finally remove the hash mark (browsers sometimes add these to the end of the URL)
		return res.replace("#", "");
	} else {
		return "";
	}
}

/**
 * checks if graphics pack is active and gets its path
 */ 
function getGraphicPackPathPrefix() {
	var woodImgUrl = "img/un/r/1.gif";
	var imgs = document.getElementsByTagName('img');
	for (var i=0;i<imgs.length;i++) {
	  if (imgs[i].src.indexOf('img/un/r/1.gif')>-1) {
	    var imgSrc = imgs[i].src;
	    DEF_GRAPHIC_PACK_PREFIX = unescape(imgSrc.replace(woodImgUrl, "").replace("///", "//"));
	    break;
      }
    }
}

/** 
 * gets the resource filed names from the resources div
 */
function getResourceFieldNames(){
	var orgbar=returnObjById('lres0');
	if(!orgbar) {orgbar=getElementsByClassName(document, 'div', 'div4')[0];}
	if(!orgbar) {orgbar=returnObjById('lres');}
	if(!orgbar) return;
	var resbar=orgbar.getElementsByTagName('img');
	return [resbar[0].title, resbar[1].title, resbar[2].title, resbar[3].title]
}

/**
 * searches the oElm for strTagName objects with strClassName class
 */ 
function getElementsByClassName(oElm, strTagName, strClassName){
    var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
    var arrReturnElements = new Array();
    strClassName = strClassName.replace(/\-/g, "\\-");
    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    var oElement;
    for(var i=0; i<arrElements.length; i++){
        oElement = arrElements[i];      
        if(oRegExp.test(oElement.className)){
       arrReturnElements.push(oElement);
        }   
    }
    return (arrReturnElements)
}

/**
 * this is cross browser compatible
 */ 
function returnObjById( id ){ 
    if (document.getElementById)
        return document.getElementById(id);
    else if (document.all)
        return document.all[id];
    else if (document.layers)
        return document.layers[id];
}

/** save, reset, load, createKey, exists - ReportsAction - <server>_<userId>_reportsAction */
// Saved info: url of type of report to delete
function save_ReportsAction(reportAction) { PRO_setValue(key_ReportsAction(), reportAction); }
function reset_ReportsAction() { save_ReportsAction(""); }
function load_ReportsAction() { return PRO_getValue(key_ReportsAction(), ""); }
function key_ReportsAction() { return DEF_PARTKEY_PREFIX + DEF_PARTKEY_REPORTSACTION; }
function exists_ReportsAction() { return (load_ReportsAction() != ""); }

