/// <summary>
		/// Creates a DataView of the Player details which can be sorted, filtered and adjusted
		/// </summary>
		/// <param name="storeReader"></param>
		/// <param name="recs"></param>
		/// <returns>DataView of all Players sorted by Games DESC</returns>
		public static DataView CreatePlayerDataView(StoreReader storeReader, ReplayStore recs)
		{
			DataTable table = new DataTable("Players");
			table.Columns.Add("Player", typeof(string));
			table.Columns.Add("Games", typeof(int));
			table.Columns.Add("ReplayID", typeof(int));

			Debug.WriteLine(table);
			DataRow dvRow = null;
			

			//create a hash table to store the unique player names
			foreach (ReplayStore.PlayerRow row in recs.Player)
			{				
				object reps = storeReader.PlayerReplays(row.Name);
				if (reps != System.DBNull.Value)
				{
					dvRow = table.NewRow();
					dvRow["Player"] = row.Name;
					dvRow["Games"] = (int)reps;
					dvRow["ReplayID"] = row.ReplayID;
					table.Rows.Add(dvRow);
				}
			}

			DataView dvPlayers = new DataView(table, "", "Games DESC", DataViewRowState.CurrentRows);
			dvPlayers.Table.CaseSensitive = false;
			return dvPlayers;			
		}
		public frmMain()
		{
			InitializeComponent();

			log = new Logging("DoWRM.log");
			log.Open();
			
			if (ConfigurationSettings.AppSettings["LogLevel"] != null)
				log.LogLevel = Convert.ToInt32(ConfigurationSettings.AppSettings["LogLevel"]);

			log.Write(LogType.Info, 5, "Logging started...");

			//create the replay manager
			log.Write(LogType.Info, 5, "Create ReplayManager object");
			replayManager = new ReplayManager(Application.ExecutablePath, "Replays.zip");
			replayManager.log = log;
			//poll for new replays in the playback folder
			log.Write(LogType.Info, 5, "Polling replay folder (" + replayManager.DoWPlaybackFolder + ")...");
			object[] replayHashes = replayManager.PollPlaybackFolder(false);
			log.Write(LogType.Info, 5, "Found " + replayHashes.Length.ToString() + " replays");

			//load the store
			log.Write(LogType.Info, 5, "Create StoreReader object");
			storeReader = new StoreReader("cat.dat", "rec.dat");
			storeReader.log = log;
			storeReader.Read();
			
			//check if we have the replays found in the poll
			object[] newreplays = null;
			if (replayHashes != null)
			{
				newreplays = storeReader.HasHashes(replayHashes);
				log.Write(LogType.Info, 5, "Found " + newreplays.Length.ToString() + " NEW replay(s)");
			}

			//add replays that we dont have...
			if (newreplays != null && newreplays.Length > 0)
			{
				log.Write(LogType.Info, 5, "Adding replay(s) to store...");

				replayManager.StoreReader = storeReader;
				replayManager.Archive = ReplayManager.ArchiveType.FileStore;
				replayManager.AddReplays(newreplays);
			}
			log.Write(LogType.Info, 5, "Check for Available replays...");
			Methods.htAvailable = replayManager.GetAvailable();
			if (Methods.htAvailable != null)
				log.Write(LogType.Info, 5, "Found " + Methods.htAvailable.Count.ToString() + " Available replays");

			log.Write(LogType.Info, 5, "Creating and populating views...");
			Methods.PopulateCategoriesView(tvCategories, storeReader);

			dvPlayers = Methods.CreatePlayerDataView(storeReader, storeReader.Replays);
			Methods.PopulatePlayersView(lvPlayers, dvPlayers, null, "Games DESC");

			dvMaps = Methods.CreateMapDataView(storeReader, storeReader.Replays);
			Methods.PopulateMapsView(lvMaps, dvMaps, null, "Games DESC");

			dvReplays = Methods.CreateReplayDataView(storeReader, storeReader.Replays);
			Methods.PopulateReplaysView(lvReplays, dvReplays, null, "Added DESC");

			//set the replay number in the status bar
			System.Text.StringBuilder sNumReplays = new System.Text.StringBuilder();
			sNumReplays.Append("Replays: ");
			sNumReplays.Append(storeReader.Replays.Replay.Count.ToString());
			sbpNumReplays.Text = sNumReplays.ToString();

			//dont think i need these
			storeReader.Replays.AcceptChanges();
			storeReader.Categories.AcceptChanges();
		}
		public static object[] DeleteReplay(StoreReader storeReader, object[] ReplayIDs)
		{
			DialogResult result = MessageBox.Show(null, 
				"Deleted replays will be totally removed from your system! Are you sure?",
				"Delete replay(s)...",
				MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation);

			//store all the replay filenames that we're gonna delete in this Array
			ArrayList list = new ArrayList();

			if (result == DialogResult.Yes)
			{
				System.Text.StringBuilder s_Replayids = new System.Text.StringBuilder();
			
				if (ReplayIDs.Length > 0)
				{
					foreach (object replayid in ReplayIDs)
					{
						if (s_Replayids.Length == 0)
							s_Replayids.Append("ID = " + replayid);
						else
							s_Replayids.Append(" OR ID = " + replayid); 
					}
				}

				//first remove the replay from the store
				DataRow[] drReplay = storeReader.Replays.Replay.Select(s_Replayids.ToString());
				foreach (ReplayStore.ReplayRow row in drReplay)
				{
					list.Add(row.Filename);
					storeReader.Replays.Replay.RemoveReplayRow(row);
				}
				
				//remove from the map store
				DataRow[] drMap = storeReader.Replays.Map.Select(s_Replayids.ToString().Replace("ID", "ReplayID"));
				foreach (ReplayStore.MapRow row in drMap)
				{
					storeReader.Replays.Map.RemoveMapRow(row);
				}
					//remove from the player store
				DataRow[] drPlayers = storeReader.Replays.Player.Select(s_Replayids.ToString().Replace("ID", "ReplayID"));
				foreach (ReplayStore.PlayerRow row in drPlayers)
				{
					storeReader.Replays.Player.RemovePlayerRow(row);
				}
				
				//attempt to save the changes to the store
				if (!storeReader.SaveReplays("rec.dat"))
					MessageBox.Show(null, StoreReader.STORE_REPLAYSAVE_FAIL, "Save failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
				else
					return list.ToArray();
			}
			return list.ToArray();
		}
		public static void RenameReplay(StoreReader storeReader, int ReplayID, string NewName)
		{
			DataRow[] drRows = storeReader.Replays.Replay.Select("ID = " + ReplayID);
			foreach (ReplayStore.ReplayRow row in drRows)
			{
				row.Name = NewName;
			}

			storeReader.Replays.Merge(drRows);

			if (!storeReader.SaveReplays("rec.dat"))
				MessageBox.Show(null, StoreReader.STORE_REPLAYSAVE_FAIL, "Save failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
		}
		public static void DeleteCategory(StoreReader storeReader, int CategoryID)
		{
			DataRow[] drRows = storeReader.Categories.Category.Select("ID = " + CategoryID);
			foreach (CategoryStore.CategoryRow row in drRows)
			{
				storeReader.Categories.Category.RemoveCategoryRow(row);
			}
			
			if (!storeReader.SaveCategories("cat.dat"))
				MessageBox.Show(null, StoreReader.STORE_CATEGORYSAVE_FAIL, "Save failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
		}
		public static void RenameCategory(StoreReader storeReader, int CategoryID, string NewCategoryName)
		{
			DataRow[] drRows = storeReader.Categories.Category.Select("ID = " + CategoryID);
			foreach (CategoryStore.CategoryRow row in drRows)
			{
				row.Name = NewCategoryName;
			}
	
			storeReader.Categories.Merge(drRows);
			
			if (!storeReader.SaveCategories("cat.dat"))
				MessageBox.Show(null, StoreReader.STORE_CATEGORYSAVE_FAIL, "Save failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);		
		}
		public static void CreateNewCategory(StoreReader storeReader, string NewCategoryName, int ParentID)
		{
			CategoryStore.CategoryRow row = storeReader.Categories.Category.NewCategoryRow();
			row["Name"] = NewCategoryName;
			row["AllowDelete"] = true;
			row["ParentID"] = ParentID;
			row["HasChildren"] = false;

			int id = (int)row["ID"];
			storeReader.Categories.Category.AddCategoryRow(row);

			if (!storeReader.SaveCategories("cat.dat"))
				MessageBox.Show(null, StoreReader.STORE_CATEGORYSAVE_FAIL, "Save failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
		}
		public static void PopulateCategoriesView(TreeView tvCategories, StoreReader storeReader)
		{
			tvCategories.Nodes.Clear();

			TreeNode node;
			foreach (CategoryStore.CategoryRow row in storeReader.Categories.Category)
			{
				node = new TreeNode();
				node.Tag = row.ID;
				node.Text = row.Name;

				if (row.ParentID != 0)
				{
					TreeNode pNode = GetNodeByTag(row.ParentID, tvCategories.Nodes);
					if (pNode != null)
						pNode.Nodes.Add(node);
				}
				else
				{						
					tvCategories.Nodes.Add(node);
				}
			}
			tvCategories.ExpandAll();
		}
		/// <summary>
		/// Changes the supplied Replays' Category ID to the NewCategoryID
		/// </summary>
		/// <param name="ReplayIDs"></param>
		/// <param name="NewCategoryID"></param>
		/// <param name="storeReader"></param>
		public static void AlterReplayCategory(object[] ReplayIDs, int NewCategoryID, StoreReader storeReader)
		{
			System.Text.StringBuilder s_Replayids = new System.Text.StringBuilder();
			
			if (ReplayIDs.Length > 0)
			{
				foreach (object replayid in ReplayIDs)
				{
					if (s_Replayids.Length == 0)
						s_Replayids.Append("ID = " + replayid);
					else
						s_Replayids.Append(" OR ID = " + replayid); 
				}
			
				
				DataRow[] drRows = storeReader.Replays.Tables["Replay"].Select(s_Replayids.ToString());
				foreach (ReplayStore.ReplayRow row in drRows)
				{
					row.CategoryID = NewCategoryID;
				}

				storeReader.Replays.Merge(drRows);

				//save changes
				if (!storeReader.SaveReplays("rec.dat"))
					MessageBox.Show(null, StoreReader.STORE_REPLAYSAVE_FAIL, "Save failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}
		public static DataView CreateReplayDataView(StoreReader storeReader, ReplayStore recs)
		{
			DataTable table = new DataTable("Replays");
			table.Columns.Add("ReplayID", typeof(int));
			table.Columns.Add("Name", typeof(string));
			table.Columns.Add("Modified", typeof(DateTime));
			table.Columns.Add("Added", typeof(DateTime));
			table.Columns.Add("Filename", typeof(string));
			table.Columns.Add("CategoryID", typeof(int));

			DataRow dvRow;

			foreach (ReplayStore.ReplayRow row in recs.Replay)
			{
				dvRow = table.NewRow();
				dvRow["ReplayID"] = row.ID;
				dvRow["Name"] = row.Name;
				dvRow["Modified"] = row.DateModified;
				dvRow["Added"] = row.DateAdded;
				dvRow["Filename"] = row.Filename;
				dvRow["CategoryID"] = row.CategoryID;
				table.Rows.Add(dvRow);
			}

			DataView dvReplays = new DataView(table, "", "Added DESC", DataViewRowState.CurrentRows);
			dvReplays.Table.CaseSensitive = false;
			return dvReplays;			
		}
		/// <summary>
		/// Creates a DataView of the Player details which can be sorted, filtered and adjusted
		/// </summary>
		/// <param name="storeReader"></param>
		/// <param name="recs"></param>
		/// <returns>DataView of all Maps sorted by Games DESC</returns>
		public static DataView CreateMapDataView(StoreReader storeReader, ReplayStore recs)
		{
			DataTable table = new DataTable("Maps");
			table.Columns.Add("Map", typeof(string));
			table.Columns.Add("Games", typeof(int));
			table.Columns.Add("ReplayID", typeof(int));

			DataRow dvRow;

			foreach (ReplayStore.MapRow row in recs.Map)
			{	
				object reps = storeReader.MapReplays(row.Name);
				if (reps != System.DBNull.Value)
				{
					dvRow = table.NewRow();
					dvRow["Map"] = row.Name;
					dvRow["Games"] = (int)reps;
					dvRow["ReplayID"] = row.ReplayID;
					table.Rows.Add(dvRow);
				}
			}

			DataView dvMaps = new DataView(table, "", "Games DESC", DataViewRowState.CurrentRows);
			dvMaps.Table.CaseSensitive = false;
			return dvMaps;			
		}