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;

namespace CommonMP.HYMCO.Ocean.McOceanBaseModel
{
    /// <summary><para>class outline:</para>
    /// <para>細菌（Bacterias)モデル内演算中データクラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[2021/12/31][新規作成]</para>
    /// <para>remarks</para>
    /// <para>演算中の状態、初期条件等を保持するデータクラス</para>
    /// </remarks>
    [Serializable]
    public  class MzOceanNutrientCalInfo : MzOceanModelElementCalInfo
    {
        //-------　要求元素　-----------
        /// <summary>窒素</summary>
        public double[] m_ReqN = null;
        /// <summary>リン量</summary>
        public double[] m_ReqP = null;
        /// <summary>珪素量</summary>
        public double[] m_ReqSi = null;
        /// <summary>鉄量</summary>
        public double[] m_ReqFe = null;
        //-------　提供可能な元素　-----------
        /// <summary>窒素</summary>
        public double[] m_AvailableN = null;
        /// <summary>リン量</summary>
        public double[] m_AvailableP = null;
        /// <summary>珪素量</summary>
        public double[] m_AvailableSi = null;
        /// <summary>鉄量</summary>
        public double[] m_AvailableFe = null;

        /// <summary>溶存有機物（DOM）</summary>
        public double[] mDOM = null;

        //---------------------------------------------------
        /// <summary> 無機物粒子の大きさ分布 </summary>
        public int m_iIOPSizeNum = MzOceanBaseDefine.iPARTICLE_SIZE_NUM;
        public double[] m_IOPSize = null;  // サイズ[mm] 0.1μm,0.2μm,0.5μm,1μm,2μm,5μm, ～ 1m
        /// <summary> 溶融のサイズ依存係数（比） </summary>
        public double[] m_SpdDetritusDISSOLVE = new double[MzOceanBaseDefine.iPARTICLE_SIZE_NUM];

        // ------ 溶解係数
        public double m_Dissolve_Si = 3.0E-2;   // SiO2溶融係数
        public double m_Dissolve_Fe = 3.0E-2;   // Fe2O溶融係数

        // ―――物質の量分布――――
        /// <summary> 無機物粒子  </summary>
        public double m_Density_Si = 2.65;   // SiO2密度  [g/cm^3]
        public double m_Density_Fe = 5.24;   // Fe2O密度  [g/cm^3]
        public double[][] m_Mass_Fe = null;  // 量 g/m3
        public double[][] m_Mass_Si = null;  // 量 g/m3

        //------------------------------------
        public static readonly int Fe = 1;
        public static readonly int Si = 2;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MzOceanNutrientCalInfo()
        {
            for (int i = 0; i < MzOceanBaseDefine.iPARTICLE_SIZE_NUM; i++)
            {
                m_SpdDetritusDISSOLVE[i] = 1.0 / MzOceanBaseDefine.iPARTICLE_SIZE_NUM;
            }
            m_IOPSize = new double[MzOceanBaseDefine.iPARTICLE_SIZE_NUM];
            for (int ll=0; ll< m_lLayerNumber;ll++)
            {
                m_TotalSelfMass[ll] = 0.0;
            }

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

            // サイズ別の溶解速度係数を計算
            double dSpd = 0.0;
            for (int s = 0; s < m_iIOPSizeNum; s++)
            {
                m_SpdDetritusDISSOLVE[s] = 1.0 / m_IOPSize[s];
                dSpd += m_SpdDetritusDISSOLVE[s];
            }
            for (int s = 0; s < m_iIOPSizeNum; s++)
            {
                m_SpdDetritusDISSOLVE[s] = m_SpdDetritusDISSOLVE[s] / dSpd;
            }


        }

        public override void SetLayerNum(long iLayerNum)
        {
            base.SetLayerNum(iLayerNum);
            m_ReqN = new double[m_lLayerNumber];
            m_ReqP = new double[m_lLayerNumber];
            m_ReqSi = new double[m_lLayerNumber];
            m_ReqFe = new double[m_lLayerNumber];
            m_AvailableN = new double[m_lLayerNumber];
            m_AvailableP = new double[m_lLayerNumber];
            m_AvailableSi = new double[m_lLayerNumber];
            m_AvailableFe = new double[m_lLayerNumber];
            mDOM = new double[m_lLayerNumber];


            this.m_Mass_Fe = new double[m_lLayerNumber][];
            this.m_Mass_Si = new double[m_lLayerNumber][];

            for (int ll=0; ll< m_lLayerNumber;ll++)
            {
                m_ReqN[ll] = m_N[ll] = 400.0E-4;
                m_ReqP[ll] = m_P[ll] = 40.0E-4;
                m_ReqSi[ll] = m_Si[ll] = 40.0E-4;
                m_ReqFe[ll] = m_Fe[ll] = 40.0E-4;
                m_AvailableN[ll] = m_N[ll];
                m_AvailableP[ll] = m_P[ll];
                m_AvailableSi[ll] = m_Si[ll];
                m_AvailableFe[ll] = m_Fe[ll];
                mDOM[ll] = 0.0;

                this.m_Mass_Fe[ll] = new double[m_iIOPSizeNum];
                this.m_Mass_Si[ll] = new double[m_iIOPSizeNum];
                for (int i = 0; i < m_iIOPSizeNum; i++)
                {
                    this.m_Mass_Fe[ll][i] = 0.0;
                    this.m_Mass_Si[ll][i] = 0.0;
                }
            }
        }

        public override void Clear()
        {
            base.Clear();
            for (int ll = 0; ll < m_lLayerNumber; ll++)
            {
                m_ReqN[ll] = m_N[ll] = 48.2E-6;
                m_ReqP[ll] = m_P[ll] = 3.48E-6;
                m_ReqSi[ll] = m_Si[ll] = 3.48E-6;
                m_ReqFe[ll] = m_Fe[ll] = 3.48E-6;
                m_AvailableN[ll] = m_N[ll];
                m_AvailableP[ll] = m_P[ll];
                m_AvailableSi[ll] = m_Si[ll];
                m_AvailableFe[ll] = m_Fe[ll];
                mDOM[ll] =0.0;
                for (int i = 0; i < m_iIOPSizeNum; i++)
                {
                    this.m_Mass_Fe[ll][i] = 0.0;
                    this.m_Mass_Si[ll][i] = 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()
        {
            MzOceanNutrientCalInfo csRtn = new MzOceanNutrientCalInfo();
            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);
            MzOceanNutrientCalInfo csOrgDt = (MzOceanNutrientCalInfo)csOrgInfo;
            for (int ll = 0; ll < m_lLayerNumber; ll++)
            {
                this.m_ReqN[ll] = csOrgDt.m_ReqN[ll];
                this.m_ReqP[ll] = csOrgDt.m_ReqP[ll];
                this.m_ReqSi[ll] = csOrgDt.m_ReqSi[ll];
                this.m_ReqFe[ll] = csOrgDt.m_ReqFe[ll];
                this.m_AvailableN[ll] = csOrgDt.m_AvailableN[ll];
                this.m_AvailableP[ll] = csOrgDt.m_AvailableP[ll];
                this.m_AvailableSi[ll] = csOrgDt.m_AvailableSi[ll];
                this.m_AvailableFe[ll] = csOrgDt.m_AvailableFe[ll];
                this.mDOM[ll] = csOrgDt.mDOM[ll];

                for (int k = 0; k < csOrgDt.m_iIOPSizeNum; k++)
                {
                    m_Mass_Fe[ll][k] = csOrgDt.m_Mass_Fe[ll][k];
                    m_Mass_Si[ll][k] = csOrgDt.m_Mass_Si[ll][k];
                }
            }
            return true;
        }

        /// <summary>
        /// 無機物粒子の追加
        /// </summary>
        /// <param name="iKind">種別</param>
        /// <param name="LyrNo">層No</param>
        /// <param name="dTotalMass">総量</param>
        /// <param name="dSize">サイズ</param>
        /// <param name="dDcty">密度</param>
        public virtual void AddIOPMass(int iKind, int LyrNo, double dTotalMass, double dSize, double dDcty)
        {
            if (dTotalMass <= 0.0) { return; }
            double dDDSum = dTotalMass;
            int iSizeLS = 11;

            for (int i = 0; i < m_iIOPSizeNum; i++)
            {
                if (dSize <= 0.9 * m_IOPSize[i] || i == m_iIOPSizeNum - 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)
                        {
                            if (iKind == MzOceanNutrientCalInfo.Fe)
                            {
                                m_Mass_Fe[LyrNo][i - 5 + z] += drp;
                            }
                            else if (iKind == MzOceanNutrientCalInfo.Si)
                            {
                                m_Mass_Si[LyrNo][i - 5 + z] += drp;
                            }
                            dDDSum -= drp;
                            drp = 0;
                        }
                    }
                    drp = dTotalMass * 0.5;
                    for (int z = 0; z < 5; z++)
                    {
                        if (i + z >= m_iIOPSizeNum - 1)
                        {
                            if (iKind == MzOceanNutrientCalInfo.Fe)
                            {
                                m_Mass_Fe[LyrNo][m_iIOPSizeNum - 1] += drp;
                            }
                            else if (iKind == MzOceanNutrientCalInfo.Si)
                            {
                                m_Mass_Si[LyrNo][m_iIOPSizeNum - 1] += drp;
                            }
                            dDDSum -= drp;
                            drp = 0;
                            break;
                        }
                        else
                        {
                            if (iKind == MzOceanNutrientCalInfo.Fe)
                            {
                                m_Mass_Fe[LyrNo][i + z] += dU * (4 - z);
                            }
                            else if (iKind == MzOceanNutrientCalInfo.Si)
                            {
                                m_Mass_Si[LyrNo][i + z] += dU * (4 - z);
                            }
                            drp -= dU * (4 - z);
                            dDDSum -= dU * (4 - z);
                            if (drp <= 0.0)
                            {
                                break;
                            }
                        }
                    }
                    iSizeLS = i;
                    break;
                }
            }
            if (dDDSum > 0.0)
            {
                if (iKind == MzOceanNutrientCalInfo.Fe)
                {
                    m_Mass_Fe[LyrNo][iSizeLS] += dDDSum;
                }
                else if (iKind == MzOceanNutrientCalInfo.Si)
                {
                    m_Mass_Si[LyrNo][iSizeLS] += dDDSum;
                }
            }
  
        }

    }
}
