<?php
/* * * * * * * * * * * * * * * * * * * * * * *
 * _     _ _  _   _                          *
 * \ \  ///                [ 2 0 0 6 ]       *
 *  \ \///  i s h i o u s . d e              *
 *   \///                                    *
 * * * * * * * * ` W H A T ´ * * * * * * * * *
 *   \// I N C E  subversion: Custom         *
 * * * * * * * * ` D A T A ´ * * * * * * * * *
 *  For: q4max                               *
 *  Sub: q4maxXML_class.php                  *
 *  Chg: 28.08.2006                          *
 * * * * * * * * * * * * * * * * * * * * * * */
 
 
class XMLstats {
	// basic
	var $configuration;	// config.ini
	var $XMLfiles;		// arrayed
	var $XMLparsed;		// arrayed
	var $statfolders;	// arrayed
	var $XMLfilecount;
	var $classversion;
	var $wasiparsed;	// BOOL
	var $prevparsed;	// arrayed
	var $tpdetermtype;
	var $XMLlist;		// arrayed
	var $procError;		// single errormsg
	var $skiplists;		// skiplists/filters
	
	// stat-related
	var $outputtype;
	var $statfiles;		// arrayed
	var $players; 		// subclassed
	var $clans;			// arrayed
	var $maps;			// arrayed
	var $gametypes;		// arrayed
	var $matchesplayed;
	var $topplayers;	// arrayed
	var $topclans;		// arrayed
	var $cmatcheswon;	// arrayed (hack - internal array for clan win/loss)
	
	function XMLstats () {
		// constructor
		// parse config file
		$this->XMLfiles = array();
		$this->Parse_Configuration();
		
		// set basic datatypes (cosmetic)
		$this->players 					= array();
		$this->players["playerlist"] 	= array();
		$this->clans					= array();
		$this->clans["clanlist"]		= array();
		$this->XMLfiles 				= array();
		$this->XMLparsed 				= array();
		$this->statfolders 				= array();
		$this->statfiles 				= array();
		$this->maps						= array();
		$this->gametypes 				= array();
		$this->prevparsed				= array();
		$this->topplayers				= array();
		$this->topclans					= array();
		$this->cmatcheswon				= array();
		$this->cmatcheswon["won"]		= array();
		$this->cmatcheswon["lost"]		= array();
		$this->XMLfilecount				= 0;
		$this->procError				= NULL;
		$this->skiplists				= array();
	}
	
	function Parse_Configuration() {
		$this->configuration = @parse_ini_file(CONFIGPATH."config.ini", TRUE);
		if (!is_array($this->configuration)) {
			$this->procError = "Configuration-File not found!";
			$this->pumpOutError();
			return FALSE;
		}
		
		// config setting tdeterm_type sets determination type, default: overall_eff
		
		// players
		$determtype = "overall_eff";
		switch ($this->configuration["GENERAL"]["tpdeterm_type"]) {
			case "overall_eff":
				$determtype = "overallefficiency";
				break;
			case "player_eff":
				$determtype = "playerefficiency";
				break;
			case "kills":
				$determtype = "kills";
				break;
			case "deaths":
				$determtype = "deaths";
				break;
			case "dnet":
				$determtype = "dnet";
				break;
		}
		$this->tpdetermtype = $determtype;
		
		// clans
		$determtype = "avg_playereff";
		switch ($this->configuration["GENERAL"]["tcdeterm_type"]) {
			case "avg_playereff":
				$determtype = "efficiency";
				break;
			case "kills":
				$determtype = "kills";
				break;
			case "deaths":
				$determtype = "deaths";
				break;
		}
		$this->tcdetermtype = $determtype;
		
		return TRUE;
	}
	
	function Parse_Stats() {
		$this->Build_Skip_Lists();
		$this->Get_Stat_Dumps();
		$this->Get_Stat_Files();
		$this->Parse_Info_From_Files();
		$this->Parse_Info_Into_Players();
		$this->Calculate_Player_Stats();
		$this->Calculate_Clan_Stats();
		$this->Get_Top_Players();
		$this->Get_Top_Clans();
		$this->Get_Top_Players_Clans();
		$this->Write_Stat_Dumps();
		$this->buildXMLlist();
	}
	
	function Build_Skip_Lists() {
		$filters = $this->configuration["FILTERING"];
		if (is_array($filters)) {
			foreach ($filters as $filtername => $content) {
				$this->skiplists[$filtername] = array();
				
				if (strlen($content) > 0) {
					$broken = explode("|||", $content);				
					if (is_array($broken)) {
						foreach ($broken as $skippy) $this->skiplists[$filtername][] = strtolower(trim(chop($skippy)));
					}
				}
			}
		}
	}
	
	function Get_Stat_Dumps() {
		if ($this->configuration["GENERAL"]["dump_stats"] != 1 || !is_file(IMPORTPATH."parsed.ini")) return TRUE;
		// get parsed.ini contents
		$parsed = new iniParser(IMPORTPATH."parsed.ini");
		$prevparsed = $parsed->getSection("PREVPARSED");
		$expparsed = array();
		if (is_array($prevparsed)) {
			foreach ($prevparsed as $key => $parsefileinfo) {
				$tmpparsed = explode("/", $parsefileinfo);
				$expparsed[$key]["filename"] = $tmpparsed[count($tmpparsed)-1];
				$expparsed[$key]["pathname"] = $parsefileinfo;
			}
		}
		$this->prevparsed = $expparsed;
		
		// get playerdata and reparse
		$playerdata = $parsed->_iniParsedArray;
		unset($playerdata["PREVPARSED"]);
		
		// initialize players using dump function
		foreach ($playerdata as $player) {
			$newindex = count($this->players["playerlist"]);
			$this->players["playerlist"][$newindex] = $player["guid"];
			$this->players[$newindex] = new player($player, $this->configuration, $this->skiplists, TRUE);
			// clanstats hack
			if (!isset($this->cmatcheswon["won"][$this->players[$newindex]->clan]) && !empty($player["cmatches_won"])) $this->cmatcheswon["won"][$this->players[$newindex]->clan] = $player["cmatches_won"];
			if (!isset($this->cmatcheswon["lost"][$this->players[$newindex]->clan]) && !empty($player["cmatches_lost"])) $this->cmatcheswon["lost"][$this->players[$newindex]->clan] = $player["cmatches_lost"];
		}
	}
	
	function Write_Stat_Dumps() {
		// if we had new XML files, write stat-dump
		if ($this->XMLfilecount > 0) {
			// set PREVPARSED ini settings
			$parsed = new iniParser(IMPORTPATH."parsed.ini");
			$packarray = array();
			if ($this->XMLfilecount >0) {
				foreach ($this->XMLparsed as $folderstr => $data) {
					$packarray[$folderstr] = $data;
				}
			}
			else {
				foreach ($this->prevparsed as $folderstr => $data) {
					$packarray[$folderstr] = $data["pathname"];
				}
			}
			$parsed->setSection("PREVPARSED", $packarray);
			
			// dump players using dump function
			foreach ($this->players as $key => $player) {
				if (is_numeric($key)) {
					$playersettings = get_object_vars($player);
					foreach ($playersettings as $settingname => $playersetting) {
						if (is_array($playersetting)) {
							if (count($playersetting) >0) {
								$playersettings[$settingname] = $player->serialize_arraydata($playersetting);
							}
							else unset($playersettings[$settingname]);
						}
					}
					// clanstats hack
					if (!empty($this->cmatcheswon["won"][$playersettings["clan"]])) $playersettings["cmatches_won"] = $this->cmatcheswon["won"][$playersettings["clan"]];
					if (!empty($this->cmatcheswon["lost"][$playersettings["clan"]])) $playersettings["cmatches_lost"] = $this->cmatcheswon["lost"][$playersettings["clan"]];
					$parsed->setSection($player->guid, $playersettings);
				}
			}
			$parsed->save();
		}
	}
	
	function Get_Stat_Files() {
		// partly UNOPTIMIZED
		// arrays are indexed with config.ini statfoldernames
		// get basic dirlisting of stats-root
		foreach ($this->configuration["STATFOLDERS"] as $foldervar => $statfolder) {
			// fill up statfolders array
			$this->statfolders[$foldervar] = $statfolder;
			$dirlist_years[$foldervar] = $this->dirlist($statfolder);
			// get subdirlisting of yearsfolder
			$dirlist_months = array();
			foreach ($dirlist_years[$foldervar] as $yearfolder) {
				if (!is_numeric($yearfolder) && $yearfolder != "basics") {
					$this->procError = "malformed stats-folder, it should contain 'year/month/day', containing: yearfolder $yearfolder";
					$this->pumpOutError();
				}
				// dirlist_years[__foldername__][__yearname__]
				if ($yearfolder != "basics") $dirlist_months[$foldervar][$yearfolder] = $this->dirlist("{$this->statfolders[$foldervar]}/{$yearfolder}");
			}
			// get subdirlisting of monthsfolder
			$dirlist_days = array();
			$complete_dirlist = array();
			
			// break folderstring of last parse open for skipping specific old date folders
			if (isset($this->prevparsed[$foldervar])) $subfolderstr = str_replace($this->configuration["STATFOLDERS"][$foldervar], "", $this->prevparsed[$foldervar]["pathname"]);
			if (!empty($subfolderstr)) {
				$subfolders = explode("/", $subfolderstr);
				$lastyear = $subfolders[1];
				$lastmonth = $subfolders[2];
				$lastday = $subfolders[3];
				$lastfile = $subfolders[4];
			}
			else {
				$lastyear = 0;
				$lastmonth = 0;
				$lastday = 0;
				$lastfile = NULL;
			}
			
			foreach ($dirlist_months[$foldervar] as $yearname => $monthfolders) {
				// dirlist_months[__foldername__][__yearname__][index] = __monthname__
				// if year has been processed, skip
				if ($yearname >= $lastyear) {
					foreach ($monthfolders as $monthname) {
						if (!is_numeric($monthname)) {
							$this->procError = "malformed stats-folder, it should contain 'year/month/day', containing: monthfolder $monthname";
							$this->pumpOutError();
						}
						//echo $month
						// if month has been processed, skip
						if ($monthname >= $lastmonth) {
							$dirlist_days[$foldervar][$yearname][$monthname] = $this->dirlist("{$this->statfolders[$foldervar]}/{$yearname}/{$monthname}");
							// if month has been processed, skip
							foreach ($dirlist_days[$foldervar][$yearname][$monthname] as $dayname) {
								if (!is_numeric($dayname)) {
									$this->procError = "malformed stats-folder, it should contain 'year/month/day', containing: dayfolder $dayname";
									$this->pumpOutError();
								}
								if ($dayname >= $lastday) {
									// get subdir listing of daysfolders
									// dirlist_days[__foldername__][__yearname__][__monthname__][index] = __dayname__
									$complete_dirlist[$foldervar][$yearname][$monthname][$dayname] = $this->dirlist("{$this->statfolders[$foldervar]}/{$yearname}/{$monthname}/{$dayname}");
									$foundlast = FALSE;
									// fill up local XMLfiles array
									foreach ($complete_dirlist[$foldervar][$yearname][$monthname][$dayname] as $xmlfilename) {
										// we only want xml, dont we?
										if (substr($xmlfilename, strlen($xmlfilename)-3) == "xml") {
											if ($this->configuration["GENERAL"]["dump_stats"] == 1 && !empty($lastfile)) {
												// skip "old" statfiles for parsing
												if ($xmlfilename == $lastfile) $foundlast = TRUE;
												// found last parsed file, parse rest
												elseif ($dayname > $lastday || $foundlast == TRUE) {
													$curindex = count($this->XMLfiles[$foldervar]);
													$this->XMLfilecount++;
													$this->XMLfiles[$foldervar][$curindex]["filename"] = $xmlfilename;
													$this->XMLfiles[$foldervar][$curindex]["pathname"] = "{$this->statfolders[$foldervar]}/{$yearname}/{$monthname}/{$dayname}/{$xmlfilename}";
												}
											}
											else {
												$curindex = count($this->XMLfiles[$foldervar]);
												$this->XMLfilecount++;
												$this->XMLfiles[$foldervar][$curindex]["filename"] = $xmlfilename;
												$this->XMLfiles[$foldervar][$curindex]["pathname"] = "{$this->statfolders[$foldervar]}/{$yearname}/{$monthname}/{$dayname}/{$xmlfilename}";
											}
										}
										else {
											$this->procError = "Wrong file in /stats tree {$yearname}/{$monthname}/{$dayname}: {$xmlfilename}";
											$this->pumpOutError();											
										}										
									}
								}
							}
						}
					}
				}
			}
			// got XML listing
			// set last parsed file
			if (isset($this->XMLfiles[$foldervar]))	{
				$this->XMLparsed[$foldervar] = $this->getLastParsedFile($this->XMLfiles[$foldervar]);
				$this->XMLparsed[$foldervar] = $this->XMLparsed[$foldervar]["pathname"];
			}
		}	
	}
	
	function getLastParsedFile($filedata) {
		// build easy string for sorting, of folder/filenames
		$stringlist = array();
		$curmax = 0;
		foreach ($filedata as $key => $file) {
			$exploded = explode("/", $file["pathname"]);
			$explen = count($exploded);
			$tmpstring = str_replace(array("-", ".xml"), "", $exploded[$explen-4].$exploded[$explen-3].$exploded[$explen-2].$exploded[$explen-1]);
			$stringlist[$key] = $tmpstring;
			if ($tmpstring > $stringlist[$curmax]) {
				$curmax = $key;
			}
		}
		return $filedata[$curmax];
	}
	
	function Parse_Info_From_Files() {
		if (count($this->XMLfiles) == 0 && count($this->players) <1) {
			$this->procError = "No Statfiles found!";
			$this->pumpOutError();
		}
		else {
			//var_dump($this->XMLfiles);
			// parse whole XML files for list
			foreach ($this->XMLfiles as $foldervar => $filelist) {
				$foundlast = FALSE;
				foreach ($filelist as $file) {
					/*if ($this->configuration["GENERAL"]["dump_stats"] == 1 && !empty($this->prevparsed[$foldervar])) {
						// skip "old" statfiles for parsing
						if ($file["filename"] == $this->prevparsed[$foldervar]) $foundlast = TRUE;
						// found last parsed file, parse rest
						else {
							if ($foundlast == TRUE) {
								$tmpxml = new SofeeXmlParser();
								$tmpxml->parseFile($file["pathname"]);
								$this->XMLfiles[$foldervar]["parsed"][] = $tmpxml->getTree();
							}
						}
					}
					else {*/
						$tmpxml = new SofeeXmlParser();
						$tmpxml->parseFile($file["pathname"]);
						$tmpparsed = $tmpxml->getTree();
						$tmpparsed["match"]["xmlfile"] = $file["pathname"];
						$this->XMLfiles[$foldervar]["parsed"][] = $tmpparsed;
						//echo "\n\r\n\r BLABLA";
						//var_dump($tmpparsed);
					//}
				}
			}
		}
	}
	
	function Parse_Info_Into_Players() {
		// run through parsed XML data
		foreach ($this->XMLfiles as $substats) {
			if (count($substats["parsed"])>0) {
				foreach ($substats["parsed"] as $xmldata) {
					// run through matches
					$this->matchesplayed = 0;
					foreach	($xmldata as $match) {
						//var_dump($match);
						$this->matchesplayed++;
						$themap = $match["map"];
						// parse up array if game was a teamgame
						if (isset($match["Team"]) || isset($match["team"])) {
							if (isset($match["team"])) $match["Team"] = $match["team"];
							// who's won the match?
							if ($match["Team"][0]["score"] > $match["Team"][1]["score"]) $won = 0;
							else $won = 1;
							$wonskiplist = array();
							$lostskiplist = array();
							foreach ($match["Team"] as $tkey => $team) {
								// set value for win-determination-hack
								$winnerteam = NULL;
								if ($won == $tkey) $winnerteam = TRUE;
								else $winnerteam = FALSE;
								if (!isset($team["player"]["stat"])) {
									// multiple players in team
									foreach ($team["player"] as $oneplayer) {
										// skiplist handling
										if (skipCheck($this->skiplists["ignoredplayernames"], $oneplayer["name"]))
											continue;
									
										if (!empty($oneplayer["clan"])) {
											$truncclan = substr($this->process_colorcodes($oneplayer["clan"]), 0, $this->configuration["GENERAL"]["snip_tags"]);
											$oneplayer["clan"] = $truncclan;
											// WIN/LOSS HACK
											if ($winnerteam === TRUE && !isset($wonskiplist[$truncclan])) {
												if (empty($this->cmatcheswon["won"][$truncclan])) { 
													$this->cmatcheswon["won"][$truncclan] = 1;
												}
												else $this->cmatcheswon["won"][$truncclan] += 1;
												$wonskiplist[$truncclan] = "skipme";
											}
											if ($winnerteam === FALSE && !isset($lostskiplist[$truncclan])) {
												if (empty($this->cmatcheswon["lost"][$truncclan]))  
													$this->cmatcheswon["lost"][$truncclan] = 1;
												else $this->cmatcheswon["lost"][$truncclan] += 1;
												$lostskiplist[$truncclan] = "skipme";
											}
										}
										
										$oneplayer["xmlfile"] = $match["xmlfile"];
										//if (strlen($oneplayer["guid"])<5) var_dump($xmldata);
										// if player already existing as object, add new info
										
										// if pdeterm_guid is 1 and players guid is empty, emulate
										if ($this->configuration["GENERAL"]["pdeterm_guid"] == 1 && empty($oneplayer["guid"])) $oneplayer["guid"] = substr(base64_encode($oneplayer["name"]), 0, 15)." (emulated)";
										
										$gotplayer = array_search($oneplayer["guid"], $this->players["playerlist"]);
										// add up match infos into array
										$oneplayer["map"] = $themap;
										if (is_numeric($gotplayer)) {
											$this->players[$gotplayer]->Pump_New_Stats($oneplayer);
										}
										else {
											// not existing, add new
											$newindex = count($this->players["playerlist"]);
											$this->players["playerlist"][$newindex] = $oneplayer["guid"];
											$this->players[$newindex] = new player($oneplayer, $this->configuration, $this->skiplists);
											$this->players[$newindex]->uniqueplid = base64_encode($oneplayer["guid"]);
										}
									}
								}
								else {
									// single player in team
									$oneplayer = $team["player"];
									// skiplist handling
									if (skipCheck($this->skiplists["ignoredplayernames"], $oneplayer["name"]))
										continue;
									
									if (!empty($oneplayer["clan"])) {
										$truncclan = substr($this->process_colorcodes($oneplayer["clan"]), 0, $this->configuration["GENERAL"]["snip_tags"]);										
										$oneplayer["clan"] = $truncclan;
										// WIN/LOSS HACK
										if ($winnerteam === TRUE && !isset($wonskiplist[$truncclan])) {
											if (empty($this->cmatcheswon["won"][$truncclan]))  
												$this->cmatcheswon["won"][$truncclan] = 1;
											else $this->cmatcheswon["won"][$truncclan] += 1;
											$wonskiplist[$truncclan] = "skipme";
										}
										if ($winnerteam === FALSE && !isset($lostskiplist[$truncclan])) {
											if (empty($this->cmatcheswon["lost"][$truncclan]))  
												$this->cmatcheswon["lost"][$truncclan] = 1;
											else $this->cmatcheswon["lost"][$truncclan] += 1;
											$lostskiplist[$truncclan] = "skipme";
										}
									}
									
									$oneplayer["xmlfile"] = $match["xmlfile"];
									
									// if pdeterm_guid is 1 and players guid is empty, emulate
									if ($this->configuration["GENERAL"]["pdeterm_guid"] == 1 && empty($oneplayer["guid"])) $oneplayer["guid"] = substr(base64_encode($oneplayer["name"]), 0, 15)." (emulated)";
									
									$gotplayer = array_search($oneplayer["guid"], $this->players["playerlist"]);
									// add up match infos into array
									$oneplayer["map"] = $themap;
									if (is_numeric($gotplayer)) {
										$this->players[$gotplayer]->Pump_New_Stats($oneplayer);
									}
									else {
										// not existing, add new
										$newindex = count($this->players["playerlist"]);
										$this->players["playerlist"][$newindex] = $oneplayer["guid"];
										$this->players[$newindex] = new player($oneplayer, $this->configuration, $this->skiplists);
										$this->players[$newindex]->uniqueplid = base64_encode($oneplayer["guid"]);
									}
								}
							}
						}
						else {
							// run through matchdata (players)
							if (!isset($match["player"]["stat"])) {
								// multiple players in match
								foreach ($match["player"] as $oneplayer) {
									$oneplayer["xmlfile"] = $match["xmlfile"];
									// skiplist handling
									if (skipCheck($this->skiplists["ignoredplayernames"], $oneplayer["name"]))
										continue;
									
									//if (strlen($oneplayer["guid"])<5) var_dump($xmldata);
									// if player already existing as object, add new info
									
									// if pdeterm_guid is 1 and players guid is empty, emulate
									if ($this->configuration["GENERAL"]["pdeterm_guid"] == 1 && empty($oneplayer["guid"])) $oneplayer["guid"] = substr(base64_encode($oneplayer["name"]), 0, 15)." (emulated)";
									
									$gotplayer = array_search($oneplayer["guid"], $this->players["playerlist"]);
									$oneplayer["map"] = $themap;
									if (is_numeric($gotplayer)) {
										$this->players[$gotplayer]->Pump_New_Stats($oneplayer);
									}
									else {
										// not existing, add new
										$newindex = count($this->players["playerlist"]);
										$this->players["playerlist"][$newindex] = $oneplayer["guid"];
										$this->players[$newindex] = new player($oneplayer, $this->configuration, $this->skiplists);
										$this->players[$newindex]->uniqueplid = base64_encode($oneplayer["guid"]);
									}
								}
							}
							else {
								// single player in match
								$oneplayer = $match["player"];
								// skiplist handling
								if (skipCheck($this->skiplists["ignoredplayernames"], $oneplayer["name"]))
									continue;
								
								$oneplayer["xmlfile"] = $match["xmlfile"];
								//if (strlen($oneplayer["guid"])<5) var_dump($xmldata);
								// if player already existing as object, add new info
								
								// if pdeterm_guid is 1 and players guid is empty, emulate
								if ($this->configuration["GENERAL"]["pdeterm_guid"] == 1 && empty($oneplayer["guid"])) $oneplayer["guid"] = substr(base64_encode($oneplayer["name"]), 0, 15)." (emulated)";
								
								$gotplayer = array_search($oneplayer["guid"], $this->players["playerlist"]);
								$oneplayer["map"] = $themap;
								if (is_numeric($gotplayer)) {
									$this->players[$gotplayer]->Pump_New_Stats($oneplayer);
								}
								else {
									// not existing, add new
									$newindex = count($this->players["playerlist"]);
									$this->players["playerlist"][$newindex] = $oneplayer["guid"];
									$this->players[$newindex] = new player($oneplayer, $this->configuration, $this->skiplists);
									$this->players[$newindex]->uniqueplid = base64_encode($oneplayer["guid"]);
								}
							}
						}
					}
				}
			}
		}
	}
	
	function Calculate_Player_Stats() {
		foreach ($this->players as $key => $player) {
			if (is_numeric($key)) $this->players[$key]->Calculate_Stats();
		}
	}
		
	function Calculate_Clan_Stats() {
		// run through playerlist and build clans
		$runcount = 0;
		foreach ($this->players as $index => $player) {
			if (is_numeric($index) && !empty($player->clan)) {
				$gotclan = array_search($player->clan, $this->clans["clanlist"]);
				if (is_numeric($gotclan)) {
					$this->clans[$gotclan]["players"][] = $index;
					$this->clans[$gotclan]["efficiency"] = (($this->clans[$gotclan]["efficiency"] + $player->overallefficiency) / 2);
					if (isset($this->clans[$gotclan]["bestplayer"]) && $this->players[$this->clans[$gotclan]["bestplayer"]]->overallefficiency < $player->overallefficiency) $this->clans[$gotclan]["bestplayer"] = $index;
					$this->clans[$gotclan]["kills"] += $player->kills;
					$this->clans[$gotclan]["deaths"] += $player->deaths;
					$this->clans[$gotclan]["suicides"] += $player->suicides;
					$this->clans[$gotclan]["score"] += $player->score;
					$this->clans[$gotclan]["damagegiven"] = $player->damagegiven;
					$this->clans[$gotclan]["damagetaken"] = $player->damagetaken;
					
					// fill up weapon efficiency array
					foreach ($player->weapons as $windex => $weapon) {
						if (is_numeric($windex)) {
							$gotweapon = array_search($weapon["name"], $this->clans[$gotclan]["weapons"]["weaponlist"]);
							if (is_numeric($gotweapon) && $weapon["shots"] >0) {
								$this->clans[$gotclan]["weapons"][$gotweapon] = ((($this->clans[$gotclan]["weapons"][$gotweapon]) + $weapon["efficiency"]) / 2);
							}
							else {
								$newwindex = count($this->clans[$gotclan]["weapons"]["weaponlist"]);
								$this->clans[$gotclan]["weapons"]["weaponlist"][$newwindex] = $weapon["name"];
								if (!empty($weapon["efficiency"])) $this->clans[$gotclan]["weapons"][$newwindex] = $weapon["efficiency"];
								else $this->clans[$gotclan]["weapons"][$newwindex] = "0";
							}
						}
					}
					
					// fill up map efficiency array
					foreach ($player->maps as $mindex => $map) {
						if (is_numeric($mindex)) {
							$gotmap = array_search($map["name"], $this->clans[$gotclan]["maps"]["maplist"]);
							if (is_numeric($gotmap)) {
								$this->clans[$gotclan]["maps"][$gotmap]["count"] += 1;
								$this->clans[$gotclan]["maps"][$gotmap]["efficiency_added"] += $map["efficiency"];
							}
							else {
								$newmindex = count($this->clans[$gotclan]["maps"]["maplist"]);
								$this->clans[$gotclan]["maps"]["maplist"][$newmindex] = $map["name"];
								$this->clans[$gotclan]["maps"][$newmindex]["count"] = 1;
								$this->clans[$gotclan]["maps"][$newmindex]["efficiency_added"] = $map["efficiency"];
							}
						}
					}
				}
				else {
					$newindex = count($this->clans["clanlist"]);
					$this->clans["clanlist"][$newindex] = $player->clan;
					$this->clans[$newindex]["players"][] = $index;
					$this->clans[$newindex]["weapons"] = array();
					$this->clans[$newindex]["maps"] = array();
					$this->clans[$newindex]["weapons"]["weaponlist"] = array();
					$this->clans[$newindex]["maps"]["maplist"] = array();
					$this->clans[$newindex]["efficiency"] = $player->overallefficiency;
					if (isset($this->clans[$newindex]["bestplayer"]) && $this->players[$this->clans[$newindex]["bestplayer"]]->overallefficiency < $player->overallefficiency) $this->clans[$newindex]["bestplayer"] = $index;
					$this->clans[$newindex]["name"] = $player->clan;
					$this->clans[$newindex]["kills"] = $player->kills;
					$this->clans[$newindex]["deaths"] = $player->deaths;
					$this->clans[$newindex]["suicides"] = $player->suicides;
					$this->clans[$newindex]["score"] = $player->score;
					$this->clans[$newindex]["damagegiven"] = $player->damagegiven;
					$this->clans[$newindex]["damagetaken"] = $player->damagetaken;
					
					// fill up weapon efficiency array
					foreach ($player->weapons as $windex => $weapon) {
						if (is_numeric($windex)) {
							$gotweapon = array_search($weapon["name"], $this->clans[$newindex]["weapons"]["weaponlist"]);
							if (is_numeric($gotweapon) && $weapon["shots"] >0) {
								$this->clans[$newindex]["weapons"][$gotweapon] = ((($this->clans[$newindex]["weapons"][$gotweapon]) + $weapon["efficiency"]) / 2);
							}
							else {
								$newwindex = count($this->clans[$newindex]["weapons"]["weaponlist"]);
								$this->clans[$newindex]["weapons"]["weaponlist"][$newwindex] = $weapon["name"];
								if (!empty($weapon["efficiency"])) $this->clans[$newindex]["weapons"][$newwindex] = $weapon["efficiency"];
								else $this->clans[$newindex]["weapons"][$newwindex] = "0";
							}
						}
					}
					
					// fill up map efficiency array
					foreach ($player->maps as $mindex => $map) {
						if (is_numeric($mindex)) {
							$gotmap = array_search($map["name"], $this->clans[$newindex]["maps"]["maplist"]);
							if (is_numeric($gotmap)) {
								$this->clans[$newindex]["maps"][$gotmap]["count"] += 1;
								$this->clans[$newindex]["maps"][$gotmap]["efficiency_added"] += $map["efficiency"];
							}
							else {
								$newmindex = count($this->clans[$newindex]["maps"]["maplist"]);
								$this->clans[$newindex]["maps"]["maplist"][$newmindex] = $map["name"];
								$this->clans[$newindex]["maps"][$newmindex]["count"] = 1;
								$this->clans[$newindex]["maps"][$newmindex]["efficiency_added"] = $map["efficiency"];
							}
						}
					}
				}
			}
		}
		// got clan array with basic infos, now calculate stats
		if (count($this->clans) >1) {
			foreach ($this->clans as $index => $clan) {
				if (is_numeric($index)) {
					// calculate best weapon
					$bestweapon = 0;
					foreach ($clan["weapons"] as $key => $accuracy) {
						if (is_numeric($key)) {
							if ($clan["weapons"][$bestweapon] < $accuracy) $bestweapon = $key;
						}
					}
					
					// calculate map stats then best map
					$lasteff = 0;
					$bestmap = 0;
					foreach ($clan["maps"] as $key => $map) {
						if (is_numeric($key)) {
							$this->clans[$index]["maps"][$key] = ($map["efficiency_added"] / $map["count"]);
							if ($this->clans[$index]["maps"][$key]["efficiency"] > $lasteff) {
								$lasteff = $this->clans[$index]["maps"][$key]["efficiency"];
								$bestmap = $key;
							}
						}
					}
					$this->clans[$index]["bestmap"] = $bestmap;
					$this->clans[$index]["bestweapon"] = $bestweapon;
				}
			}
		}
	}
	
	function Get_Top_Players() {	
		$determtype = $this->tpdetermtype;
		// run through player classes and collect top players
		$efflist = array();
		foreach ($this->players as $key => $player) {
			if (is_numeric($key) && !is_null($player->$determtype)) {
				$efflist[$key] = $player->$determtype;
			}
		}
		arsort($efflist);
		$count = 0;
		foreach ($efflist as $playerkey => $eff) {
			// are we inside the top-players count definition of ini?
			if ($count > $this->configuration["GENERAL"]["top_count"] && !isset($_REQUEST["showall"])) break;
			$this->topplayers[$playerkey] = $eff;
			$count++;
		}
	}
	
	function Get_Top_Players_Clans() {
		$determtype = $this->tpdetermtype;
		// run through clans' player classes and collect top players
		if (count($this->clans > 1)) {
			foreach ($this->clans as $clkey => $clan) {
				$efflist = array();
				if (isset($clan["players"])) {
					if (is_array($clan["players"])) {
						foreach ($clan["players"] as $key => $player) {
							if (is_numeric($key)) { 
								$efflist[$player] = $this->players[$player]->$determtype;
							}
						}
					}
				}
				arsort($efflist);
				$count = 0;
				foreach ($efflist as $playerkey => $eff) {
					// are we inside the top-players count definition of ini?
					if ($count > $this->configuration["GENERAL"]["top_count"]) break;
					$this->clans[$clkey]["topplayers"][$playerkey] = $eff;
				}
			}
		}
	}
	
	function Get_Top_Clans() {
		$determtype = $this->tcdetermtype;
		// run through clans array and collect top clans
		$efflist = array();
		foreach ($this->clans as $key => $clan) {
			if (is_numeric($key) && !is_null($clan[$determtype])) {
				$efflist[$key] = $clan[$determtype];
			}
		}
		arsort($efflist);
		$count = 0;
		foreach ($efflist as $clankey => $eff) {
			// are we inside the top-count count definition of ini?
			if ($count > $this->configuration["GENERAL"]["top_count"] && !isset($_REQUEST["showall"])) break;
			$this->topclans[$clankey] = $eff;
			$count++;
		}
	}
	
	function buildXMLlist() {
		// get xml files of all players
		$xmllist = array();
		foreach ($this->players as $data) {
			foreach ($data->xmlfiles as $xmlfile) {
				if (!is_numeric(array_search($xmlfile, $xmllist))) $xmllist[] = $xmlfile;
			}
		}
		$this->XMLlist = $xmllist;
	}
	
	function pumpOutError() {
		$varlist["toplists"] = "There was a fundamental error when booting up the script!";
		$varlist["content"] = "<font color=\"red\"><b>$this->procError</b></font>";
		$varlist["classversion"] = $this->getScriptVersion();
		$indexout = $this->Parse_Template(TEMPLATEPATH."index.tpl", $varlist);
		echo $indexout;
		die();
	}
	
	function Generate_Output() {
		global $script_time;
		// parse topplayer stats
		$toprepeatout = "";
		if (count($this->players)>1) {
			// do we have an error?
			if (!empty($this->procError)) {
				$this->pumpOutError();
			}
			else {
				if ($this->outputtype == "players") {
					//
					// if outputtype players ---
					//
					
					// if showall was clicked be sure to reparse if player clicks on normal top10
					$doreparse = isset($_REQUEST["showall"])?"&reparse":NULL;								
					foreach ($this->topplayers as $playerkey => $eff) {
						$varlist = array();
						$varlist["name"] = $this->Process_Colorcodes($this->players[$playerkey]->name);
	
						// name too long?
						if (strlen($varlist["name"]) > $this->configuration["GENERAL"]["tp_snip_tags"]) $varlist["name"] = (substr($varlist["name"], 0, ($this->configuration["GENERAL"]["tp_snip_tags"]-3)))."...";
						// name empty?
						if (strlen($varlist["name"]) == 0 || $varlist["name"] == " ") $varlist["name"] = "__empty__";
						// name looks like html tag?
						if (strstr($varlist["name"], "<") || strstr($varlist["name"], ">")) $varlist["name"] = htmlentities($varlist["name"]);
						$varlist["name"] = "<a href=\"?detail=$playerkey$doreparse\">{$varlist['name']}</a>";
						
						$varlist["clan"] = empty($this->players[$playerkey]->clan)?"-":$this->Process_Colorcodes($this->players[$playerkey]->clan);
						// clan too lonmg?
						if (strlen($varlist["clan"]) > $this->configuration["GENERAL"]["tp_snip_tags"]) $varlist["clan"] = (substr($varlist["clan"], 0, ($this->configuration["GENERAL"]["tp_snip_tags"]-3)))."...";
						// clan empty?
						if (strlen($varlist["clan"]) == 0 || $varlist["clan"] == "") $varlist["clan"] = "__empty__";
						// clan looks like html tag?
						if (strstr($varlist["clan"], "<") || strstr($varlist["clan"], ">")) $varlist["clan"] = htmlentities($varlist["clan"]);
						
						// got details for clan?
						$probclan = array_search($this->players[$playerkey]->clan, $this->clans["clanlist"]);
						if (is_numeric($probclan)) $varlist["clan"] = "<a href=\"?clandetail=$probclan$doreparse\">{$varlist['clan']}</a>";
						$varlist["overallefficiency"] = round($this->players[$playerkey]->overallefficiency, 2);
						$varlist["playerefficiency"] = round($this->players[$playerkey]->playerefficiency, 2);
						$varlist["kills"] = $this->players[$playerkey]->kills;
						$varlist["deaths"] = $this->players[$playerkey]->deaths;
						$varlist["dnet"] = $this->players[$playerkey]->dnet;
						
						$toprepeatout .= $this->Parse_Template(TEMPLATEPATH."top_players_repeat.tpl", $varlist);
					}
					$varlist = array();
					$varlist["top_players_repeat"] = $toprepeatout;
					
					if (!is_null($doreparse)) {
						$varlist["toptype"] = "<a href=\"?top=players$doreparse\">Top {$this->configuration['GENERAL']['top_count']} $this->outputtype</a> | <a href=\"?top=clans$doreparse\">clans</a> | <a href=\"?top=players&showall&reparse\">All</a>";
					}
					else {
						$varlist["toptype"] = "Top {$this->configuration['GENERAL']['top_count']} $this->outputtype | <a href=\"?top=clans$doreparse\">clans</a> | <a href=\"?top=players&showall&reparse\">All</a>";
					}
					
					// servername
					$varlist["serverfor"] = $this->Process_Colorcodes($this->configuration["GENERAL"]["servername"]);
					if (strlen($varlist["serverfor"]) > $this->configuration["GENERAL"]["crop_servername"]) $varlist["serverfor"] = substr($varlist["serverfor"], 0, $this->configuration["GENERAL"]["crop_servername"]-3)."...";
					
					// underlined top-determination-type
					
					$varlist["orderbyoveff"] = "i-title";
					$varlist["orderbypleff"] = "i-title";
					$varlist["orderbykills"] = "i-title";
					$varlist["orderbydeaths"] = "i-title";
					$varlist["orderbydnet"] = "i-title";
					if ($this->tpdetermtype == "overallefficiency") $varlist["orderbyoveff"] = 'orderby';
					elseif ($this->tpdetermtype == "playerefficiency") $varlist["orderbypleff"] = 'orderby';
					elseif ($this->tpdetermtype == "kills") $varlist["orderbykills"] = 'orderby"';
					elseif ($this->tpdetermtype == "deaths") $varlist["orderbydeaths"] = 'orderby';
					elseif ($this->tpdetermtype == "dnet") $varlist["orderbydnet"] = 'orderby';
						
					// xml filelist
					if (!isset($_REQUEST["detail"]) && !isset($_REQUEST["clandetail"])) {
					$varlist["xmllist"] = "<select name=\"xmlfile\" onChange=\"javascript:loadLinkInFrame();\"><option selected disabled style=\"font-weight: bold;\">All available match-statistics</option><option style=\"font-weight: bold;\">Reload current file</option><option disabled>---------</option>";
						$thexmllist = $this->XMLlist;
						sort($thexmllist);
						$thexmllist = array_reverse($thexmllist);
						foreach ($thexmllist as $matchfile) {
							$matchxml = $this->refurbishXMLdate(str_replace($this->configuration["STATFOLDERS"]["folder1"], "", $matchfile));
							$varlist["xmllist"] .= "<option value=\"$matchfile\" style=\"font-weight:normal;\">$matchxml</option>";
						}
						$varlist["xmllist"] .= "</select>";
						
						$varlist["xmlframe"] = '<table cellspacing="0" cellpadding="0" width="100%" height="100%" class="stats_infotop"  id="statsubTR" style="display:none; table-layout:fixed;">
						  <tr>
							<td class="stats_title" id="frametd">XML Statview (<span class="i-title">Match from:</span> <span id="statview_name" class="i-title"></span>)
							</td>
							<td class="stats_title" align="right">
							<a onClick="javascript:document.getElementById(\'statsubTR\').style.display = \'none\'; document.getElementsByName(\'xmlfile\')[0].options[0].selected = true;" style="cursor: pointer;">Close Matchview</a>
							</td>
						  </tr>
						  <tr>
							<td class="stats_title" id="frametd" colspan="2"><iframe id="statinclude" height="100%" width="100%" style="border:none; position:relative;" scrolling="no" allowtransparency="1" onLoad="javascript:setTimeout(\'iFrameHeight()\', 100)" frameborder="0"></iframe></td>
						  </tr>
						</table>';
						
					} else {
						$varlist["xmllist"] = "<br />";
						$varlist["xmlframe"] = "";
					}
						
					// build expand/contract link if our playercount is bigger than topmax
					if (count($this->topplayers) > $this->configuration["GENERAL"]["top_count"]) {
						if (isset($_REQUEST["showall"])) {
							// we are showing all, show contract link
							$varlist["expandcontract"] = '<a href="?top=players&reparse" style="text-decoration:none"><span style="text-decoration:none"><img src="../img/arrup.gif" />&#160; Contract (show only '.$this->configuration["GENERAL"]["top_count"].' entries)</span></a>';
						}
						else {
							// show expand link
							$varlist["expandcontract"] = '<a href="?top=players&showall&reparse" style="text-decoration:none"><span style="text-decoration:none"><img src="../img/arrdown.gif" />&#160; Expand (showing '.$this->configuration["GENERAL"]["top_count"].' entries)</span></a>';
						}
					}
					else $varlist["expandcontract"] = "";
					
					$topbasicout = $this->Parse_Template(TEMPLATEPATH."top_players_basic.tpl", $varlist);
				}
				else {
					//
					// if outputtype clans ---
					//
					foreach ($this->topclans as $clankey => $eff) {
						$varlist = array();
						$varlist["name"] = $this->Process_Colorcodes($this->clans[$clankey]["name"]);
						// name too long?
						if (strlen($varlist["name"]) > $this->configuration["GENERAL"]["snip_tags"]) $varlist["name"] = (substr($varlist["name"], 0, ($this->configuration["GENERAL"]["snip_tags"]-3)))."...";
						// name empty?
						if (strlen($varlist["name"]) == 0 || $varlist["name"] == " ") $varlist["name"] = "__empty__";
						// name looks like html tag?
						if (strstr($varlist["name"], "<") || strstr($varlist["name"], ">")) $varlist["name"] = htmlentities($varlist["name"]);
						$varlist["name"] = "<a href=\"?clandetail=$clankey\">{$varlist['name']}</a>";
						$varlist["efficiency"] = round($this->clans[$clankey]["efficiency"], 2);
						$varlist["bestmap"] = $this->clans[$clankey]["maps"]["maplist"][$this->clans[$clankey]["bestmap"]];
						$varlist["playercount"] = count($this->clans[$clankey]["players"]);
						$varlist["kills"] = $this->clans[$clankey]["kills"];
						$varlist["deaths"] = $this->clans[$clankey]["deaths"];
						$toprepeatout .= $this->Parse_Template(TEMPLATEPATH."top_clans_repeat.tpl", $varlist);
					}
					$varlist = array();
					$varlist["top_clans_repeat"] = $toprepeatout;
					// if showall was clicked be sure to reparse if player clicks on normal top10
					$doreparse = isset($_REQUEST["showall"])?"&reparse":NULL;
					
					if (!is_null($doreparse)) {
						$varlist["toptype"] = "<a href=\"?top=players$doreparse\">Top {$this->configuration['GENERAL']['top_count']} players</a> | <a href=\"?top=clans$doreparse\">clans</a> | <a href=\"?top=players&showall&reparse\">All</a>";
					}
					else {
						$varlist["toptype"] = "<a href=\"?top=players$doreparse\">Top {$this->configuration['GENERAL']['top_count']} players</a> | ".$this->outputtype." | <a href=\"?top=clans&showall&reparse\">All</a>";
					}
					// servername
					$varlist["serverfor"] = $this->Process_Colorcodes($this->configuration["GENERAL"]["servername"]);
					if (strlen($varlist["serverfor"]) > $this->configuration["GENERAL"]["crop_servername"]) $varlist["serverfor"] = substr($varlist["serverfor"], 0, $this->configuration["GENERAL"]["crop_servername"]-3)."...";
					
					// underlined top-determination-type
					$varlist["orderbyeff"] = "i-title";
					$varlist["orderbykills"] = "i-title";
					$varlist["orderbydeaths"] = "i-title";
					if ($this->tcdetermtype == "efficiency") $varlist["orderbyeff"] = 'orderby';
					elseif ($this->tcdetermtype == "kills") $varlist["orderbykills"] = 'orderby"';
					elseif ($this->tcdetermtype == "deaths") $varlist["orderbydeaths"] = 'orderby';
					
					// xml filelist
					if (!isset($_REQUEST["detail"]) && !isset($_REQUEST["clandetail"])) {
					$varlist["xmllist"] = "<select name=\"xmlfile\" onChange=\"javascript:loadLinkInFrame();\"><option selected disabled style=\"font-weight: bold;\">All available match-statistics</option><option style=\"font-weight: bold;\">Reload current file</option><option disabled>---------</option>";
						$thexmllist = $this->XMLlist;
						sort($thexmllist);
						$thexmllist = array_reverse($thexmllist);
						foreach ($thexmllist as $matchfile) {
							$matchxml = $this->refurbishXMLdate(str_replace($this->configuration["STATFOLDERS"]["folder1"], "", $matchfile));
							$varlist["xmllist"] .= "<option value=\"$matchfile\" style=\"font-weight:normal;\">$matchxml</option>";
						}
						$varlist["xmllist"] .= "</select>";
						
						$varlist["xmlframe"] = '<table cellspacing="0" cellpadding="0" width="100%" height="100%" class="stats_infotop"  id="statsubTR" style="display:none; table-layout:fixed;">
						  <tr>
							<td class="stats_title" id="frametd">XML Statview (<span class="i-title">Match from:</span> <span id="statview_name" class="i-title"></span>)
							</td>
							<td class="stats_title" align="right">
							<a onClick="javascript:document.getElementById(\'statsubTR\').style.display = \'none\'; document.getElementsByName(\'xmlfile\')[0].options[0].selected = true;" style="cursor: pointer;">Close Matchview</a>
							</td>
						  </tr>
						  <tr>
							<td class="stats_title" id="frametd" colspan="2"><iframe id="statinclude" height="100%" width="100%" style="border:none; position:relative;" scrolling="no" allowtransparency="1" onLoad="javascript:setTimeout(\'iFrameHeight()\', 100)" frameborder="0"></iframe></td>
						  </tr>
						</table>';
						
					} else {
						$varlist["xmllist"] = "<br />";
						$varlist["xmlframe"] = "";
					}
					
					// build expand/contract link if our playercount is bigger than topmax
					if (count($this->topclans) > $this->configuration["GENERAL"]["top_count"]) {
						if (isset($_REQUEST["showall"])) {
							// we are showing all, show contract link
							$varlist["expandcontract"] = '<a href="?top=clans&reparse" style="text-decoration:none"><span style="text-decoration:none"><img src="../img/arrup.gif" />&#160; Contract (show only '.$this->configuration["GENERAL"]["top_count"].' entries)</span></a>';
						}
						else {
							// show expand link
							$varlist["expandcontract"] = '<a href="?top=clans&showall&reparse" style="text-decoration:none"><span style="text-decoration:none"><img src="../img/arrdown.gif" />&#160; Expand (showing '.$this->configuration["GENERAL"]["top_count"].' entries)</span></a>';
						}
					}
					else $varlist["expandcontract"] = "";
					
					$topbasicout = $this->Parse_Template(TEMPLATEPATH."top_clans_basic.tpl", $varlist);
				}
				$varlist = array();
				
				$varlist["content"] = "";
				$newcont = "";
				
				// basic things parsed, do content
				if (isset($_REQUEST["detail"])) {
					//
					// if request = (player) DETAIL ---
					//
					if (!isset($this->players[$_REQUEST["detail"]])) $varlist["content"] = "Wrong Player specified.";
					else {
						$probclan = NULL;
						$theplayer = $this->players[$_REQUEST["detail"]];
						// get general info
						$varlist["name"] = $this->Process_Colorcodes($theplayer->name);
						// name looks like html tag?
						if (strstr($varlist["name"], "<") || strstr($varlist["name"], ">")) $varlist["name"] = htmlentities($varlist["name"]);

						$varlist["clanshort"] = $this->Process_Colorcodes($theplayer->clan);
						if (!empty($varlist["clanshort"])) $probclan = array_search($varlist["clanshort"], $this->clans["clanlist"]);
						// clan looks like html tag?
						if (strstr($varlist["clanshort"], "<") || strstr($varlist["clanshort"], ">")) $varlist["clanshort"] = htmlentities($varlist["clanshort"]);
						
						$varlist["clan"] = empty($varlist["clanshort"])?"":"of ".$varlist["clanshort"];

						$varlist["clanshort"] = is_numeric($probclan)?"<a href=\"?clandetail=$probclan\">".$varlist["clanshort"]."</a>":$varlist["clanshort"];
						$varlist["clanshort"] = empty($varlist["clanshort"])?"-":$varlist["clanshort"];
						$varlist["guid"] = $theplayer->guid;
						$varlist["kills"] = $theplayer->kills;
						$varlist["deaths"] = $theplayer->deaths;
						$varlist["score"] = $theplayer->score;
						$varlist["suicides"] = $theplayer->suicides;
						$varlist["thaws"] = $theplayer->thaws;
						$varlist["damagegiven"] = $theplayer->damagegiven;
						$varlist["damagetaken"] = $theplayer->damagetaken;
						$varlist["dnet"] = $theplayer->dnet;
						$varlist["bestweapon"] = $theplayer->weapons[$theplayer->bestweapon]["name"];
						$varlist["bestmap"] = $theplayer->maps[$theplayer->bestmap]["name"];
						$varlist["bestmapefficiency"] = round($theplayer->maps[$theplayer->bestmap]["efficiency"], 2);
						$varlist["playerefficiency"] = round($theplayer->playerefficiency, 2);
						$varlist["overallefficiency"] = round($theplayer->overallefficiency, 2);
						$varlist["uniqueplid"] = $theplayer->uniqueplid;
						$varlist["mostplayedmap"] = $theplayer->maps[$theplayer->mostplayedmap]["name"];
						$varlist["mostplayedmapcount"] = $theplayer->maps[$theplayer->mostplayedmap]["count"];
						$varlist["awardsearned"] = 0;
						foreach ($theplayer->awards as $key => $award) {
							if (is_numeric($key)) $varlist["awardsearned"] += $award["count"];
						}
						
						// get weapon stats
						$weaprepeatout = "";
						foreach ($theplayer->weapons as $key => $weapon) {
							if (is_numeric($key)) {
								$weaptplvars = array();
								$weaptplvars["weaponimage"] = is_file(IMAGEPATH."weapons/{$weapon['name']}.gif")?"<img src=\"".IMAGEPATH."weapons/{$weapon['name']}.gif\" border=\"0\">":"";
								$weaptplvars["weaponname"] = $weapon["name"];
								$weaptplvars["shots"] = $weapon["shots"];
								$weaptplvars["hits"] = $weapon["hits"];
								if (!isset($weapon["efficiency"]) || is_null($weapon["efficiency"])) $weaptplvars["efficiency"] = "0";
								else $weaptplvars["efficiency"] = round($weapon["efficiency"], 2);
								$weaprepeatout .= $this->Parse_Template(TEMPLATEPATH."pl_details_weapons_repeat.tpl", $weaptplvars);
							}
						}
						
						// get awards stats
						$awardsrepeatout = "";
						foreach ($theplayer->awards as $key => $award) {
							if (is_numeric($key)) {
								$awardtplvars = array();
								$award['lowname'] = strtolower($award["name"]);
								// RAVEN TE NOOB
								if ($award["lowname"] == "critical failure") $awardtplvars["awardimage"] = "<a href=\"".IMAGEPATH."awards/raven_hi_res.gif\" target=\"_blank\"><img src=\"".IMAGEPATH."awards/{$award['name']}.gif\" border=\"0\"></a>";
								else $awardtplvars["awardimage"] = is_file("".IMAGEPATH."awards/{$award['name']}.gif")?"<img src=\"".IMAGEPATH."awards/{$award['name']}.gif\" border=\"0\">":"";
								$awardtplvars["name"] = $this->Refurbish_Award($award["name"]);
								$awardtplvars["count"] = $award["count"];
								$awardsrepeatout .= $this->Parse_Template(TEMPLATEPATH."pl_details_awards_repeat.tpl", $awardtplvars);
							}
						}
						
						// get maps stats
						$mapsrepeatout = "";
						foreach ($theplayer->maps as $key => $map) {
							if (is_numeric($key)) {
								$maptplvars = array();
								$maptplvars["name"] = $map["name"];
								$maptplvars["count"] = $map["count"];
								$maptplvars["kills"] = $map["kills"];
								$maptplvars["deaths"] = $map["deaths"];
								$maptplvars["thaws"] = $map["thaws"];
								$maptplvars["efficiency"] = round($map["efficiency"], 2);
								$mapsrepeatout .= $this->Parse_Template(TEMPLATEPATH."pl_details_maps_repeat.tpl", $maptplvars);
							}
						}
						
						// get alternative nicks
						$altnicks = array();
						$gotfirst = FALSE;
						if (count($theplayer->altnicks["nicklist"])>0) {
							foreach ($theplayer->altnicks["nicklist"] as $key => $nick) {
								// replace old strong tags (dirty)
								$nick = str_replace(array("<strong>", "</strong>"), "", $nick);
								// value looks like html tag?
								if (strstr($nick, "<") || strstr($nick, ">")) $nick = htmlentities($nick);
								if (!$gotfirst) {
									$altnicks[] = "<strong>$nick</strong> ({$theplayer->altnicks[$key]['count']})";
									$gotfirst = TRUE;
								}
								else $altnicks[] = "$nick ({$theplayer->altnicks[$key]['count']})";
							}
						}
						$varlist["pl_details_altnicks"] = implode(", ", $altnicks);
						$varlist["pl_details_altnicks"] = empty($varlist["pl_details_altnicks"])?"-":$varlist["pl_details_altnicks"];
	
						// get alternative clantags
						$alttags = array();
						$gotfirst = FALSE;
						if (count($theplayer->altclantags["taglist"])>0) {
							foreach ($theplayer->altclantags["taglist"] as $key => $tag) {
								// replace old strong tags (dirty)
								$tag = str_replace(array("<strong>", "</strong>"), "", $tag);
								// value looks like html tag?
								if (strstr($tag, "<") || strstr($tag, ">")) $tag = htmlentities($tag);
								if (!$gotfirst) {
									$alttags[] = "<strong>$tag</strong> ({$theplayer->altclantags[$key]['count']})";
									$gotfirst = TRUE;
								}
								else $alttags[] = "$tag ({$theplayer->altclantags[$key]['count']})";
							}
						}
						$varlist["pl_details_alttags"] = implode(", ", $alttags);
						$varlist["pl_details_alttags"] = empty($varlist["pl_details_alttags"])?"-":$varlist["pl_details_alttags"];
						
						$varlist["pl_details_maps_repeat"] = $mapsrepeatout;
						$varlist["pl_details_awards_repeat"] = $awardsrepeatout;				
						$varlist["pl_details_weapons_repeat"] = $weaprepeatout;
						
							
						
						// xml filelist
						$varlist["matchlist"] = "<select name=\"xmlfile\" onChange=\"javascript:loadLinkInFrame();\"><option selected disabled>All matches of {$varlist['name']}</option><option>Reload current file</option><option disabled>---------</option>";
						
						foreach ($theplayer->xmlfiles as $matchfile) {
							$matchxml = $this->refurbishXMLdate(str_replace($this->configuration["STATFOLDERS"]["folder1"], "", $matchfile));
							$varlist["matchlist"] .= "<option value=\"$matchfile\" style=\"font-weight: normal;\">$matchxml</option>";
						}
						$varlist["matchlist"] .= "</select>";
					
						
						// kill empty values
						foreach($varlist as $key => $var) {
							if (is_null($var)) $varlist[$key] = "0";
						}
			
						$newcont .= $this->Parse_Template(TEMPLATEPATH."pl_details_basic.tpl", $varlist);
						$varlist = array();
						$varlist["content"] = $newcont;
					}
				}
				elseif (isset($_REQUEST["clandetail"])) {
					//
					// if request = CLANDETAIL ---
					//
					if (!isset($this->clans[$_REQUEST["clandetail"]])) $varlist["content"] = "Wrong Clan specified.";
					else {
						$theclan = $this->clans[$_REQUEST["clandetail"]];
						// get general info
						$varlist["name"] = $this->Process_Colorcodes($theclan["name"]);
						// name looks like html tag?
						if (strstr($varlist["name"], "<") || strstr($varlist["name"], ">")) $varlist["name"] = htmlentities($varlist["name"]);
						$varlist["playercount"] = count($theclan["players"]);
						$varlist["kills"] = $theclan["kills"];
						$varlist["deaths"] = $theclan["deaths"];
						$varlist["score"] = $theclan["score"];
						$varlist["suicides"] = $theclan["suicides"];
						$varlist["thaws"] = $theclan["thaws"];
						$varlist["damagegiven"] = $theclan["damagegiven"];
						$varlist["damagetaken"] = $theclan["damagetaken"];
						$varlist["bestweapon"] = $theclan["weapons"]["weaponlist"][$theclan["bestweapon"]];
						$varlist["bestweaponeff"] = round($theclan["weapons"][$theclan["bestweapon"]], 2);
						$varlist["bestmap"] = $theclan["maps"]["maplist"][$theclan["bestmap"]];
						$varlist["bestmapefficiency"] = round($theclan["maps"][$theclan["bestmap"]], 2);
						$varlist["efficiency"] = round($theclan["efficiency"], 2);
						
						$varlist["matcheswon"] = empty($this->cmatcheswon["won"][$varlist["name"]])?0:$this->cmatcheswon["won"][$varlist["name"]];
						$varlist["matcheslost"] = empty($this->cmatcheswon["lost"][$varlist["name"]])?0:$this->cmatcheswon["lost"][$varlist["name"]];
						
						$subpllistout = "";
						foreach ($theclan["topplayers"] as $playerkey => $eff) {
							$subpllist["name"] = $this->Process_Colorcodes($this->players[$playerkey]->name);
							// name too long?
							if (strlen($subpllist["name"]) > $this->configuration["GENERAL"]["snip_tags"]) $subpllist["name"] = (substr($subpllist["name"], 0, ($this->configuration["GENERAL"]["snip_tags"]-3)))."...";
							// name looks like html tag?
							if (strstr($subpllist["name"], "<") || strstr($subpllist["name"], ">")) $subpllist["name"] = htmlentities($subpllist["name"]);
							$subpllist["name"] = "<a href=\"?detail=$playerkey\">{$subpllist['name']}</a>";
							$subpllist["clan"] = empty($this->players[$playerkey]->clan)?"-":$this->Process_Colorcodes($this->players[$playerkey]->clan);
							
							// clan looks like html tag?
							if (strstr($subpllist["clan"], "<") || strstr($subpllist["clan"], ">")) $subpllist["clan"] = htmlentities($subpllist["clan"]);
							
							$subpllist["bestweapon"] = $this->players[$playerkey]->weapons[$this->players[$playerkey]->bestweapon]["name"];
							$subpllist["bestweapon"] = empty($subpllist["bestweapon"])?"-":$subpllist["bestweapon"];
							$subpllist["bestweapimg"] = is_file(IMAGEPATH."weapons/{$subpllist['bestweapon']}.gif")?"<img src=\"".IMAGEPATH."weapons/{$subpllist['bestweapon']}.gif\" border=\"0\">":"";
							$subpllist["bestweaponeff"] = round($this->players[$playerkey]->weapons[$this->players[$playerkey]->bestweapon]["efficiency"], 2);
							$subpllist["overallefficiency"] = round($this->players[$playerkey]->overallefficiency, 2);
							$subpllist["playerefficiency"] = round($this->players[$playerkey]->playerefficiency, 2);
							$subpllist["kills"] = $this->players[$playerkey]->kills;
							$subpllist["deaths"] = $this->players[$playerkey]->deaths;
							$subpllistout .= $this->Parse_Template(TEMPLATEPATH."clan_details_players_repeat.tpl", $subpllist);
						}
						
						$varlist["clan_details_players_repeat"] = $subpllistout;
						
						// kill empty values
						foreach($varlist as $key => $var) {
							if (is_null($var)) $varlist[$key] = "0";
						}
						
						// underlined top-determination-type
						if ($this->tpdetermtype == "overallefficiency") $varlist["orderbyoveff"] = ' style="text-decoration:underline"';
						elseif ($this->tpdetermtype == "playerefficiency") $varlist["orderbypleff"] = ' style="text-decoration:underline"';
						elseif ($this->tpdetermtype == "kills") $varlist["orderbykills"] = ' style="text-decoration:underline"';
						elseif ($this->tpdetermtype == "deaths") $varlist["orderbydeaths"] = ' style="text-decoration:underline"';
						
						$varlist["orderbyoveff"] = "i-title";
						$varlist["orderbypleff"] = "i-title";
						$varlist["orderbykills"] = "i-title";
						$varlist["orderbydeaths"] = "i-title";
						if ($this->tpdetermtype == "overallefficiency") $varlist["orderbyoveff"] = 'orderby';
						if ($this->tpdetermtype == "playerefficiency") $varlist["orderbypleff"] = 'orderby';
						elseif ($this->tpdetermtype == "kills") $varlist["orderbykills"] = 'orderby"';
						elseif ($this->tpdetermtype == "deaths") $varlist["orderbydeaths"] = 'orderby';
						
						// xml filelist
						$varlist["matchlist"] = "<select name=\"xmlfile\" onChange=\"javascript:loadLinkInFrame();\"><option selected disabled>All matches of {$varlist['name']}</option><option>Reload current file</option><option disabled>---------</option>";
						
						$thelist = array();
						foreach ($theclan["players"] as $player) {
							foreach ($this->players[$player]->xmlfiles as $xmlfile) {
								if (!is_numeric(array_search($xmlfile, $thelist))) {
									$thelist[] = $xmlfile;
									$matchxml = $this->refurbishXMLdate(str_replace($this->configuration["STATFOLDERS"]["folder1"], "", $xmlfile));
									$varlist["matchlist"] .= "<option value=\"$xmlfile\" style=\"font-weight: normal;\">$matchxml</option>";
								}
							}
						}
						$varlist["matchlist"] .= "</select>";
						
						$newcont .= $this->Parse_Template(TEMPLATEPATH."clan_details_basic.tpl", $varlist);
						$varlist = array();
						$varlist["content"] = $newcont;
					}
				}
				
				// process search
				if (isset($_REQUEST["s"])) {
					$needle = $_REQUEST["needle"];
					// lowercase needle
					$searchvars["playerresults"] = "<tr><td class=\"stats_header\" colspan=\"3\" style=\"border-top:none; border-bottom:none\">none</td></tr>";
					$searchvars["clanresults"] = "<tr><td class=\"stats_header\" colspan=\"3\" style=\"border-top:none; border-bottom:none\">none</td></tr>";
					if (!empty($needle) && $needle != "needle") {
						$result = $this->searchData($needle);
						if ($result["count"] == 0) $searchvars["foundentries"] = "No entries with content '$needle' found. Please try again.";
						else {
							$searchvars["foundentries"] = "Found {$result['count']} entries for your search with needle '$needle':";
							$searchvars["playerresults"] = "";
							$searchvars["clanresults"] = "";
							// players
							
							// compute relevances for players
							$relevancelist = array();
							foreach ($result["players"] as $index => $player) {
								$result["players"][$index] = $this->Process_Colorcodes($result["players"][$index]);
								$relevancelist[$index] = $this->computeSearchRelevance($result["players"][$index], $needle);
							}
							arsort($relevancelist);
							
							$plcnt = 0;
							foreach ($relevancelist as $index => $relevance) {
								$plcnt++;
								$subsrchvars = array();
								$subsrchvars["foundindex"] = $plcnt.".";
								// value looks like html tag?
								$resfiltered = $this->Process_Colorcodes($result["players"][$index]);
								if (strstr($resfiltered, "<") || strstr($resfiltered, ">")) $resfiltered = htmlentities($resfiltered);
								$subsrchvars["result"] = "<a href=\"?detail=$index\">".$resfiltered."</a>";
								$subsrchvars["relevance"] = $relevance."%";
								$subsrchvars["clan"] = $this->players[$index]->clan;
								// value looks like html tag?
								$clanfiltered = $this->Process_Colorcodes($subsrchvars["clan"]);
								if (strstr($clanfiltered, "<") || strstr($clanfiltered, ">")) $clanfiltered = htmlentities($clanfiltered);
								if (!empty($clanfiltered)) $subsrchvars["clan"] = "<a href=\"?clandetail=".array_search($subsrchvars["clan"], $this->clans["clanlist"])."\">{$clanfiltered}</a>";
								else $subsrchvars["clan"] = "none";
								$searchvars["playerresults"] .= $this->Parse_Template(TEMPLATEPATH."search_repeat.tpl", $subsrchvars);
							}
							
							// clans
							
							// compute relevances for clans
							$relevancelist = array();
							foreach ($result["clans"] as $index => $clan) {
								$result["clans"][$index] = $this->Process_Colorcodes($result["clans"][$index]);
								$relevancelist[$index] = $this->computeSearchRelevance($result["clans"][$index], $needle);
							}
							arsort($relevancelist);
							$clcnt = 0;
							foreach ($relevancelist as $index => $relevance) {
								$clcnt++;
								$subsrchvars = array();
								$subsrchvars["foundindex"] = $clcnt.".";
								// value looks like html tag?
								$resfiltered = $this->Process_Colorcodes($result["clans"][$index]);
								if (strstr($resfiltered, "<") || strstr($resfiltered, ">")) $resfiltered = htmlentities($resfiltered);
								$subsrchvars["result"] = "<a href=\"?clandetail=$index\">".$resfiltered."</a>";
								$subsrchvars["relevance"] = $relevance."%";
								$subsrchvars["clan"] = "";
								$searchvars["clanresults"] .= $this->Parse_Template(TEMPLATEPATH."search_repeat.tpl", $subsrchvars);
							}
							
							// do we have empty searchresults?
							if ($searchvars["playerresults"] == "") {
								$searchvars["playerresults"] = "";
								$subsrchvars = "";
								$subsrchvars["foundindex"] = "";
								$subsrchvars["relevance"] = "";
								$subsrchvars["relevance"] = "";
								$subsrchvars["clan"] = "";
								$subsrchvars["result"] = "none";
								$searchvars["playerresults"] .= $this->Parse_Template(TEMPLATEPATH."search_repeat.tpl", $subsrchvars);
							}
							if ($searchvars["clanresults"] == "") {
								$searchvars["clanresults"] = "";
								$subsrchvars = "";
								$subsrchvars["foundindex"] = "";
								$subsrchvars["relevance"] = "";
								$subsrchvars["clan"] = "";
								$subsrchvars["result"] = "none";
								$searchvars["clanresults"] .= $this->Parse_Template(TEMPLATEPATH."search_repeat.tpl", $subsrchvars);
							}
						}
					}
					else $searchvars["foundentries"] = "No needle given. Please try again.";
					$varlist["content"] = $this->Parse_Template(TEMPLATEPATH."search.tpl", $searchvars);
				}
				
				$varlist["toplists"] = $topbasicout;
				
				$varlist["force_reparse"] = "<a href=\"?reparse\">Force reparsing of all data</a>";
				$varlist["gohome"] = "<a href=\"serverside.php\">Go Home</a>";
				
				$varlist["classversion"] = $this->getScriptVersion();
				
				$indexout = $this->Parse_Template(TEMPLATEPATH."index.tpl", $varlist);
				
				return $indexout;
			}
		}
		else {
			$this->procError = "no stat-files found";
			$this->pumpOutError();
		}
	}
	
	function searchData($needle) {
		$result = array();
		$result["clans"] = array();
		$result["players"] = array();
		$result["count"] = 0;
		// search clanlist
		foreach ($this->clans["clanlist"] as $id => $clan) {
			if (stristr($this->Process_Colorcodes($clan), $needle)){
				$result["clans"][$id] = $clan;
				$result["count"]++;
			}
		}
		// search players
		foreach ($this->players as $id => $player) {
			if (stristr($this->Process_Colorcodes($player->name), $needle)){
				$result["players"][$id] = $player->name;
				$result["count"]++;
			}
		}
		return $result;
	}
	
	function computeSearchRelevance($haystack, $needle) {
		$relevance = round((strlen($needle) / strlen($haystack) * 100), 1);
		return $relevance;
	}
	
	function getScriptVersion() {
		global $script_time;
		// was script parsed?
		$cached = ($this->wasiparsed == TRUE)?", realtime":", cached";
		$prevpcount = count($this->prevparsed);
		$reparsewhen = "";
		if ($prevpcount > 0) {
			if ($this->wasiparsed == TRUE) $cached = ", dumped, realtime";
			else $cached = ", dump cached";			
		}
		if ($this->wasiparsed == FALSE) $reparsewhen = ", reparsing in ".($_SESSION["q4maxstats"]["reparse_when"] - (time()))."s";
		$howmuch = ($prevpcount>0)?NULL:", for <strong>$this->XMLfilecount</strong> XML files";
		return "Script loaded in <strong>{$script_time}s</strong>$cached$reparsewhen$howmuch using <strong>$this->classversion</strong>";
	}
	
	function Parse_Template($tplfile, $vararray) {
		$tplfile = file_get_contents($tplfile);
		preg_match_all("=TPL__(.*?)__TPL=si", $tplfile, $matches);
		foreach ($matches[1] as $key => $match) {
			$realvarname = strtolower($match);
			if (isset($vararray[$realvarname])) $tplfile = str_replace($matches[0][$key], $vararray[$realvarname], $tplfile);
		}
		// kill not found rest
		preg_replace("=TPL__(.*?)__TPL=si", "", $tplfile);
		return $tplfile;
	}
	
	function Process_Colorcodes($data) {
		//$data = preg_replace("=[\^][a-zA-Z]*[0-9]*=si", "", $data);
		$data = preg_replace('=[\^][a-zA-Z]{0,4}[0-9]{0,3}[+-]*=si', "", $data);
		
		// look if filtered value is empty or spaces
		if (empty($data) || strlen(str_replace(" ", "", $data)) == 0) $data = "";
		return $data;
	}
	
	function Refurbish_Award($data) {
		$data = str_replace("_", " ", $data);
		$data = ucwords($data);
		return $data;
	}
	
	function refurbishXMLdate($data) {
		$broken = explode("/", $data);
		$broken = array_reverse($broken);
		if (strstr($broken[0], "-"))
			$brokentime = explode("-", $broken[0]);
		else
			$brokentime = explode("_", $broken[0]);
		$sec = @str_replace(".xml", "", $brokentime[2]);

		if (isset($broken[1], $broken[2], $broken[3]))
			$out = "{$broken[1]}.{$broken[2]}.{$broken[3]} {$brokentime[0]}:{$brokentime[1]}:$sec";
		else $out = "";
		return $out;
	}
	
	function dirlist($path) {
		$dirlist = array();
		if ($handle = opendir($path)) {
		   while (false !== ($file = readdir($handle))) {
			   if ($file != "." && $file != "..") {
				   $dirlist[] = $file;
			   }
		   }
		   closedir($handle);
		}
		else return FALSE;
		return $dirlist;	
	}
	
	function cool_var_dump($var, $dontecho = FALSE) {
		// replaces linefeeds with html tags using output buffer
		ob_start();
		var_dump($var);
		$output = ob_get_contents();
		ob_end_clean();	
		$output = nl2br($output);
		if ($dontecho == TRUE) return $output;	
		echo $output;
	}
}

class player {
	var $name;
	var $clan;
	var $guid;
	var $kills;
	var $deaths;
	var $score;
	var $suicides;
	var $damagegiven;
	var $damagetaken;
	var $healthtotal;
	var $armortotal;
	var $dnet;
	var $awards; 		// arrayed
	var $weapons;		// arrayed
	var $bestweapon;
	var $playerefficiency;  // score/deaths
	var $overallefficiency; // score/deaths incl average weapon eff
	var $uniqueplid;
	var $configuration;	// configurational data from parent
	var $maps; 			// arrayed
	var $mostplayedmap;
	var $bestmap;
	var $altnicks;		// arrayed
	var $altclantags;	// arrayed
	var $xmlfiles;		// arrayed
	//var $modType; 		// cpma/q4max
	var $skiplists;
	function player($statdata, $configuration, $skiplists, $parse_dumped = FALSE) {
		// constructor
		// recieves an array with new statdata and processes it
		$this->configuration 			= $configuration;
		$this->awards 					= array();
		$this->awards["awardlist"] 		= array();
		$this->maps 					= array();
		$this->maps["maplist"] 			= array();
		$this->altnicks 				= array();
		$this->altnicks["nicklist"] 	= array();
		$this->altclantags 				= array();
		$this->altclantags["taglist"] 	= array();
		$this->xmlfiles					= array();
		$this->weapons 					= array();
		$this->weapons["weaponlist"]	= array();
		
		$this->kills					= 0;
		$this->deaths					= 0;
		$this->score					= 0;
		$this->suicides					= 0;
		$this->damagegiven				= 0;
		$this->damagetaken				= 0;
		$this->healthtotal				= 0;
		$this->armortotal				= 0;
		$this->dnet						= 0;
		$this->thaws					= 0;
		
		$this->name = $statdata["name"];
		$this->clan = isset($statdata["clan"])?substr(XMLstats::process_colorcodes($statdata["clan"]), 0, $this->configuration["GENERAL"]["snip_tags"]):"";
		$this->guid = $statdata["guid"];
		$this->playerefficiency = 0;
		$this->overallefficiency = 0;
		
		if (isset($this->configuration["GENERAL"]["modtype"]))	
			$this->modType = $this->configuration["GENERAL"]["modtype"];
		$this->skiplists = $skiplists;
		
		if ($this->configuration["GENERAL"]["pdeterm_guid"] == 1 && empty($this->guid)) $this->guid = substr(base64_encode($this->name), 0, 15)." (emulated)";
		
		// is $statdata array a dumped one?
		if ($parse_dumped == TRUE) $this->Parse_Dumped_Stat_Data($statdata);
		else $this->Parse_Stat_Data($statdata);
		return TRUE;
	}
	
	function Parse_Dumped_Stat_Data($statdata) {
		// simple values
		
		$this->kills 				= $statdata["kills"];
		$this->clan 				= $statdata["clan"];
		$this->deaths 				= $statdata["deaths"];
		$this->score 				= $statdata["score"];
		$this->thaws				= $statdata["thaws"];
		$this->suicides 			= $statdata["suicides"];
		$this->damagegiven 			= $statdata["damagegiven"];
		$this->damagetaken 			= $statdata["damagetaken"];
		$this->healthtotal			= $statdata["healthtotal"];
		$this->armortotal			= $statdata["armortotal"];
		$this->bestweapon 			= $statdata["bestweapon"];
		$this->playerefficiency 	= $statdata["playerefficiency"];
		$this->overallefficiency 	= $statdata["overallefficiency"];
		$this->uniqueplid 			= $statdata["uniqueplid"];
		$this->mostplayedmap 		= $statdata["mostplayedmap"];
		$this->bestmap 				= $statdata["bestmap"];
		$this->dnet 				= $statdata["dnet"];
		$this->thaws 				= $statdata["thaws"];
		
		// punched arrays
		$this->awards 		= !empty($statdata["awards"])?$this->unserialize_arraydata($statdata["awards"]):NULL;
		$this->weapons		= !empty($statdata["weapons"])?$this->unserialize_arraydata($statdata["weapons"]):NULL;
		$this->maps 		= !empty($statdata["maps"])?$this->unserialize_arraydata($statdata["maps"]):NULL;
		$this->altnicks		= !empty($statdata["altnicks"])?$this->unserialize_arraydata($statdata["altnicks"]):NULL;
		$this->altclantags	= !empty($statdata["altclantags"])?$this->unserialize_arraydata($statdata["altclantags"]):NULL;
		$this->xmlfiles		= !empty($statdata["xmlfiles"])?$this->unserialize_arraydata($statdata["xmlfiles"]):NULL;
	}
	
	function serialize_arraydata($array) {
		// workaround for weird PHP float bug (round doesnt cut internal value of float)
		foreach ($array as $key => $setting) {
			if (is_float($setting)) {
				//$array[$key] = $setting."DBL";
				$array[$key] = strval($setting);
				//$array[$key] = substr($setting, 0, 2);
			}
			if (is_array($setting)) {
				foreach ($setting as $subkey => $subsetting) {
					if (is_float($subsetting)) {
						//$array[$key][$subkey] = $subsetting."DBL";
						$array[$key][$subkey] = strval($subsetting);
					}
				}
			}
		}
		$return = serialize($array);
		$return = str_replace(array('\n', '\r', '\t', '"'), array("_:N:_", "_:R:_", "_:T:_", "_:Q:_"), $return);
		$return = addslashes($return);
		return $return;
	}
	
	function unserialize_arraydata($data) {
		$return = stripslashes($data);
		$return = str_replace(array("_:N:_", "_:R:_", "_:T:_", "_:Q:_"), array('\n', '\r', '\t', '"'), $return);
		$return = unserialize($return);	
		return $return;
	}
	
	function giveFilteredStatsArray($statdata) {
		global $statsToGet;
		
		$gotstats = array();
		foreach ($statsToGet as $sname) {
			$gotstats[strtolower($sname)] = 0;
		}
		
		$statsToGetLower = $gotstats;
		
		foreach ($statdata as $single) {
			$lname = strtolower($single["name"]);
			if (in_array($lname, $statsToGetLower)) {
				$gotstats[$lname] = $single["value"];
			}
		}
		return $gotstats;
	}
	
	function Parse_Stat_Data($statdata) {
		// basic stats, section "stat"
		//var_dump($this->modType);
		/*if ($this->modType == "Q4MAX") {
			$this->kills 			= empty($statdata["stat"][0]["value"])?0:$statdata["stat"][0]["value"];
			$this->deaths 			= empty($statdata["stat"][1]["value"])?0:$statdata["stat"][1]["value"];
			$this->score 			= empty($statdata["stat"][2]["value"])?0:$statdata["stat"][2]["value"];
			$this->suicides 		= empty($statdata["stat"][3]["value"])?0:$statdata["stat"][3]["value"];
			$this->damagegiven 		= empty($statdata["stat"][4]["value"])?0:$statdata["stat"][4]["value"];
			$this->damagetaken 		= empty($statdata["stat"][5]["value"])?0:$statdata["stat"][5]["value"];
			$this->thaws	 		= empty($statdata["stat"][6]["value"])?0:$statdata["stat"][6]["value"];
		}
		elseif ($this->modType == "CPMA") {*/
		
		// cause we've deprecated the old XML format, we dont need to separate CPMA from Q4MAX
		
		$filtstats = $this->giveFilteredStatsArray($statdata["stat"]);
		foreach ($filtstats as $name => $value) {
			if (isset($this->$name)) {
				$this->$name = $value;
			}
		}

		//}
		
		// xmlfiles
		if (!is_numeric(array_search($statdata["xmlfile"], $this->xmlfiles))) $this->xmlfiles[] = $statdata["xmlfile"];
		
		//var_dump( $statdata["clan"]);
		
		if (empty($this->clan) && !empty($statdata["clan"])) $this->clan = substr(XMLstats::process_colorcodes($statdata["clan"]), 0, $this->configuration["GENERAL"]["snip_tags"]);
		
		// fill up altnicks and altclantags array
		$foundnick = array_search($statdata["name"], $this->altnicks["nicklist"]);
		if (is_numeric($foundnick)) $this->altnicks[$foundnick]["count"]++;
		else {
			$newindex = count($this->altnicks)-1;
			$this->altnicks["nicklist"][$newindex] = $statdata["name"];
			$this->altnicks[$newindex]["name"] = $statdata["name"];
			$this->altnicks[$newindex]["count"] = 1;
		}
		if (!empty($statdata["clan"])) {
			$theclan = substr(XMLstats::process_colorcodes($statdata["clan"]), 0, $this->configuration["GENERAL"]["snip_tags"]);
			$foundtag = array_search($theclan, $this->altclantags["taglist"]);
			if (is_numeric($foundtag)) $this->altclantags[$foundtag]["count"]++;
			else {
				$newindex = count($this->altclantags)-1;
				$this->altclantags["taglist"][$newindex] = $theclan;
				$this->altclantags[$newindex]["name"] = $theclan;
				$this->altclantags[$newindex]["count"] = 1;
			}
		}
		
		// parse map information
		if (!empty($statdata["map"])) {
			// break string open for clearer view
			$brokenmap = explode("/", $statdata["map"]);
			$mapname = $brokenmap[count($brokenmap)-1];
			$mapname = explode(".", $mapname);
			$mapname = strtoupper($mapname[0]);
			$newindex = count($this->maps["maplist"]);
			$this->maps["maplist"][$newindex] = $mapname;
			$this->maps[$newindex]["name"] = $mapname;
			$this->maps[$newindex]["count"] = 1;
			$this->maps[$newindex]["kills"] = $filtstats["kills"];
			$this->maps[$newindex]["deaths"] = $filtstats["deaths"];
			$this->maps[$newindex]["thaws"] = $filtstats["thaws"];
			$this->maps[$newindex]["efficiency"] = 0;
		}

		// awards, section "awards"
		if (isset($statdata["awards"]["award"]) && isset($statdata["awards"]["Award"])) $statdata["awards"]["Award"] = array_merge($statdata["awards"]["Award"], $statdata["awards"]["award"]);
		if (isset($statdata["awards"]["Award"])) {
			if (isset($statdata["awards"]["Award"]["name"])) $awards[0] = $statdata["awards"]["Award"];
			else $awards = $statdata["awards"]["Award"];
			
			if (is_array($awards)) {
				foreach ($awards as $award) {
					// is awardname in skiplist or empty, skip
					if (!empty($award["name"])) {
						if (!skipCheck($this->skiplists["ignoredawards"], $award["name"])) {
							$newindex = count($this->awards["awardlist"]);
							$this->awards["awardlist"][$newindex] = $award["name"];
							$this->awards[$newindex]["name"] = $award["name"];
							$this->awards[$newindex]["count"] = empty($award["value"])?1:$award["value"];
						}
					}
				}
			}
		}
		
		// weapons, section "weapons"
		if (isset($statdata["weapons"]["weapon"]) and is_array($statdata["weapons"]["weapon"])) {
			$getweaps = array();
			if (!isset($statdata["weapons"]["weapon"][0])) $getweaps[] = $statdata["weapons"]["weapon"];
			else $getweaps = $statdata["weapons"]["weapon"];
			foreach ($getweaps as $weapon) {
				if (!empty($weapon["name"])) {
					if (!skipCheck($this->skiplists["ignoredweapons"], "[".$weapon["name"]."]")) {
						$newindex = count($this->weapons["weaponlist"]);
						$this->weapons["weaponlist"][$newindex] = $weapon["name"];
						$this->weapons[$newindex]["name"] = $weapon["name"];
						$this->weapons[$newindex]["hits"] = $weapon["hits"];
						$this->weapons[$newindex]["shots"] = $weapon["shots"];
					}
				}
			}
		}
	}
	
	function Pump_New_Stats($statdata) {
		// recieves an array with new statdata and processes it upon old data
		// basic stats, section "stat"
		/*$this->score 			+= empty($statdata["stat"][0]["value"])?0:$statdata["stat"][0]["value"];
		$this->kills 			+= empty($statdata["stat"][1]["value"])?0:$statdata["stat"][1]["value"];
		$this->deaths 			+= empty($statdata["stat"][2]["value"])?0:$statdata["stat"][2]["value"];
		$this->suicides 		+= empty($statdata["stat"][3]["value"])?0:$statdata["stat"][3]["value"];
		$this->damagegiven 		+= empty($statdata["stat"][5]["value"])?0:$statdata["stat"][5]["value"];
		$this->damagetaken 		+= empty($statdata["stat"][6]["value"])?0:$statdata["stat"][6]["value"];
		$this->thaws	 		+= empty($statdata["stat"][7]["value"])?0:$statdata["stat"][7]["value"];*/
		
		/*if ($this->modType == "Q4MAX") {
			$this->kills 			+= empty($statdata["stat"][0]["value"])?0:$statdata["stat"][0]["value"];
			$this->deaths 			+= empty($statdata["stat"][1]["value"])?0:$statdata["stat"][1]["value"];
			$this->score 			+= empty($statdata["stat"][2]["value"])?0:$statdata["stat"][2]["value"];
			$this->suicides 		+= empty($statdata["stat"][3]["value"])?0:$statdata["stat"][3]["value"];
			$this->damagegiven 		+= empty($statdata["stat"][4]["value"])?0:$statdata["stat"][4]["value"];
			$this->damagetaken 		+= empty($statdata["stat"][5]["value"])?0:$statdata["stat"][5]["value"];
			$this->thaws	 		+= empty($statdata["stat"][6]["value"])?0:$statdata["stat"][6]["value"];
		}
		elseif ($this->modType == "CPMA") {*/
		
		$filtstats = $this->giveFilteredStatsArray($statdata["stat"]);
		foreach ($filtstats as $name => $value) {
			if (isset($this->$name)) {
				$this->$name += $value;
			}
		}
		//}
		
		// xmlfiles
		if (!is_numeric(array_search($statdata["xmlfile"], $this->xmlfiles))) $this->xmlfiles[] = $statdata["xmlfile"];
		
		if (empty($this->clan) && !empty($statdata["clan"])) $this->clan = substr(XMLstats::process_colorcodes($statdata["clan"]), 0, $this->configuration["GENERAL"]["snip_tags"]);
		
		// fill up altnicks and altclantags array
		$foundnick = array_search($statdata["name"], $this->altnicks["nicklist"]);
		if (is_numeric($foundnick)) $this->altnicks[$foundnick]["count"]++;
		else {
			$newindex = count($this->altnicks)-1;
			$this->altnicks["nicklist"][$newindex] = $statdata["name"];
			$this->altnicks[$newindex]["name"] = $statdata["name"];
			$this->altnicks[$newindex]["count"] = 1;
		}
		if (!empty($statdata["clan"])) {
			$theclan = substr(XMLstats::process_colorcodes($statdata["clan"]), 0, $this->configuration["GENERAL"]["snip_tags"]);
			$foundtag = array_search($theclan, $this->altclantags["taglist"]);
			if (is_numeric($foundtag)) $this->altclantags[$foundtag]["count"]++;
			else {
				$newindex = count($this->altclantags)-1;
				$this->altclantags["taglist"][$newindex] = $theclan;
				$this->altclantags[$newindex]["name"] = $theclan;
				$this->altclantags[$newindex]["count"] = 1;
			}
		}
		
		// parse map information
		if (!empty($statdata["map"])) {
			// break string open for clearer view
			$brokenmap = explode("/", $statdata["map"]);
			$mapname = $brokenmap[count($brokenmap)-1];
			$mapname = explode(".", $mapname);
			$mapname = $mapname[0];
			$havemap = array_search($mapname, $this->maps["maplist"]);
			if (is_numeric($havemap)) {
				$this->maps[$havemap]["count"] += 1;
				$this->maps[$havemap]["kills"] += empty($filtstats["kills"])?0:$filtstats["kills"];
				$this->maps[$havemap]["deaths"] += empty($filtstats["deaths"])?0:$filtstats["deaths"];
				$this->maps[$havemap]["thaws"] += empty($filtstats["thaws"])?0:$filtstats["thaws"];
			}
			else {
				$newindex = count($this->maps["maplist"]);
				$this->maps["maplist"][$newindex] = $mapname;
				$this->maps[$newindex]["name"] = $mapname;
				$this->maps[$newindex]["count"] = 1;
				$this->maps[$newindex]["kills"] = $filtstats["kills"];
				$this->maps[$newindex]["deaths"] = $filtstats["deaths"];	
				$this->maps[$newindex]["thaws"] = $filtstats["thaws"];
				$this->maps[$newindex]["efficiency"] = 0;
			}
		}

		// awards, section "awards"
		if (isset($statdata["awards"]["award"]) && isset($statdata["awards"]["Award"])) $statdata["awards"]["Award"] = array_merge($statdata["awards"]["Award"], $statdata["awards"]["award"]);
		elseif (isset($statdata["awards"]["award"]) && !isset($statdata["awards"]["Award"])) $statdata["awards"]["Award"] = $statdata["awards"]["award"];
		if (isset($statdata["awards"]["Award"])) {
			if (isset($statdata["awards"]["Award"]["name"])) $awards[0] = $statdata["awards"]["Award"];
			else $awards = $statdata["awards"]["Award"];
			
			if (is_array($awards)) {
				foreach ($awards as $award) {
					// is awardname in skiplist or empty, skip
					if (!empty($award["name"])) {
						if (!skipCheck($this->skiplists["ignoredawards"], $award["name"])) {
							// award already in list? update
							$haveaward = array_search($award["name"], $this->awards["awardlist"]);
							if (is_numeric($haveaward)) {
								$this->awards[$haveaward]["count"] += empty($award["value"])?1:$award["value"];
							}
							else {
								$newindex = count($this->awards["awardlist"]);
								$this->awards["awardlist"][$newindex] = $award["name"];
								$this->awards[$newindex]["name"] = $award["name"];
								$this->awards[$newindex]["count"] = empty($award["value"])?1:$award["value"];
							}
						}
					}
				}
			}
		}
		
		// weapons, section "weapons"
		if (isset($statdata["weapons"]["weapon"]) and is_array($statdata["weapons"]["weapon"])) {
			$getweaps = array();
			if (!isset($statdata["weapons"]["weapon"][0])) $getweaps[] = $statdata["weapons"]["weapon"];
			else $getweaps = $statdata["weapons"]["weapon"];
			foreach ($getweaps as $weapon) {
				if (!empty($weapon["name"])) {
					if (!skipCheck($this->skiplists["ignoredweapons"], "[".$weapon["name"]."]")) {
						// weapon already in list? update
						$haveweapon = array_search($weapon["name"], $this->weapons["weaponlist"]);
						if (is_numeric($haveweapon)) {
							$this->weapons[$haveweapon]["hits"] += $weapon["hits"];
							$this->weapons[$haveweapon]["shots"] += $weapon["shots"];
						}
						else {
							$newindex = count($this->weapons["weaponlist"]);
							$this->weapons["weaponlist"][$newindex] = $weapon["name"];
							$this->weapons[$newindex]["name"] = $weapon["name"];
							$this->weapons[$newindex]["hits"] = $weapon["hits"];
							$this->weapons[$newindex]["shots"] = $weapon["shots"];
						}
					}
				}
			}
		}
	}
	
	function Calculate_Stats() {
		// to be called after all data has been parsed
		$this->Get_Weapon_Efficiencies();
		$this->Get_Map_Efficiencies();
		$this->Get_Overall_Efficiency();
		$this->Get_Most_Played_Map();
		$this->Sort_Alternative_Nickclan();
		//$this->Get_Best_Map();
	}
	
	function Get_Weapon_Efficiencies() {
		$maxeff = 0.0;
		$maxeff_key = NULL;
		
		if (is_array($this->weapons)) {
			foreach ($this->weapons as $index => $weapon) {
				if (is_numeric($index) && $weapon["shots"]>0) {
					$percents = round(($weapon["hits"] * 100 / $weapon["shots"]), 2);
					$this->weapons[$index]["efficiency"] = $percents;
					if ($percents > $maxeff) {
						$maxeff = $percents;
						$maxeff_key = $index;
					}
				}
			}
		}
		$this->bestweapon = $maxeff_key;
	}
	
	function Get_Map_Efficiencies() {
		$maxeff = 0.0;
		$maxeff_key = NULL;
		foreach ($this->maps as $index => $map) {
			if (is_numeric($index) && $map["kills"]>0) {
				$percents = round(($map["kills"] * 100 / ($map["kills"] + $map["deaths"])), 2);
				$this->maps[$index]["efficiency"] = $percents;
				if ($percents > $maxeff) {
					$maxeff = $percents;
					$maxeff_key = $index;
				}
			}
		}
		$this->bestmap = $maxeff_key;
	}
	
	function Get_Overall_Efficiency() {
		// get player efficiency
		if (is_numeric($this->deaths) && $this->deaths > 0 && $this->kills > 0) {
			$this->playerefficiency = round(($this->kills * 100 / ($this->kills + $this->deaths)), 2);
		}
		
		// get overall efficiency
		$effcount = 0;
		$alleff = 0.0;
		foreach ($this->weapons as $index => $weapon) {
			if (isset($weapon["efficiency"])) {
				if (is_numeric($index) && is_float($weapon["efficiency"]) && $weapon["shots"] >0) {
					$alleff += $weapon["efficiency"];
					$effcount++;
				}
			}
		}
		if ($effcount > 0) $avgweapeff = round(($alleff / $effcount), 2);
		else return FALSE;
		if (is_numeric($this->playerefficiency)) {
			$overall_eff = round((($avgweapeff + $this->playerefficiency) / 2), 2);
		}
		else $overall_eff = $avgweapeff;
		$this->overallefficiency = $overall_eff;
		
		// get DNET
		$this->dnet = ($this->damagegiven - $this->damagetaken);
		
		return TRUE;
	}
	
	function Get_Most_Played_Map() {
		// name says it all
		$mostplayed = NULL;
		$mostcount = 0;
		foreach ($this->maps as $key=> $map) {
			if (is_numeric($key)) {
				if ($map["count"] > $mostcount) {
					$mostcount = $map["count"];
					$mostplayed = $key;
				}
			}
		}
		$this->mostplayedmap = $mostplayed;
	}
	
	function Get_Best_Map() {
		// name says it all
		$bestmap = NULL;
		$bestcount = 0;
		foreach ($this->maps as $key=> $map) {
			if (is_numeric($key)) {
				if ($map["efficiency"] > $bestcount) {
					$bestcount = $map["efficiency"];
					$bestmap = $key;
				}
			}
		}
		$this->bestmap = $bestmap;
	}
	
	function Sort_Alternative_Nickclan() {
		// run through altnicklist array and sort by count
		if (count($this->altnicks) >0) {
			$list = array();
			foreach ($this->altnicks as $key => $nick) {
				if (is_numeric($key)) {
					$list[$key] = $nick["count"];
				}
			}
			arsort($list);
			$oldlist = $this->altnicks;
			$this->altnicks = array();
			$count = 0;
			$foundmost = FALSE;
			foreach ($list as $nickkey => $count) {
				if (!$foundmost) {
					$this->altnicks["nicklist"][$nickkey] = "<strong>".XMLstats::Process_Colorcodes($oldlist["nicklist"][$nickkey])."</strong>";
					$foundmost = TRUE;
				}
				else $this->altnicks["nicklist"][$nickkey] = XMLstats::Process_Colorcodes($oldlist["nicklist"][$nickkey]);
				$this->altnicks[$nickkey]["name"] = $oldlist["nicklist"][$nickkey];
				$this->altnicks[$nickkey]["count"] = $count;
			}
		}
		
		// run through altclantags array and sort by count
		if (count($this->altclantags) >0) {
			// run through altnicklist array and sort by count
			$list = array();
			foreach ($this->altclantags as $key => $clantag) {
				if (is_numeric($key)) {
					$list[$key] = $clantag["count"];
				}
			}
			arsort($list);
			$oldlist = $this->altclantags;
			$this->altclantags = array();
			$count = 0;
			$foundmost = FALSE;
			foreach ($list as $clantagkey => $count) {
				if (!$foundmost) {
					$this->altclantags["taglist"][$clantagkey] = "<strong>".XMLstats::Process_Colorcodes($oldlist["taglist"][$clantagkey])."</strong>";
					$foundmost = TRUE;
				}
				else $this->altclantags["taglist"][$clantagkey] = $oldlist["taglist"][$clantagkey];
				$this->altclantags[$clantagkey]["name"] = $oldlist["taglist"][$clantagkey];
				$this->altclantags[$clantagkey]["count"] = $count;
			}
		}
	}
}

function microtime_float() {
   list($usec, $sec) = explode(" ", microtime());
   return ((float)$usec + (float)$sec);
}

function skipCheck($skiplist, $needle) {
	foreach ($skiplist as $toskip) {
		if (strstr(strtolower($needle), $toskip)) return TRUE;
	}
	return FALSE;
}

?>