using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using CommonMP.HYSSOP.Interface.HSData;
using CommonMP.HYSSOP.Interface.HSViewer;
using CommonMP.HYSSOP.CoreImpl.HSData;
using CommonMP.HYSSOP.CoreImpl.HSTools;

using CommonMP.HYMCO.Interface.Model;
using CommonMP.HYMCO.Interface.Data;
using CommonMP.HYMCO.Interface.Controller;

using CommonMP.HYMCO.CoreImpl.Data;
using CommonMP.HYMCO.Ocean.McOceanBaseModel;

namespace CommonMP.HYMCO.Ocean.McOceanSampleModels
{
    /// <summary><para>class outline:</para>
    /// <para> デトリタス（Detritus) モデル内演算中データクラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[2021/12/31][新規作成]</para>
    /// <para>remarks</para>
    /// <para>演算中の状態、初期条件等を保持するデータクラス</para>
    /// </remarks>
    [Serializable]
    public  class MzOceanDetritusCalInfo : MzOceanModelElementCalInfo
    {
        /// <summary>要求質量 g/m3</summary>
        public double[] m_TotalReqedDecomposeMass = null;
        public double[] m_TotalDecomposeMass = null;

        /////// <summary> デトリタスの捕獲率 </summary>
        ////public double m_DetritusCatchRatio = 0.4;

        /// <summary> デトリタスの凝集率(<10μm) </summary>
        public double m_AggregationRatio10   = 0.005;
        /// <summary> デトリタスの凝集率(<100μm) </summary>
        public double m_AggregationRatio100  = 0.0025;
        /// <summary> デトリタスの凝集率(<1mm) </summary>
        public double m_AggregationRatio1000 = 0.001;

        //----チェック用-----
        /// <summary> 総入力 </summary>
        public double d_TotalIN = 0.0;
        /// <summary> 総出力(<1mm) </summary>
        public double d_TotalOUT = 0.0;
        /// <summary> 総デトリタス量 </summary>
        public double d_PreTotalMass = 0.0;
        public double d_NowTotalMass = 0.0;
        //-------------------

        /// <summary> デトリタスの分解係数（比） </summary>
        public double[] m_SpdDetritusDECOMPOSE = new double[MzOceanBaseDefine.iPARTICLE_SIZE_NUM];

        //---------------------------------------------------
        /// <summary> デトリタスの大きさ分布 </summary>
        public int m_iDetritusSizeNum = MzOceanBaseDefine.iPARTICLE_SIZE_NUM;
        public double[] m_DetritusSize = null;  // サイズ[mm] 0.1μm,0.2μm,0.5μm,1μm,2μm,5μm, ～ 1m

        // ―――物質の量分布――――
        /// <summary> デトリタス1（Detritus1)  </summary>
        public double[] m_Density_1 = null; //1.075;   // デトリタス１密度  [g/cm^3]
        public double[][] m_DetritusMass_1 = null;  // 量 g/m3
        public double[] m_SumDetritusMass = null;  // 各層の総量 g/m3

        public double[] m_SinkDetritusMass = null;   // 各層の沈降量:割合 0-1

        ///// <summary> デトリタス2（Detritus2)  </summary>
        //public double m_Density_2 =1.027;   // デトリタス２密度  [g/cm^3]   珪素：2.33    ホタテ貝殻(SS,密度= 2.53g/cm3)
        //public double[][] m_DetritusMass_2 = null;  // 量 g/m3

        ///// <summary> デトリタス3（Detritus3)  </summary>
        //public double m_Density_3 = 1.043;   // デトリタス３密度  [g/cm^3] 
        //public double[][] m_DetritusMass_3 = null;  // 量 g/m3

        //public double m_Density_Mean = 1.027;   // 平均密度


        public MzOceanDetritusCalInfo()
        {
            for(int i=0;i< MzOceanBaseDefine.iPARTICLE_SIZE_NUM;i++)
            {
                m_SpdDetritusDECOMPOSE[i] = 1.0 / MzOceanBaseDefine.iPARTICLE_SIZE_NUM;
            }

            m_TotalReqedDecomposeMass = new double[m_lLayerNumber];
            m_TotalDecomposeMass = new double[m_lLayerNumber];
            /// <summary> 粒子状有機物（POM） </summary>
            m_Density_1 = new double[m_lLayerNumber]; // 1.027;   // デトリタス１密度  [g/cm^3]
            //m_Density_2 = 1.075;   // デトリタス２密度  [g/cm^3]   珪素：2.33    ホタテ貝殻(SS,密度= 2.53g/cm3)
            //m_Density_3 = 1.043;   // デトリタス３密度  [g/cm^3] 

            m_iDetritusSizeNum = MzOceanBaseDefine.iPARTICLE_SIZE_NUM;
            m_DetritusSize = new double[m_iDetritusSizeNum];   // サイズ[mm] 0.1μm,0.2μm,0.5μm,1μm,2μm,5μm, ～ 1m
            m_DetritusMass_1 = new double[m_lLayerNumber][];
            //m_DetritusMass_2 = new double[m_lLayerNumber][];
            //m_DetritusMass_3 = new double[m_lLayerNumber][];
            m_SinkDetritusMass = new double[m_lLayerNumber];

            for (int ll = 0; ll < m_lLayerNumber; ll++)
            {
                m_TotalReqedDecomposeMass[ll] = 0.0;
                m_TotalDecomposeMass[ll] = 0.0;
                m_Density_1[ll] = 1.075;
                m_DetritusMass_1[ll] = new double[m_iDetritusSizeNum];
                //m_DetritusMass_2[ll] = new double[m_iDetritusSizeNum];
                //m_DetritusMass_3[ll] = new double[m_iDetritusSizeNum];
                for (int i = 0; i < m_iDetritusSizeNum; i++)
                {
                    m_DetritusMass_1[ll][i] = 0.0;
                }
            }

            double dOrdr = 0.1E-3;
            for (int i = 0; i < m_iDetritusSizeNum; i++)
            {
                if (i % 3 == 0)
                {
                    m_DetritusSize[i] = dOrdr * 1.0;
                }
                else if (i % 3 == 1)
                {
                    m_DetritusSize[i] = dOrdr * 2.0;
                }
                else if (i % 3 == 2)
                {
                    m_DetritusSize[i] = dOrdr * 5.0;
                    dOrdr = dOrdr * 10.0;
                }
            }

            // サイズ別の分解速度係数を計算
            double dSpd = 0.0;
            for (int s = 0; s < m_iDetritusSizeNum; s++)
            {
                m_SpdDetritusDECOMPOSE[s] = Math.Sqrt(0.1E-3 / m_DetritusSize[s]);
                dSpd += m_SpdDetritusDECOMPOSE[s];
            }
            for (int s = 0; s < m_iDetritusSizeNum; s++)
            {
                m_SpdDetritusDECOMPOSE[s] = m_SpdDetritusDECOMPOSE[s] / dSpd;
            }

        }

        public override void SetLayerNum(long iLayerNum)
        {
            base.SetLayerNum(iLayerNum);

            m_TotalReqedDecomposeMass = new double[m_lLayerNumber];
            m_TotalDecomposeMass = new double[m_lLayerNumber];

            this.m_Density_1 = new double[this.m_lLayerNumber];
            this.m_DetritusMass_1 = new double[m_lLayerNumber][];
            this.m_SumDetritusMass = new double[this.m_lLayerNumber];
            this.m_SinkDetritusMass = new double[this.m_lLayerNumber];

            for (int ll = 0; ll < m_lLayerNumber; ll++)
            {
                m_TotalReqedDecomposeMass[ll] = 0.0;
                m_TotalDecomposeMass[ll] = 0.0;
                this.m_Density_1[ll] = 1.075;
                this.m_DetritusMass_1[ll] = new double[m_iDetritusSizeNum];
                //m_DetritusMass_2[ll] = new double[m_iDetritusSizeNum];
                //m_DetritusMass_3[ll] = new double[m_iDetritusSizeNum];
                for (int i = 0; i < m_iDetritusSizeNum; i++)
                {
                    this.m_DetritusMass_1[ll][i] = 0.0;
                    //this.m_DetritusMass_2[ll][i] = 0.0;
                    //this.m_DetritusMass_3[ll][i] = 0.0;
                }
                this.m_SumDetritusMass[ll] = 0.0;
                this.m_SinkDetritusMass[ll] = 0.0;
            }
        }


        public override void Clear()
        {
            base.Clear();
 
            for (int ll = 0; ll < m_lLayerNumber; ll++)
            {
                m_TotalReqedDecomposeMass[ll] = 0.0;
                m_TotalDecomposeMass[ll] = 0.0;
                this.m_Density_1[ll] = 1.075;
                for (int i = 0; i < m_iDetritusSizeNum; i++)
                {
                    this.m_DetritusMass_1[ll][i] = 0.0;
                    //this.m_DetritusMass_2[ll][i] = 0.0;
                    //this.m_DetritusMass_3[ll][i] = 0.0;
                }
                this.m_SumDetritusMass[ll] = 0.0;
                this.m_SinkDetritusMass[ll] = 0.0;
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>自己複製</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Clone( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>同一内容で　別院スタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>収束演算時、特定の時刻に状態を戻す場合等に使用する</para>
        /// </remarks>
        public override McCalInfo Clone()
        {
            MzOceanDetritusCalInfo csRtn = new MzOceanDetritusCalInfo();
            csRtn.CopyInfo(this);
            return csRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>引数で与えられた情報を自分にコピーを行う</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = CopyInfo(csOrgInfo) </para>
        /// </example>
        /// <param name="csOrgInfo">コピー元情報</param>
        /// <returns> bool true :正常 , false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool CopyInfo(McCalInfo csOrgInfo)
        {
            base.CopyInfo(csOrgInfo);
            MzOceanDetritusCalInfo csOrgDt = (MzOceanDetritusCalInfo)csOrgInfo;
            this.m_AggregationRatio10 = csOrgDt.m_AggregationRatio10;
            this.m_AggregationRatio100 = csOrgDt.m_AggregationRatio100;
            this.m_AggregationRatio1000 = csOrgDt.m_AggregationRatio1000;
            this.d_TotalIN = csOrgDt.d_TotalIN;
            this.d_TotalOUT = csOrgDt.d_TotalOUT;

            for (int i = 0; i < csOrgDt.m_lLayerNumber; i++)
            {
                m_TotalReqedDecomposeMass[i] = csOrgDt.m_TotalReqedDecomposeMass[i];
                m_TotalDecomposeMass[i] = csOrgDt.m_TotalDecomposeMass[i];
                m_Density_1[i] = csOrgDt.m_Density_1[i];   // デトリタス１密度  [g/cm^3]
                for (int k = 0; k < csOrgDt.m_iDetritusSizeNum; k++)
                {
                    m_DetritusMass_1[i][k] = csOrgDt.m_DetritusMass_1[i][k];
                    //m_DetritusMass_2[i][k] = csOrgDt.m_DetritusMass_2[i][k];
                    //m_DetritusMass_3[i][k] = csOrgDt.m_DetritusMass_3[i][k];
                }
                this.m_SumDetritusMass[i] = csOrgDt.m_SumDetritusMass[i];
                this.m_SinkDetritusMass[i] = csOrgDt.m_SinkDetritusMass[i];
            }
            return true;
        }

        /// <summary>
        /// デトリタスの追加
        /// </summary>
        /// <param name="LyrNo">層No</param>
        /// <param name="dTotalMass">総量</param>
        /// <param name="dSize">サイズ</param>
        /// <param name="dDcty">密度</param>
        public virtual void AddDetritus(int LyrNo, double dTotalMass, double dSize, double dDcty)
        {
            if (dTotalMass <= 0.0) { return; }
            double dSumLLMass = m_SumDetritusMass[LyrNo];
            double dDDSum = dTotalMass;
            int iSizeLS = 11;

            for (int i = 0; i < m_iDetritusSizeNum; i++)
            {
                if (dSize <= 0.9 * m_DetritusSize[i] || i == m_iDetritusSizeNum - 1)
                {
                    // サイズのバラつきを考慮して、幅を持ってばらまく。
                    double dU = dTotalMass * 0.5 * 0.1;
                    double drp = 0.0;
                    for (int z = 0; z < 5; z++)
                    {
                        drp += dU * z;
                        if (i - 5 + z >= 0)
                        {
                            m_DetritusMass_1[LyrNo][i - 5 + z] += drp;
                            dDDSum -= drp;
                            drp = 0;
                        }
                    }
                    drp = dTotalMass * 0.5;
                    for (int z = 0; z < 5; z++)
                    {
                        if (i + z >= m_iDetritusSizeNum - 1)
                        {
                            m_DetritusMass_1[LyrNo][m_iDetritusSizeNum - 1] += drp;
                            dDDSum -= drp;
                            drp = 0;
                            break;
                        }
                        else
                        {
                            m_DetritusMass_1[LyrNo][i + z] += dU * (4 - z);
                            drp -= dU * (4 - z);
                            dDDSum -= dU * (4 - z);
                            if (drp <= 0.0)
                            {
                                break;
                            }
                        }
                    }
                    iSizeLS = i;
                    break;
                }
            }   // end of for(i)
            if( dDDSum > 0.0 )
            {
                m_DetritusMass_1[LyrNo][iSizeLS] += dDDSum;
            }


            m_SumDetritusMass[LyrNo] = 1E-42;
            for (int i = 0; i < m_iDetritusSizeNum; i++)
            {
                m_SumDetritusMass[LyrNo] += m_DetritusMass_1[LyrNo][i];
            }
            m_Density_1[LyrNo] = (dSumLLMass * m_Density_1[LyrNo] + dTotalMass * dDcty) / (dSumLLMass + dTotalMass);
            m_SumDetritusMass[LyrNo] -= 1E-42;
        }


    }
}
