//----------------------------------------------------------------------
//	IIR フィルタの係数をファイルから読み込むメソッド ReadFile()
//
//		作成者：三上直樹，2022/12/04 作成，ⓒ三上直樹 2022
//----------------------------------------------------------------------

using System;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.IO;
using Mikami.Filter;

namespace IIRフィルタ_係数読込_正弦波入力_波形
{
	public partial class Form1 : Form
	{
		private bool ReadFile(ref double[] akD, ref double[] bkD,
							  ref BiquadD.Coefs[] ckD, ref double g0D)
		{
			if (openFileDialog1.ShowDialog() != DialogResult.OK) return false;

			// Shift-JIS としてファイルを読み込む
			string[] strIn = File.ReadAllLines(openFileDialog1.FileName, Encoding.Default);
			if (!strIn.Any(s => s.Contains("標本化周波数")) || !strIn.Any(s => s.Contains("次数")))
			{
				// UTF-8 としてファイルを読み込む
				strIn = File.ReadAllLines(openFileDialog1.FileName, Encoding.UTF8);
				if (ErrMsgDirect(strIn.Any(s => s.Contains("標本化周波数")) &&
						   strIn.Any(s => s.Contains("次数")), ref akD, ref bkD,
						   "データのフォーマットが違っているか\r\n"+
						   "文字コードがシフトJIS または UTF-8 以外の可能性があります．"))
					return false;
			}

			textBox1.Clear();
			foreach (string s in strIn.Where(s2 => s2.StartsWith("// ")))
				textBox1.AppendText(s.Replace("// ", " ")+"\r\n");

			// 標本化周波数の読み込み
			double fSkHz = -1;
			var strFs = strIn.FirstOrDefault(s => s.Contains("標本化周波数"));
			if (strFs != null)
			{
				string fsText = strFs.Split(' ').Where(s => (s != "") && !s.Contains("kHz"))
									 .Last();
				if (ErrMsgDirect(double.TryParse(fsText, out fSkHz), ref akD, ref bkD,
						   "標本化周波数に対応する数値が見つかりません．")) return false;
			}

			if (ErrMsgDirect((float)(fSkHz*1000) == FS_, ref akD, ref bkD,
					   "ファイルの標本化周波数は 10 kHz ではありません．")) return false;

			// 次数の読み込み
			int order = -1;
			var strOrder = strIn.FirstOrDefault(s => s.Contains("次数"));
			if (strOrder != null)
			{
				var orderText = strOrder.Split(' ').Where(s => (s != "") && !s.Contains("次"))
										.Last();
				if (ErrMsgDirect(int.TryParse(orderText, out order), ref akD, ref bkD,
						   "次数に対応する数値が見つかりません．")) return false;
			}

			// 直接形の係数の処理
			if (ErrMsgDirect(strIn.Any(s => s.Contains("直接形の係数")), ref akD, ref bkD,
					   "「直接形の係数」という文字列が見つかりません．")) return false;

			int lines;
			for (lines=0; lines<strIn.Length; lines++)
				if (strIn[lines].Contains("直接形の係数")) break;

			lines += 2;
			if (ErrMsgDirect(!strIn[lines].Contains("f"), ref akD, ref bkD,
					   "double 型の係数を使ってください．")) return false;

			Array.Resize(ref akD, order);
			Array.Resize(ref bkD, order+1);
			for (int k=0; k<=order; k++)
			{
				var str = strIn[k+lines].Split(' ').Where(s => s != "");
				if (k != 0)
					if (ErrMsgDirect(double.TryParse(str.ElementAt(1), out akD[k-1]), ref akD, ref bkD,
						"不正なデータです．")) return false;
				if (ErrMsgDirect(double.TryParse(str.Last(), out bkD[k]), ref akD, ref bkD,
					"不正なデータです．")) return false;
			}

			// 縦続形の係数の処理
			if (ErrMsgCascade((order % 2) == 0, ref ckD, ref g0D,
					   "次数は偶数にしてください．")) return false;

			if (ErrMsgCascade(strIn.Any(s => s.Contains("縦続形の係数")), ref ckD, ref g0D,
					   "「縦続形の係数」という文字列が見つかりません．")) return false;
			
			for (lines=0; lines<strIn.Length; lines++)
				if (strIn[lines].Contains("縦続形の係数")) break;

			lines++;
			if (ErrMsgCascade(!strIn[lines].Contains("f"), ref ckD, ref g0D,
					   "double 型の係数を使ってください．")) return false;

			Array.Resize(ref ckD, order/2);
			for (int m=0; m<order/2; m++)
			{
				double[] ab = new double[5];
				for (int k=0; k<5; k++)
				{
					var str = strIn[k+lines].Split(' ').Last();
					if (ErrMsgCascade(double.TryParse(str, out ab[k]), ref ckD, ref g0D,
						"不正なデータです．")) return false;

				}
				lines += 6;
				ckD[m] = new BiquadD.Coefs(ab[0], ab[1], ab[3], ab[4]);
			}

			if (ErrMsgCascade(double.TryParse(strIn[lines].Split(' ').Last(), out g0D),
					   ref ckD, ref g0D, "不正なデータです．")) return false;

			return true;
		}

		// tf が false の場合，エラーメッセージを表示し，true を返す
		bool ErrMsgDirect(bool tf, ref double[] akD, ref double[] bkD, string str)
		{
			if (!tf)
			{
				MessageBox.Show(str);
				textBox1.Clear();
				Array.Resize(ref akD, 1);
				Array.Resize(ref bkD, 2);
				akD = new double[]{0.0};
				bkD = new double[]{1.0, 0.0};
			}
			return !tf;
		}
		// tf が false の場合，エラーメッセージを表示し，true を返す
		bool ErrMsgCascade(bool tf, ref BiquadD.Coefs[] ckD, ref double g0D, string str)
		{
			if (!tf)
			{
				MessageBox.Show(str);
				textBox1.Clear();
				Array.Resize(ref ckD, 1);
				ckD[0] = new BiquadD.Coefs(0, 0, 0, 0);
				g0D = 1.0;
			}
			return !tf;
		}
	}
}
