using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using CoverageFramework.Model;
using Paraiba.Collections.Generic;
using Paraiba.Core;
using Paraiba.Linq;
using Paraiba.Windows.Forms;

namespace CoverageReporter
{
	public partial class MainForm : Form
	{
		private readonly List<CoverageInfomation> _stmtCov, _branchCov, _condCov, _switchCov;

		public MainForm()
		{
			InitializeComponent();

			_stmtCov = new List<CoverageInfomation>();
			_branchCov = new List<CoverageInfomation>();
			_condCov = new List<CoverageInfomation>();
			_switchCov = new List<CoverageInfomation>();
		}

		private void Form1_Load(object sender, EventArgs e)
		{
			//_txtCovInfoPath.Text = @"C:\work\cobertura\src\main\java\coverageinfo";
			_txtCovInfoPath.Text = Directory.GetCurrentDirectory();
		}

		private void Analyze(IEnumerable<string> resultFileNames)
		{
			IDictionary<string, CoverageInfomation> covInfos;

			// カバレッジ情報（母数）の取得
			using (var fs = new FileStream(_txtCovInfoPath.Text, FileMode.Open))
			{
				var formatter = new BinaryFormatter();
				covInfos = (IDictionary<string, CoverageInfomation>)formatter.Deserialize(fs);
			}

            // カバレッジ収集結果の取得と反映
			foreach (var fileName in resultFileNames)
			{
				using (var reader = new StreamReader(fileName))
				{
					string line;
					while ((line = reader.ReadLine()) != null)
					{
						// 値とキーに分解する
						var words = line.Halve(',');
						var info = covInfos.GetValueOrDefault(words.Value2.Trim());
						var state = words.Value1.Trim().TryToInt();
						if (info != null && state > 0)
						{
							info.State |= (CoverageState)state;
						}
					}
				}
			}

			_stmtCov.Clear();
			_branchCov.Clear();
			_condCov.Clear();
			_switchCov.Clear();

			var tagDict = new HashSet<string>();

			foreach (var item in covInfos)
			{
				var info = item.Value;
				switch (item.Key.Halve(',').Value1.Trim())
				{
				case "stmt":
					_stmtCov.Add(info);
					break;

				case "branch":
					_branchCov.Add(info);
					break;

				case "cond":
					_condCov.Add(info);
					break;

				case "switch":
					_switchCov.Add(info);
					break;

				default:
					continue;
				}
				tagDict.Add(info.Tag);
			}

			var newTagDict = new HashSet<string>();

			foreach (var tag in tagDict)
			{
				var tags = tag.Split('>');
				var str = "";
				// 自分自身と語尾の">"から生成される空文字を除く
				var length = tags.Length - 1;
				for (int i = 0; i < length; i++)
				{
					str += tags[i];
					if (!string.IsNullOrEmpty(str))
						newTagDict.Add(str);
					else
						newTagDict.Add(">");
					str += ">";
				}
			}
			var tagList = newTagDict.ToList();
			tagList.Sort();

			_lbTag.Items.Clear();
			foreach (var tag in tagList)
			{
				_lbTag.Items.Add(tag);
			}
			_lbTag.SelectAll();
			_btnAnalyze.PerformClick();
		}

		private void MainForm_DragEnter(object sender, DragEventArgs e)
		{
			e.Effect = DragDropEffects.All;
		}

		private void MainForm_DragDrop(object sender, DragEventArgs e)
		{
			if (e.Data.GetDataPresent(DataFormats.FileDrop))
			{
				Analyze((string[])e.Data.GetData(DataFormats.FileDrop));
			}
		}

		private void _btnAnalyze_Click(object sender, EventArgs e)
		{
			var robustTags = _lbTag.SelectedItems
				.Cast<object>()
				.Select(item_ => _lbTag.GetItemText(item_))
				.ToList();
			var tags = robustTags
				.Where(t1_ => robustTags.All(t2_ => t1_ == t2_ || !t1_.StartsWith(t2_)))
				.ToList();
			var condCovGroup = _condCov
				.Where(info_ => tags.Any(tag_ => info_.Tag.StartsWith(tag_)))
				.GroupBy(info_ => info_.EntirePosition)
				.ToList();
			var switchCovGroup = _switchCov
				.Where(info_ => tags.Any(tag_ => info_.Tag.StartsWith(tag_)))
				.GroupBy(info_ => info_.EntirePosition)
				.ToList();

			// 命令網羅
			{
				_txtStatement.Clear();
				int nAll = 0, nBad = 0;
				_stmtCov.Where(info_ => tags.Any(tag_ => info_.Tag.StartsWith(tag_)))
					.ForEach(info_ => {
						var prefix = "○";
						if (info_.State != CoverageState.Done)
						{
							prefix = "×";
							nBad++;
						}
						nAll++;
						_txtStatement.AppendText(nAll + ": " + prefix + ": " + info_.Position + "\n");
					});
				if (nAll == 0)
					_pgbStatement.Value = 100;
				else
					_pgbStatement.Value = 100 * (nAll - nBad) / nAll;
				_lbStatement.Text = _pgbStatement.Value + "% : " + (nAll - nBad) + " / " + nAll;
			}

			// 分岐網羅
			{
				_txtBranch.Clear();
				int nAll = 0, nBad = 0;
				_branchCov.Where(info_ => tags.Any(tag_ => info_.Tag.StartsWith(tag_)))
					.ForEach(info_ => {
						var prefix = "○";
						if (info_.State != CoverageState.Done)
						{
							prefix = "×";
							nBad++;
						}
						nAll++;
						_txtBranch.AppendText(nAll + ": " + prefix + ": " + info_.Position + "\n");
					});
				switchCovGroup.ForEach(group_ => {
					var prefix = "○";
					if (group_.Aggregate(CoverageState.Done, (state_, info_) => state_ & info_.State) != CoverageState.Done)
					{
						prefix = "×";
						nBad++;
					}
					nAll++;
					_txtBranch.AppendText(nAll + ": " + prefix + ": " + group_.Key + "\n");
				});
				if (nAll == 0)
					_pgbBranch.Value = 100;
				else
					_pgbBranch.Value = 100 * (nAll - nBad) / nAll;
				_lbBranch.Text = _pgbBranch.Value + "% : " + (nAll - nBad) + " / " + nAll;
			}

			// 条件網羅
			{
				_txtCondition.Clear();
				int nAll = 0, nBad = 0;
				condCovGroup.ForEach(group_ => {
					var prefix = "○";
					if (group_.Aggregate(CoverageState.Done, (state_, info_) => state_ & info_.State) != CoverageState.Done)
					{
						prefix = "×";
						nBad++;
					}
					nAll++;
					_txtCondition.AppendText(nAll + ": " + prefix + ": " + group_.Key + "\n");
				});
				if (nAll == 0)
					_pgbCondition.Value = 100;
				else
					_pgbCondition.Value = 100 * (nAll - nBad) / nAll;
				_lbCondition.Text = _pgbCondition.Value + "% : " + (nAll - nBad) + " / " + nAll;
			}

			// 判定条件網羅
			{
				_txtBranchCond.Clear();
				int nAll = 0, nBad = 0;
				condCovGroup.ForEach(group_ => {
					var branch = _branchCov.Find(info_ => info_.Position.Equals(group_.Key));
					var prefix = "○";
					if (branch == null || branch.State != CoverageState.Done ||
						group_.Aggregate(CoverageState.Done, (state_, info_) => state_ & info_.State) != CoverageState.Done)
					{
						prefix = "×";
						nBad++;
					}
					nAll++;
					_txtBranchCond.AppendText(nAll + ": " + prefix + ": " + group_.Key + "\n");
				});
				switchCovGroup.ForEach(group_ => {
					var prefix = "○";
					if (group_.Aggregate(CoverageState.Done, (state_, info_) => state_ & info_.State) != CoverageState.Done)
					{
						prefix = "×";
						nBad++;
					}
					nAll++;
					_txtBranchCond.AppendText(nAll + ": " + prefix + ": " + group_.Key + "\n");
				});
				if (nAll == 0)
					_pgbBranchCond.Value = 100;
				else
					_pgbBranchCond.Value = 100 * (nAll - nBad) / nAll;
				_lbBranchCond.Text = _pgbBranchCond.Value + "% : " + (nAll - nBad) + " / " + nAll;
			}
		}

		private void _txtCovInfoPath_DragEnter(object sender, DragEventArgs e)
		{
			e.Effect = DragDropEffects.All;
		}

		private void _txtCovInfoPath_DragDrop(object sender, DragEventArgs e)
		{
			if (e.Data.GetDataPresent(DataFormats.FileDrop))
			{
				foreach (var fileName in (string[])e.Data.GetData(DataFormats.FileDrop))
				{
					_txtCovInfoPath.Text = fileName;
					break;
				}
			}
		}
	}
}
