/// <summary>
/// 流下能力算出用クラス
/// </summary>
/// <create>2010/02/02</create>
/// <modifier></modifier>
/// <modify></modify>
/// <modification></modification>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace lsor
{
    /// <summary><para>class outline:</para>
    /// <para>流下能力算出用クラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[ver 1.0.0][2010/02/02][新規作成]</para>
    /// </remarks>
    class FlowCalculator
    {
        #region プライベート変数

        /// <summary>共通データ</summary>
        private CommonData _commonData = new CommonData();

        /// <summary>キー項目リスト</summary>
        private List<KeyData> _keyList = new List<KeyData>();

        #endregion

        #region プロパティ

        #region 保存ファイル名

        /// <summary><para>method outline:</para>
        /// <para>保存ファイル名を設定・取得する</para>
        /// </summary>
        /// <value>保存ファイル名</value>
        /// <example><para>usage:</para>
        /// <para>string strSaveFileNm = clsFlowCalculator.SaveFileNm()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public string SaveFileNm { get; set; }

        #endregion

        #region キー項目リスト

        /// <summary><para>method outline:</para>
        /// <para>キー項目リストを設定・取得する</para>
        /// </summary>
        /// <value>キー項目リスト</value>
        /// <example><para>usage:</para>
        /// <para>List ＜KeyData＞ keyList = clsFlowCalculator.KeyList()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public List<KeyData> KeyList
        {
            get { return this._keyList; }
            set { this._keyList = value; }
        }

        #endregion

        #endregion

        #region コンストラクタ

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>FlowCalculator csCommonData = new FlowCalculator(commonData)</para>
        /// </example>
        /// <param name="commonData">共通データ</param>
        /// <returns>流下能力算出用クラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public FlowCalculator(CommonData commonData)
        {
            this._commonData = commonData;
        }

        #endregion

        #region パブリックメソッド

        #region 計算実行（係数 a,b,r）

        /// <summary><para>method outline:</para>
        /// <para>計算実行をする（係数 a,b,r）</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = ExecCalcABR()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public bool ExecCalcABR()
        {

            KeyData keyData;

            try
            {
                // 元データの取得
                ArrayList csvDataH = new ArrayList();
                ArrayList csvDataQ = new ArrayList();
                for (int j = 0; j < this._commonData.FlowData.FlowSourceList.Count; j++)
                {
                    string[] dataH = Util.GetData(
                         this._commonData,
                         this._commonData.FlowData.FlowSourceList[j].FileId,
                         this._commonData.FlowData.FlowSourceList[j].ColumnNmH);
                    csvDataH.Add(dataH);

                    string[] dataQ = Util.GetData(
                         this._commonData,
                         this._commonData.FlowData.FlowSourceList[j].FileId,
                         this._commonData.FlowData.FlowSourceList[j].ColumnNmQ);
                    csvDataQ.Add(dataQ);
                }

                // 計算入力ファイルの全行をループ
                for (int i = 0; i < this._commonData.FileList[0].CsvData.Count; i++)
                {

                    // キー項目リストに追加（累加距離まで）
                    keyData = new KeyData();

                    // 河川名
                    keyData.RiverNm = ((string[])this._commonData.FileList[0].CsvData[i])[Util.GetColumnIndex(this._commonData.FileList[0], CommonData.KEY_RIVER_NM)];
                    // topoID
                    keyData.TopoId = ((string[])this._commonData.FileList[0].CsvData[i])[Util.GetColumnIndex(this._commonData.FileList[0], CommonData.KEY_TOPO_ID)];
                    // 断面No
                    keyData.SliceNo = ((string[])this._commonData.FileList[0].CsvData[i])[Util.GetColumnIndex(this._commonData.FileList[0], CommonData.KEY_SLICE_NO)];
                    // 累加距離
                    keyData.SumDistance = ((string[])this._commonData.FileList[0].CsvData[i])[Util.GetColumnIndex(this._commonData.FileList[0], CommonData.KEY_SUM_DISTANCE)];

                    int cnt = this._commonData.FlowData.FlowSourceList.Count;
                    double[,] wk = new double[cnt, 2];
                    double x2 = 0, xy = 0, x1 = 0, y1 = 0, xm = 0, ym = 0, c1 = 0, c2 = 0, c3 = 0, a = 0, b = 0;
                    // a, b, r を算出してキー項目リストに格納

                    // 流下能力算定用データのファイル件数分ループ
                    for (int j = 0; j < cnt; j++)
                    {
                        // 流量と水位を取得し、計算用配列へ格納
                        int fileIdx = Util.GetFileIndex(this._commonData.FileList, this._commonData.FlowData.FlowSourceList[j].FileId);
                        int colIdxH = Util.GetColumnIndex(this._commonData.FileList[fileIdx], this._commonData.FlowData.FlowSourceList[j].ColumnNmH);
                        int colIdxQ = Util.GetColumnIndex(this._commonData.FileList[fileIdx], this._commonData.FlowData.FlowSourceList[j].ColumnNmQ);
                        // (√Q) = (√a)H + (√a)b
                        try
                        {
                            wk[j, 0] = double.Parse(((string[])csvDataH[j])[i]);   // 水位(H)　X軸
                            wk[j, 1] = Math.Sqrt(double.Parse(((string[])csvDataQ[j])[i]));   // 流量(Q)　Y軸
                            x1 += wk[j, 0];
                            y1 += wk[j, 1];
                            x2 += (wk[j, 0] * wk[j, 0]);
                            xy += (wk[j, 0] * wk[j, 1]);
                        }
                        catch
                        {
                        }
                    }

                    try
                    {
                        xm = x1 / cnt;
                        ym = y1 / cnt;
                        a = (cnt * xy - x1 * y1) / (cnt * x2 - x1 * x1);
                        b = (x2 * y1 - x1 * xy) / (cnt * x2 - x1 * x1);
                        keyData.resultA = Math.Round(a * a, 5);
                        keyData.resultB = Math.Round(b / a, 5);

                        for (int j = 0; j < cnt; j++)
                        {
                            c1 += ((wk[j, 0] - xm) * (wk[j, 1] - ym));
                            c2 += ((wk[j, 0] - xm) * (wk[j, 0] - xm));
                            c3 += ((wk[j, 1] - ym) * (wk[j, 1] - ym));
                        }
                        keyData.resultR = Math.Round(c1 / Math.Sqrt(c2 * c3), 5);
                    }
                    catch
                    {
                    }

                    this._keyList.Add(keyData);
                }
            }
            catch
            {
                return false;
            }
            return true;
        }

        #endregion

        #endregion
    }

    /// <summary><para>class outline:</para>
    /// <para>キー項目制御クラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[ver 1.0.0][2010/02/02][新規作成]</para>
    /// </remarks>
    public class KeyData
    {
        #region プロパティ

        /// <summary><para>method outline:</para>
        /// <para>河川名を設定・取得する</para>
        /// </summary>
        /// <value>河川名</value>
        /// <example><para>usage:</para>
        /// <para>string strRiverNm = clsFlowCalculator.RiverNm()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public string RiverNm { get; set; }

        /// <summary><para>method outline:</para>
        /// <para>topoIDを設定・取得する</para>
        /// </summary>
        /// <value>topoID</value>
        /// <example><para>usage:</para>
        /// <para>string strTopoId = clsFlowCalculator.TopoId()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public string TopoId { get; set; }

        /// <summary><para>method outline:</para>
        /// <para>断面Noを設定・取得する</para>
        /// </summary>
        /// <value>断面No</value>
        /// <example><para>usage:</para>
        /// <para>string strSliceNo = clsFlowCalculator.SliceNo()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public string SliceNo { get; set; }

        /// <summary><para>method outline:</para>
        /// <para>累加距離を設定・取得する</para>
        /// </summary>
        /// <value>累加距離</value>
        /// <example><para>usage:</para>
        /// <para>string strSumDistance = clsFlowCalculator.SumDistance()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public string SumDistance { get; set; }

        /// <summary><para>method outline:</para>
        /// <para>結果aを設定・取得する</para>
        /// </summary>
        /// <value>結果a</value>
        /// <example><para>usage:</para>
        /// <para>double dResultA = clsFlowCalculator.resultA()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public double resultA { get; set; }

        /// <summary><para>method outline:</para>
        /// <para>結果bを設定・取得する</para>
        /// </summary>
        /// <value>結果b</value>
        /// <example><para>usage:</para>
        /// <para>double dResultB = clsFlowCalculator.resultB()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public double resultB { get; set; }

        /// <summary><para>method outline:</para>
        /// <para>結果rを設定・取得する</para>
        /// </summary>
        /// <value>結果r</value>
        /// <example><para>usage:</para>
        /// <para>double dResultR = clsFlowCalculator.resultR()</para>
        /// </example>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public double resultR { get; set; }


        #endregion
    }
}
