using ElectronicObserver.Data;
using ElectronicObserver.Resource;
using ElectronicObserver.Resource.Record;
using ElectronicObserver.Utility.Mathematics;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ElectronicObserver.Window.Dialog
{
	public partial class DialogDropRecordViewer : Form
	{

		private ShipDropRecord _record;

		private const string NameAny = "(全て)";
		private const string NameNotExist = "(なし)";
		private const string NameFullPort = "(満員)";
		private const string NameExist = "(ドロップ)";

		private const string MapAny = "*";

		private Dictionary<int, DataTable> MapCellTable;


		private class SearchArgument
		{
			public string ShipName;
			public string ItemName;
			public string EquipmentName;
			public DateTime DateBegin;
			public DateTime DateEnd;
			public int MapAreaID;
			public int MapInfoID;
			public int MapCellID;
			public int MapDifficulty;
			public CheckState IsBossOnly;
			public bool RankS;
			public bool RankA;
			public bool RankB;
			public bool RankX;
			public bool MergeRows;
			public DataGridViewRow BaseRow;
		}


		public DialogDropRecordViewer()
		{
			InitializeComponent();

			_record = RecordManager.Instance.ShipDrop;
		}

		private void DialogDropRecordViewer_Load(object sender, EventArgs e)
		{

			var includedShipNames = _record.Record
				.Select(r => r.ShipName)
				.Distinct()
				.Except(new[] { NameNotExist, NameFullPort });

			var includedShipObjects = includedShipNames
				.Select(name => KCDatabase.Instance.MasterShips.Values.FirstOrDefault(ship => ship.NameWithClass == name))
				.Where(s => s != null);

			var removedShipNames = includedShipNames.Except(includedShipObjects.Select(s => s.NameWithClass));


			var includedItemNames = _record.Record
				.Select(r => r.ItemName)
				.Distinct()
				.Except(new[] { NameNotExist });

			var includedItemObjects = includedItemNames
				.Select(name => KCDatabase.Instance.MasterUseItems.Values.FirstOrDefault(item => item.Name == name))
				.Where(s => s != null);

			var removedItemNames = includedItemNames.Except(includedItemObjects.Select(item => item.Name));

			var dtbase = new DataTable();
			dtbase.Columns.AddRange(new DataColumn[] {
				new DataColumn( "Value", typeof( int ) ),
				new DataColumn( "Display", typeof( string ) ),
			});



			MapCellTable = new Dictionary<int, DataTable>();
			{
				var dict = new Dictionary<int, HashSet<int>>();

				foreach (var r in _record.Record)
				{
					int id = r.MapAreaID * 10 + r.MapInfoID;

					if (!dict.ContainsKey(id))
					{
						dict.Add(id, new HashSet<int>());
					}

					dict[id].Add(r.CellID);
				}

				foreach (var p in dict)
				{
					MapCellTable.Add(p.Key, dtbase.Clone());
					MapCellTable[p.Key].Rows.Add(-1, MapAny);
					foreach (var c in p.Value.OrderBy(k => k))
						MapCellTable[p.Key].Rows.Add(c, c.ToString());
					MapCellTable[p.Key].AcceptChanges();
				}
			}



			ShipName.Items.Add(NameAny);
			ShipName.Items.Add(NameExist);
			ShipName.Items.Add(NameNotExist);
			ShipName.Items.Add(NameFullPort);
			ShipName.Items.AddRange(includedShipObjects
				.OrderBy(s => s.NameReading)
				.OrderBy(s => s.ShipType)
				.Select(s => s.NameWithClass)
				.Union(removedShipNames.OrderBy(s => s))
				.ToArray()
				);
			ShipName.SelectedIndex = 0;

			ItemName.Items.Add(NameAny);
			ItemName.Items.Add(NameExist);
			ItemName.Items.Add(NameNotExist);
			ItemName.Items.AddRange(includedItemObjects
				.OrderBy(i => i.ItemID)
				.Select(i => i.Name)
				.Union(removedItemNames.OrderBy(i => i))
				.ToArray()
				);
			ItemName.SelectedIndex = 0;

			// not implemented: eq


			DateBegin.Value = DateBegin.MinDate = DateEnd.MinDate = _record.Record.First().Date.Date;
			DateEnd.Value = DateBegin.MaxDate = DateEnd.MaxDate = DateTime.Now.AddDays(1).Date;

			{
				DataTable dt = dtbase.Clone();
				dt.Rows.Add(-1, MapAny);
				foreach (var i in _record.Record
					.Select(r => r.MapAreaID)
					.Distinct()
					.OrderBy(i => i))
					dt.Rows.Add(i, i.ToString());
				dt.AcceptChanges();
				MapAreaID.DisplayMember = "Display";
				MapAreaID.ValueMember = "Value";
				MapAreaID.DataSource = dt;
				MapAreaID.SelectedIndex = 0;
			}

			{
				DataTable dt = dtbase.Clone();
				dt.Rows.Add(-1, MapAny);
				foreach (var i in _record.Record
					.Select(r => r.MapInfoID)
					.Distinct()
					.OrderBy(i => i))
					dt.Rows.Add(i, i.ToString());
				dt.AcceptChanges();
				MapInfoID.DisplayMember = "Display";
				MapInfoID.ValueMember = "Value";
				MapInfoID.DataSource = dt;
				MapInfoID.SelectedIndex = 0;
			}

			{
				DataTable dt = dtbase.Clone();
				dt.Rows.Add(-1, MapAny);
				// 残りは都度生成する
				dt.AcceptChanges();
				MapCellID.DisplayMember = "Display";
				MapCellID.ValueMember = "Value";
				MapCellID.DataSource = dt;
				MapCellID.SelectedIndex = 0;
			}

			{
				DataTable dt = dtbase.Clone();
				dt.Rows.Add(0, MapAny);
				foreach (var diff in _record.Record
					.Select(r => r.Difficulty)
					.Distinct()
					.Except(new[] { 0 })
					.OrderBy(i => i))
					dt.Rows.Add(diff, Constants.GetDifficulty(diff));
				dt.AcceptChanges();
				MapDifficulty.DisplayMember = "Display";
				MapDifficulty.ValueMember = "Value";
				MapDifficulty.DataSource = dt;
				MapDifficulty.SelectedIndex = 0;
			}


			foreach (DataGridViewColumn column in RecordView.Columns)
				column.Width = 20;

			LabelShipName.ImageList = ResourceManager.Instance.Icons;
			LabelShipName.ImageIndex = (int)ResourceManager.IconContent.HeadQuartersShip;
			LabelItemName.ImageList = ResourceManager.Instance.Icons;
			LabelItemName.ImageIndex = (int)ResourceManager.IconContent.ItemPresentBox;
			LabelEquipmentName.ImageList = ResourceManager.Instance.Equipments;
			LabelEquipmentName.ImageIndex = (int)ResourceManager.EquipmentContent.MainGunL;

			Icon = ResourceManager.ImageToIcon(ResourceManager.Instance.Icons.Images[(int)ResourceManager.IconContent.ItemPresentBox]);
		}

		private void DialogDropRecordViewer_FormClosed(object sender, FormClosedEventArgs e)
		{
			ResourceManager.DestroyIcon(Icon);
		}



		private string GetContentString(ShipDropRecord.ShipDropElement elem, bool ignoreShip = false, bool ignoreItem = false, bool ignoreEquipment = false)
		{

			if (elem.ShipID > 0 && !ignoreShip)
			{

				if (elem.ItemID > 0 && !ignoreItem)
				{
					if (elem.EquipmentID > 0 && !ignoreEquipment)
						return elem.ShipName + " + " + elem.ItemName + " + " + elem.EquipmentName;
					else
						return elem.ShipName + " + " + elem.ItemName;
				}
				else
				{
					if (elem.EquipmentID > 0 && !ignoreEquipment)
						return elem.ShipName + " + " + elem.EquipmentName;
					else
						return elem.ShipName;
				}

			}
			else
			{
				if (elem.ItemID > 0 && !ignoreItem)
				{
					if (elem.EquipmentID > 0 && !ignoreEquipment)
						return elem.ItemName + " + " + elem.EquipmentName;
					else
						return elem.ItemName;
				}
				else
				{
					if (elem.EquipmentID > 0 && !ignoreEquipment)
						return elem.EquipmentName;
					else
						return elem.ShipName;
				}
			}

		}

		private string GetContentStringForSorting(ShipDropRecord.ShipDropElement elem, bool ignoreShip = false, bool ignoreItem = false, bool ignoreEquipment = false)
		{

			var ship = KCDatabase.Instance.MasterShips[elem.ShipID];
			var item = KCDatabase.Instance.MasterUseItems[elem.ItemID];
			var eq = KCDatabase.Instance.MasterEquipments[elem.EquipmentID];

			if (ship != null && ship.Name != elem.ShipName) ship = null;
			if (item != null && item.Name != elem.ItemName) item = null;
			if (eq != null && eq.Name != elem.EquipmentName) eq = null;

			StringBuilder sb = new StringBuilder();


			if (elem.ShipID > 0 && !ignoreShip)
			{
				sb.AppendFormat("0{0:D4}{1}/{2}", (int?)ship?.ShipType ?? 0, ship?.NameReading ?? elem.ShipName, elem.ShipName);
			}

			if (elem.ItemID > 0 && !ignoreItem)
			{
				if (sb.Length > 0) sb.Append(",");
				sb.AppendFormat("1{0:D4}{1}", item?.ItemID ?? 0, elem.ItemName);
			}

			if (elem.EquipmentID > 0 && !ignoreEquipment)
			{
				if (sb.Length > 0) sb.Append(",");
				sb.AppendFormat("2{0:D4}{1}", eq?.EquipmentID ?? 0, elem.EquipmentName);
			}

			return sb.ToString();
		}


		private string ConvertContentString(string str)
		{

			if (str.Length == 0)
				return NameNotExist;

			StringBuilder sb = new StringBuilder();

			foreach (var s in str.Split(",".ToCharArray()))
			{

				if (sb.Length > 0)
					sb.Append(" + ");

				switch (s[0])
				{
					case '0':
						sb.Append(s.Substring(s.IndexOf("/") + 1));
						break;
					case '1':
					case '2':
						sb.Append(s.Substring(5));
						break;
				}
			}

			return sb.ToString();
		}



		private string GetMapString(int maparea, int mapinfo, int cell = -1, bool isboss = false, int difficulty = -1, bool insertEnemyFleetName = true)
		{
			var sb = new StringBuilder();
			sb.Append(maparea);
			sb.Append("-");
			sb.Append(mapinfo);
			if (difficulty != -1)
				sb.AppendFormat("[{0}]", Constants.GetDifficulty(difficulty));
			if (cell != -1)
			{
				sb.Append("-");
				sb.Append(cell);
			}
			if (isboss)
				sb.Append(" [ボス]");

			if (insertEnemyFleetName)
			{
				var enemy = RecordManager.Instance.EnemyFleet.Record.Values.FirstOrDefault(r => r.MapAreaID == maparea && r.MapInfoID == mapinfo && r.CellID == cell && r.Difficulty == difficulty);
				if (enemy != null)
					sb.AppendFormat(" ({0})", enemy.FleetName);
			}

			return sb.ToString();
		}

		private string GetMapString(int serialID, bool insertEnemyFleetName = true)
		{
			return GetMapString(serialID >> 24 & 0xFF, serialID >> 16 & 0xFF, serialID >> 8 & 0xFF, (serialID & 1) != 0, (sbyte)((serialID >> 1 & 0x7F) << 1) >> 1, insertEnemyFleetName);
		}

		private int GetMapSerialID(int maparea, int mapinfo, int cell, bool isboss, int difficulty = -1)
		{
			return (maparea & 0xFF) << 24 | (mapinfo & 0xFF) << 16 | (cell & 0xFF) << 8 | (difficulty & 0x7F) << 1 | (isboss ? 1 : 0);
		}


		private void MapAreaID_SelectedIndexChanged(object sender, EventArgs e)
		{

			int maparea = (int)(MapAreaID.SelectedValue ?? -1);
			int mapinfo = (int)(MapInfoID.SelectedValue ?? -1);

			if (maparea == -1 || mapinfo == -1)
			{
				MapCellID.Enabled = false;
				if (MapCellID.Items.Count > 0)
					MapCellID.SelectedIndex = 0;

			}
			else
			{
				MapCellID.Enabled = true;
				if (MapCellTable.ContainsKey(maparea * 10 + mapinfo))
				{
					MapCellID.DataSource = MapCellTable[maparea * 10 + mapinfo];
				}
				else
				{
					MapCellID.Enabled = false;
				}
				MapCellID.SelectedIndex = 0;
			}
		}


		private void ButtonRun_Click(object sender, EventArgs e)
		{

			if (Searcher.IsBusy)
			{
				if (MessageBox.Show("検索を中止しますか?", "検索中です", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2)
					== System.Windows.Forms.DialogResult.Yes)
				{
					Searcher.CancelAsync();
				}
				return;
			}

			RecordView.Rows.Clear();

			var row = new DataGridViewRow();
			row.CreateCells(RecordView);

			var args = new SearchArgument
			{
				ShipName = ShipName.Text,
				ItemName = (string)ItemName.SelectedItem,
				EquipmentName = (string)EquipmentName.SelectedItem,
				DateBegin = DateBegin.Value,
				DateEnd = DateEnd.Value,
				MapAreaID = (int)MapAreaID.SelectedValue,
				MapInfoID = (int)MapInfoID.SelectedValue,
				MapCellID = (int)MapCellID.SelectedValue,
				MapDifficulty = (int)MapDifficulty.SelectedValue,
				IsBossOnly = IsBossOnly.CheckState,
				RankS = RankS.Checked,
				RankA = RankA.Checked,
				RankB = RankB.Checked,
				RankX = RankX.Checked,
				MergeRows = MergeRows.Checked,
				BaseRow = row
			};

			RecordView.Tag = args;


			// column initialize
			if (MergeRows.Checked)
			{
				RecordView_Name.DisplayIndex = 0;
				RecordView_Header.HeaderText = "回数";
				RecordView_Header.Width = 100;
				RecordView_Header.DisplayIndex = 1;
				RecordView_RankS.Width = 100;
				RecordView_RankS.Visible = true;
				RecordView_RankA.Width = 100;
				RecordView_RankA.Visible = true;
				RecordView_RankB.Width = 100;
				RecordView_RankB.Visible = true;

				RecordView_Date.Visible = false;
				RecordView_Map.Visible = false;
				RecordView_Rank.Visible = false;

			}
			else
			{
				RecordView_Header.HeaderText = "";
				RecordView_Header.Width = 50;
				RecordView_Header.DisplayIndex = 0;
				RecordView_Date.Width = 150;
				RecordView_Date.Visible = true;
				RecordView_Map.Width = 240;
				RecordView_Map.Visible = true;
				RecordView_Rank.Width = 40;
				RecordView_Rank.Visible = true;

				RecordView_RankS.Visible = false;
				RecordView_RankA.Visible = false;
				RecordView_RankB.Visible = false;

			}
			RecordView.ColumnHeadersVisible = true;


			StatusInfo.Text = "検索中です...";
			StatusInfo.Tag = DateTime.Now;

			Searcher.RunWorkerAsync(args);
		}


		private void Searcher_DoWork(object sender, DoWorkEventArgs e)
		{

			SearchArgument args = (SearchArgument)e.Argument;


			int priorityShip =
				args.ShipName == NameAny ? 0 :
				args.ShipName == NameExist ? 1 : 2;
			int priorityItem =
				args.ItemName == NameAny ? 0 :
				args.ItemName == NameExist ? 1 : 2;
			int priorityContent = Math.Max(priorityShip, priorityItem);

			var records = RecordManager.Instance.ShipDrop.Record;
			var rows = new LinkedList<DataGridViewRow>();


			//lock ( records ) 
			{
				int i = 0;
				var counts = new Dictionary<string, int[]>();
				var allcounts = new Dictionary<string, int[]>();


				foreach (var r in records)
				{

					#region Filtering

					if (r.Date < args.DateBegin || args.DateEnd < r.Date)
						continue;

					if (((r.Rank == "SS" || r.Rank == "S") && !args.RankS) ||
						 ((r.Rank == "A") && !args.RankA) ||
						 ((r.Rank == "B") && !args.RankB) ||
						 ((Constants.GetWinRank(r.Rank) <= 3) && !args.RankX))
						continue;


					if (args.MapAreaID != -1 && args.MapAreaID != r.MapAreaID)
						continue;
					if (args.MapInfoID != -1 && args.MapInfoID != r.MapInfoID)
						continue;
					if (args.MapCellID != -1 && args.MapCellID != r.CellID)
						continue;
					switch (args.IsBossOnly)
					{
						case CheckState.Unchecked:
							if (r.IsBossNode)
								continue;
							break;
						case CheckState.Checked:
							if (!r.IsBossNode)
								continue;
							break;
					}
					if (args.MapDifficulty != 0 && args.MapDifficulty != r.Difficulty)
						continue;



					if (args.MergeRows)
					{
						string key;

						if (priorityContent == 2)
						{
							key = GetMapSerialID(r.MapAreaID, r.MapInfoID, r.CellID, r.IsBossNode, args.MapDifficulty == 0 ? -1 : r.Difficulty).ToString("X8");

						}
						else
						{
							key = GetContentString(r, priorityShip < priorityItem && priorityShip < 2, priorityShip >= priorityItem && priorityItem < 2);
						}


						if (!allcounts.ContainsKey(key))
						{
							allcounts.Add(key, new int[4]);
						}

						switch (r.Rank)
						{
							case "B":
								allcounts[key][3]++;
								break;
							case "A":
								allcounts[key][2]++;
								break;
							case "S":
							case "SS":
								allcounts[key][1]++;
								break;
						}
						allcounts[key][0]++;
					}



					switch (args.ShipName)
					{
						case NameAny:
							break;
						case NameExist:
							if (r.ShipID < 0)
								continue;
							break;
						case NameNotExist:
							if (r.ShipID != -1)
								continue;
							break;
						case NameFullPort:
							if (r.ShipID != -2)
								continue;
							break;
						default:
							if (r.ShipName != args.ShipName)
								continue;
							break;
					}

					switch (args.ItemName)
					{
						case NameAny:
							break;
						case NameExist:
							if (r.ItemID < 0)
								continue;
							break;
						case NameNotExist:
							if (r.ItemID != -1)
								continue;
							break;
						default:
							if (r.ItemName != args.ItemName)
								continue;
							break;
					}

					#endregion


					if (!args.MergeRows)
					{
						var row = (DataGridViewRow)args.BaseRow.Clone();

						row.SetValues(
							i + 1,
							GetContentString(r),
							r.Date,
							GetMapString(r.MapAreaID, r.MapInfoID, r.CellID, r.IsBossNode, r.Difficulty),
							Constants.GetWinRank(r.Rank),
							null,
							null,
							null
							);

						row.Cells[1].Tag = GetContentStringForSorting(r);
						row.Cells[3].Tag = GetMapSerialID(r.MapAreaID, r.MapInfoID, r.CellID, r.IsBossNode, r.Difficulty);

						rows.AddLast(row);


					}
					else
					{
						//merged

						string key;

						if (priorityContent == 2)
						{
							key = GetMapSerialID(r.MapAreaID, r.MapInfoID, r.CellID, r.IsBossNode, args.MapDifficulty == 0 ? -1 : r.Difficulty).ToString("X8");

						}
						else
						{
							key = GetContentStringForSorting(r, priorityShip < priorityItem && priorityShip < 2, priorityShip >= priorityItem && priorityItem < 2);
						}


						if (!counts.ContainsKey(key))
						{
							counts.Add(key, new int[4]);
						}

						switch (r.Rank)
						{
							case "B":
								counts[key][3]++;
								break;
							case "A":
								counts[key][2]++;
								break;
							case "S":
							case "SS":
								counts[key][1]++;
								break;
						}
						counts[key][0]++;

					}



					if (Searcher.CancellationPending)
						break;

					i++;
				}


				if (args.MergeRows)
				{

					int[] allcountssum = Enumerable.Range(0, 4).Select(k => allcounts.Values.Sum(a => a[k])).ToArray();

					foreach (var c in counts)
					{
						var row = (DataGridViewRow)args.BaseRow.Clone();

						string name = c.Key;

						if (int.TryParse(name, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out int serialID))
							name = GetMapString(serialID);

						// fixme: name != map だった時にソートキーが入れられない

						row.SetValues(
							c.Value[0],
							serialID != 0 ? name : ConvertContentString(name),
							null,
							null,
							null,
							c.Value[1],
							c.Value[2],
							c.Value[3]
							);


						if (priorityContent == 2)
						{
							row.Cells[0].Tag = allcounts[c.Key][0];
							if (serialID != 0)
								row.Cells[1].Tag = serialID;
							else
								row.Cells[1].Tag = name;
							row.Cells[5].Tag = allcounts[c.Key][1];
							row.Cells[6].Tag = allcounts[c.Key][2];
							row.Cells[7].Tag = allcounts[c.Key][3];

						}
						else
						{
							row.Cells[0].Tag = ((double)c.Value[0] / Math.Max(allcountssum[0], 1));
							if (serialID != 0)
								row.Cells[1].Tag = serialID;
							else
								row.Cells[1].Tag = name;
							row.Cells[5].Tag = ((double)c.Value[1] / Math.Max(allcountssum[1], 1));
							row.Cells[6].Tag = ((double)c.Value[2] / Math.Max(allcountssum[2], 1));
							row.Cells[7].Tag = ((double)c.Value[3] / Math.Max(allcountssum[3], 1));

						}

						rows.AddLast(row);
					}

				}

			}

			e.Result = rows.ToArray();
		}



		private void Searcher_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{

			if (!e.Cancelled)
			{
				var rows = (DataGridViewRow[])e.Result;

				RecordView.Rows.AddRange(rows);

				RecordView.Sort(RecordView.SortedColumn ?? RecordView_Header,
					RecordView.SortOrder == SortOrder.Ascending ? ListSortDirection.Ascending : ListSortDirection.Descending);

				StatusInfo.Text = "検索が完了しました。(" + (int)(DateTime.Now - (DateTime)StatusInfo.Tag).TotalMilliseconds + " ms)";

			}
			else
			{

				StatusInfo.Text = "検索がキャンセルされました。";
			}

		}


		private void RecordView_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
		{

			object tag1 = RecordView[e.Column.Index, e.RowIndex1].Tag;
			object tag2 = RecordView[e.Column.Index, e.RowIndex2].Tag;

			if (tag1 != null && (tag1 is double || tag1 is int) && e.CellValue1 is int)
			{
				double c1 = 0, c2 = 0;

				if (tag1 is double)
				{
					c1 = (double)tag1;
					c2 = (double)tag2;
				}
				else if (tag1 is int)
				{
					c1 = (double)(int)e.CellValue1 / Math.Max((int)tag1, 1);
					c2 = (double)(int)e.CellValue2 / Math.Max((int)tag2, 1);
				}


				if (Math.Abs(c1 - c2) < 0.000001)
					e.SortResult = (int)e.CellValue1 - (int)e.CellValue2;
				else if (c1 < c2)
					e.SortResult = -1;
				else
					e.SortResult = 1;
				e.Handled = true;

			}
			else if (tag1 is string)
			{
				e.SortResult = ((IComparable)tag1).CompareTo(tag2);
				e.Handled = true;
			}
			else if (tag1 is int)
			{
				e.SortResult = (int)tag1 - (int)tag2;
				e.Handled = true;
			}


			if (!e.Handled)
			{
				e.SortResult = ((IComparable)e.CellValue1 ?? 0).CompareTo(e.CellValue2 ?? 0);
				e.Handled = true;
			}

			if (e.SortResult == 0)
			{
				e.SortResult = (int)(RecordView.Rows[e.RowIndex1].Tag ?? 0) - (int)(RecordView.Rows[e.RowIndex2].Tag ?? 0);
			}

		}

		private void RecordView_Sorted(object sender, EventArgs e)
		{

			for (int i = 0; i < RecordView.Rows.Count; i++)
			{
				RecordView.Rows[i].Tag = i;
			}

		}


		private void RecordView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
		{

			SearchArgument args = (SearchArgument)RecordView.Tag;

			if (args.MergeRows)
			{
				// merged

				if (e.ColumnIndex == RecordView_Header.Index ||
					 e.ColumnIndex == RecordView_RankS.Index ||
					 e.ColumnIndex == RecordView_RankA.Index ||
					 e.ColumnIndex == RecordView_RankB.Index)
				{

					if (RecordView[e.ColumnIndex, e.RowIndex].Tag is double)
					{
						e.Value = string.Format("{0} ({1:p1})", e.Value, (double)RecordView[e.ColumnIndex, e.RowIndex].Tag);
					}
					else
					{
						int max = (int)RecordView[e.ColumnIndex, e.RowIndex].Tag;
						e.Value = string.Format("{0}/{1} ({2:p1})", e.Value, max, (double)((int)e.Value) / Math.Max(max, 1));
					}
					e.FormattingApplied = true;
				}

			}
			else
			{
				//not merged

				if (e.ColumnIndex == RecordView_Date.Index)
				{
					e.Value = DateTimeHelper.TimeToCSVString((DateTime)e.Value);
					e.FormattingApplied = true;

				}
				else if (e.ColumnIndex == RecordView_Rank.Index)
				{
					e.Value = Constants.GetWinRank((int)e.Value);
					e.FormattingApplied = true;
				}
			}

		}


		private void RecordView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
		{

			SearchArgument args = (SearchArgument)RecordView.Tag;
			if (args == null || args.MergeRows)
				return;

			try
			{

				DateTime time = Convert.ToDateTime(RecordView[RecordView_Date.Index, e.RowIndex].Value);


				if (!Directory.Exists(Data.Battle.BattleManager.BattleLogPath))
				{
					StatusInfo.Text = "戦闘ログが見つかりませんでした。";
					return;
				}

				StatusInfo.Text = "戦闘ログを検索しています…";
				string battleLogFile = Directory.EnumerateFiles(Data.Battle.BattleManager.BattleLogPath,
					time.ToString("yyyyMMdd_HHmmss", System.Globalization.CultureInfo.InvariantCulture) + "*.txt",
					SearchOption.TopDirectoryOnly)
					.FirstOrDefault();

				if (battleLogFile == null)
				{
					StatusInfo.Text = "戦闘ログが見つかりませんでした。";
					return;
				}

				StatusInfo.Text = string.Format("戦闘ログ {0} を開きます。", Path.GetFileName(battleLogFile));
				System.Diagnostics.Process.Start(battleLogFile);


			}
			catch (Exception)
			{
				StatusInfo.Text = "戦闘ログを開けませんでした。";
			}

		}

	}
}