////////////////////
//Dementia_Pre.cs
////////////////////
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;		//Assemblyを使う為
using System.Diagnostics;		//Stopwatchを使う為
using System.IO;	 			//StreamReader/Writerを使用するのに必要
using System.Text;	 			//Encoding.GetEncodingを使用するのに必要
using System.Windows.Forms.DataVisualization.Charting;	//MS Chartを使用するのに必要

namespace Dementia_Pre
{
	//アプリケーションクラス（解説：DemAppを動かすだけのクラス）
	public class Launcher
	{
		[STAThread]
		public static void Main()
		{
			DemApp da = new DemApp();
			Application.Run(da);
		}
	}

	/////////////////////////////
	//Demntia_Preクラス（DemApp）
	/////////////////////////////
	public class DemApp : Form
	{

		//クラスフィールド
		Button[] Btns = new Button[36];					//36個のボタン（解説：表示する数字は変わります）
		string[] txtStr = {"0", "1", "2", "3", "4",		//ボタン表示用文字列（解説：乱数でシャッフルします）
							"5", "6", "7", "8", "9",
							"A", "B", "C", "D", "E",
							"F", "G", "H", "I", "J",
							"K", "L", "M", "N", "O",
							"P", "Q", "R", "S", "T",
							"U", "V", "W", "X", "Y",
							"Z"};
		string question, answer;						//問題と答え（解説：文字列です）
		Stopwatch stw = new Stopwatch();				//ストップウオッチ（解説：所要時間を図ります）
		string Dem_Pre_Data;							//Dementia_Preの履歴データ（解説：CSVファイルなので、Excelなどで読めますよ）

		//コンストラクター
		public DemApp()
		{
			//プログラムアイコンをフォームにつける
			Assembly myOwn = Assembly.GetEntryAssembly();
			this.Icon = Icon.ExtractAssociatedIcon(myOwn.Location);
			this.Size = new Size(640, 480);
			this.MinimumSize = new Size(320, 190);
			this.Text = "Dementia Prevention";
			this.Load += Initialize;
		}

		//初期化処理
		private void Initialize(object sender, EventArgs e)
		{
			//ボタン x 36
			int w = ClientSize.Width / 6;
			int h = ClientSize.Height / 6;
			for(int y = 0; y < 6; y++)		//解説：縦
			{
				for(int x = 0; x < 6; x++)	//解説：横
				{
					int i = y * 6 + x;
					Btns[i] = new Button();
					Btns[i].Size = new Size(w, h);
					Btns[i].Location = new Point(x * w, y * h);
					Btns[i].Text = txtStr[i];
					Btns[i].Click += Buttons_Click;
					this.Controls.Add(Btns[i]);
				}
			}
			if(LogRead())		//履歴ログを読む（解説：読めたらTrue、不可ならFalse）
			{
				//過去履歴データをグラフ表示
				DemPreChart dpc = new DemPreChart();
				dpc.ShowDialog();
				dpc.Dispose();
			}
			//新しいゲームの開始
			MakeNewQuestion();
		}

		//サイズ変更処理
		protected override void OnResize(EventArgs e)
		{
			base.OnResize(e);
			//ボタン配置更新
			int w = ClientSize.Width / 6;
			int h = ClientSize.Height / 6;
			for(int y = 0; y < 6; y++)		//解説：縦
			{
				for(int x = 0; x < 6; x++)	//解説：横
				{
					int i = y * 6 + x;
					if(Btns[i] != null)
					{	//解説：サイズと位置を変更
						Btns[i].Size = new Size(w, h);
						Btns[i].Location = new Point(x * w, y * h);
					}
				}
			}
		}

		//終了処理
		protected override void OnFormClosing(FormClosingEventArgs e)
		{
			base.OnFormClosing(e);
			DialogResult dr = MessageBox.Show("終了しますか？", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
			if(dr == DialogResult.No)
				e.Cancel = true;
			else
				LogWrite();			//履歴ログを書く
		}

		//すべてのボタンが押された時の処理
		private void Buttons_Click(object sender, EventArgs e)
		{
			//終了処理（"Q"ボタンが押された時に確認してくる）
			if(((Button)sender).Text == "Q")
			{
				Close();
			}
			//答えを生成する
			answer += ((Button)sender).Text;
			//クリックされたボタンのNameを表示する
	 	 	 MessageBox.Show(answer, "現在の答え", MessageBoxButtons.OK, MessageBoxIcon.Information);
			//完了確認（解説：8文字入力されるまではスキップします）
			if(answer.Length == 8)
			{
				stw.Stop();					//解説：ストップウオッチを止めます
				TimeSpan ts = stw.Elapsed;	//分ts.Minutes, 秒ts.Seconds
				string erapsed_time = "所要時間: " + ts.Minutes + "分" + ts.Seconds + "秒";
				string msg, title;
				if(answer == question)
				{
					msg = "正解しました！";
					title = "正解";
				}
				else
				{
					msg = "不正解でした！";
					title = "不正解";
				}
				msg += System.Environment.NewLine + "question: " + question + System.Environment.NewLine + "answer ?: " + answer + System.Environment.NewLine + erapsed_time;
				MessageBox.Show(msg, title, MessageBoxButtons.OK, MessageBoxIcon.Information);
				Dem_Pre_Data += question + "," + answer + "," + (answer == question).ToString() + "," + ts.TotalMinutes.ToString() + System.Environment.NewLine;
				question = answer = string.Empty;
				MakeNewQuestion();
			}
			//新しいボタン表示文字の設定
			ShuffletxtStr();
		}

		//txtStr配列をシャッフルし、ボタン表示文字列も変更する
		private void ShuffletxtStr()
		{
			//乱数の初期化
			Random rand = new Random((int) DateTime.Now.Ticks & 0x0000FFFF);
			for(int i = 35; i >= 0; i--)
			{	//解説：36のアルファベット大文字、数字の配列をシャッフルしています
				int n = rand.Next(i);
				string temp = txtStr[i];
				Btns[i].Text = txtStr[i] = txtStr[n];
				txtStr[n] = temp;
			}
		}

		//新しいquesionを作成する
		private void MakeNewQuestion()
		{
			//乱数の初期化
			Random rand = new Random((int) DateTime.Now.Ticks & 0x0000FFFF);
			for(int i = 0; i < 8; i++)	//解説：乱数で8文字の出題を作成します
			{
				question += txtStr[rand.Next(36)];
			}
			MessageBox.Show("以下の文字列をよく覚えてOKボタンを押してください。" + System.Environment.NewLine + question,
							"ゲーム開始", MessageBoxButtons.OK, MessageBoxIcon.Information);
			//ストップウォッチを初期化して開始する
			stw.Reset();
			stw.Start();
		}

		///////////////////
		//ログファイル処理
		///////////////////
		private bool LogRead()
		{
			try		//解説：エラー処理の為
			{
	 	 	 	using (StreamReader file = new StreamReader(".\\Dem_Pre.log", Encoding.UTF8, false))
				{
					//ファイルを読む
	 	 	 	 	 Dem_Pre_Data = file.ReadToEnd();
					// ファイルを閉じる
					file.Close();
					return true;
				}
			}
			catch(FileNotFoundException e)	//FileNotFoundException用
			{
				MessageBox.Show("Dem_Pre.logファイルを読み込みで、エラーが発生しましたが続行します。\r\n" + e.Message , "Logファイル読込エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return false;
			}
			catch (Exception e)				//FileNotFoundException以外用
			{
				MessageBox.Show("エラーが発生しましたが続行します。\r\n" + e.Message , "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return false;
			}
		}

		private void LogWrite()
		{
			//累計を今回のデータで更新する
	 	 	using (StreamWriter file = new StreamWriter(".\\Dem_Pre.log", false, Encoding.UTF8))
			{
				//ファイルを書く
				file.Write(Dem_Pre_Data);
				// ファイルを閉じる
				file.Close();
			}
		}
	}

	////////////////////
	//DemPreChartクラス
	////////////////////
	public class DemPreChart : Form
	{
		//クラスコントロール
		Chart chart;		//MS Chartコントロール
		Button extBtn;		//終了ボタン
		//クラスフィールド
		double[] dat;		//解説：履歴の所要時間を記録するdouble配列です
		//コンストラクター
		public DemPreChart()
		{
			//プログラムアイコンをフォームにつける
			Assembly myOwn = Assembly.GetEntryAssembly();
			this.Icon = Icon.ExtractAssociatedIcon(myOwn.Location);
			//フォームの設定
			this.Size = new Size(640, 480);
			this.MinimumSize = new Size(320, 190);
			this.Text = "Dementia Prevention Log Chart";
			this.Load += Initialize;
		}

		//初期設定
		private void Initialize(object sender, EventArgs e)
		{
			//MS Chart
			chart = new Chart();
			chart.Location = new Point(10, 10);
			chart.Size = new Size(ClientSize.Width - 20, ClientSize.Height - 60);
			chart.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left);
//			chart.Legends.Add("Legend1");	//Addしないと「凡例」が表示されない
			this.Controls.Add(chart);

			//終了ボタン
			extBtn = new Button();
			extBtn.Location = new Point((ClientSize.Width - extBtn.Width) /2, ClientSize.Height - extBtn.Height - 10);
			extBtn.Text = "終了";
			extBtn.Anchor = (AnchorStyles.Bottom | AnchorStyles.Right);
			extBtn.Click += exitButton_Click;
			this.Controls.Add(extBtn);

			if(IniChart())		//データを読み込む
				ShowChart();	//MS Chartを表示する
		}

		//終了ボタンが押された時の処理
		private void exitButton_Click(object sender, EventArgs e)
		{
			Close();
		}

		//Dem_Pre.logファイル読み込み
		private bool IniChart()
		{
			string data = "";
			//ファイル（UTF-8：Encoding.UTF8）を読む
			try
			{
				using(StreamReader file = new StreamReader("Dem_Pre.log", Encoding.UTF8))
				{
					data = file.ReadToEnd();
					// ファイルを閉じる
					file.Close();
				}
			}
			catch(FileNotFoundException e)	//FileNotFoundException用
	 	 	{
				MessageBox.Show("Dem_Pre.logファイルを読み込めなかったので、履歴グラフを表示できません。このウィンドウを終了させてください。\r\nエラーコード：" + e.Message, "Logファイル読み込みエラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return false;
	 	 	}
			catch(Exception e)	//FileNotFoundException以外用
			{
	 	 		MessageBox.Show("このウィンドウを終了させてください。\r\nエラーコード：" + e.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return false;
			}
			//文字列の行分割
			string[] lines = data.Split(new[]{"\r\n","\n","\r"}, StringSplitOptions.None);
			//行の語分割と実数配列の作成
			dat = new double[lines.Length - 1];				//最終行は空行の為
			for(int ln = 0; ln < lines.Length - 1; ln++)	//最終行は空行の為
			{
				string[] dt = lines[ln].Split(',');
				bool flag;		//検査結果
				double sec;		//所要時間（秒）
				if(!bool.TryParse(dt[2], out flag))
					return false;
				if(!double.TryParse(dt[3], out sec))
					return false;
				dat[ln] = flag ? sec : -sec;	//解説：正解は正（青）、不正解は負（赤）
			}
			return true;
		}

		//MS Chartを表示する
		private void ShowChart()
		{
			//MS Chartの初期化
			chart.Series.Clear();
			chart.ChartAreas.Clear();
			chart.Titles.Clear();
			//タイトル設定
			Title title = new Title("過去の検査履歴（「不正解」はマイナス表示）");
			Title title1 = new Title("所要時間（分）");
			//チャートエリア作成
			ChartArea chartAria = new ChartArea("Area1");
			chartAria.AxisX.Title = "回数";
			chartAria.AxisY.Title = "分";
			//系列の作成
			Series series = new Series();
			series.Color = Color.Transparent;
			series.ChartType = SeriesChartType.Column;	//系列の種類を棒グラフに設定
//			series.LegendText = "凡例:所要時間（分）";	//系列の凡例を設置
			series.BorderWidth = 2;						//系列の境界線太さ
			series.MarkerStyle = MarkerStyle.None;		//系列のポイントマークの形状
	 	 	//読み込んだデータでデータポイントを作成
	 	 	 for (int i = 0; i < dat.Length; i++)
			{
				DataPoint dp = new DataPoint(i + 1, dat[i]);
				//値によって色を変更（解説：正解は正（青）、不正解は負（赤））
				if(dat[i] >= 0)
					dp.Color = Color.Blue;
				else
					dp.Color = Color.Red;
				series.Points.Add(dp);
			}
			//チャート設定
			chart.Titles.Add(title);
			chart.Titles.Add(title1);
			chart.ChartAreas.Add(chartAria);
			chart.Series.Add(series);
			chart.ChartAreas["Area1"].BackColor = Color.WhiteSmoke;	//背景色を変更
		}
	}
}
