using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using CommonMP.HYSSOP.Interface.HSData;
using CommonMP.HYSSOP.CoreImpl.HSData;
using CommonMP.HYSSOP.CoreImpl.HSTools;
using CommonMP.HYSSOP.CoreImpl.HSDBA;
using CommonMP.HYSSOP.CoreImpl.HSDBA.FileBase;

namespace CommonMP.HYSSOP.CoreImpl.HSDBA.FileBase
{
    /// <summary><para>class outline:</para>
    /// <para>演算ロット情報DBAクラス</para>
    /// </summary>
    /// <remarks><para>remarks:</para>
    /// <para>演算ロット情報DBへのアクセスを提供する。</para>
    /// <para>本クラスは共通形式ファイル実装である。</para>
    /// <para>DBパス、ファイル名規則に関わる部分のみオーバーライドする。</para>
    /// </remarks>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2009/06/22][新規作成]</para>
    /// </remarks>
    public class HySCalLotInfoDBASub : HySCommonFileDBA
    {
        /// <summary>
        /// 自クラス名(ログ出力用)
        /// </summary>
        private const string m_csMyClassName = "HySCalLotInfoDBASub";

        /// <summary>
        /// DBフォルダパス(ホームディレクトリからの相対パス)
        /// </summary>
        private string m_csDBPath = null;

        /// <summary><para>method outline:</para>
        /// <para>デフォルトコンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>HySCommonDBA csDBA = new HySCalLotInfoDBASub();</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>HySCalLotInfoDBASub 生成されたクラスのインスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>使用禁止</para>
        /// </remarks>
        private HySCalLotInfoDBASub()
        {
        }

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>HySCommonDBA csDBA = new HySCalLotInfoDBASub(csDBPath);</para>
        /// </example>
        /// <param name="csDBPath">DBフォルダ(ホームディレクトリからの相対パス)</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public HySCalLotInfoDBASub(string csDBPath)
            : base()
        {
            m_csDBPath = csDBPath;
        }

        #region カスタマイズパラメータ

        /// <summary>
        /// データファイルプレフィックス
        /// </summary>
        public const string DATAFILE_PREFFIX = "CLot_";

        /// <summary>
        /// データファイル拡張子
        /// </summary>
        public const string DATAFILE_EXTENSION = ".dat";
        
        /// <summary>
        /// メタデータリストファイル名
        /// </summary>
        public const string METADATALIST_FILENAME = "CalLotInfo.mng";

        /// <summary>
        /// メタデータリスト一時ファイル名
        /// </summary>
        public const string TMP_METADATALIST_FILENAME = "TmpCalLotInfo.mng";

        /// <summary>
        /// メタデータリストダンプファイル名
        /// </summary>
        public const string METADATALIST_DUMP_FILENAME = "CalLotInfo.mng.txt";

        #endregion

        #region publicメソッドのオーバーライド

        /// <summary><para>class outline:</para>
        /// <para>1件新規登録</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = RegisterNew(csStockData)</para>
        /// </example>
        /// <param name="csStockData">DB登録データ</param>
        /// <returns>true:成功, false:失敗</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>前処理として、HySStockDataの追加検索キー(KeyInfo)に演算ロット情報の一部を設定する</para>
        /// </remarks>
        public override bool RegisterNew(HySStockData csStockData)
        {
            const string csMyMethodName = "RegisterNew(HySStockData)";

            // 追加検索キーをセットする
            if (!SetKeyInfoOfStockData(csStockData))
            {
                HySDBALog.WriteOnline(m_csMyClassName, csMyMethodName, "SetKeyInfoOfStockData() returned false");
                return false;
            }
            // 登録処理実行
            return base.RegisterNew(csStockData);
        }

        /// <summary><para>method outline:</para>
        /// <para>複数件一括新規登録</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = RegisterNew(csStockDataList) </para>
        /// </example>
        /// <param name="csStockDataList">DB登録データ</param>
        /// <returns>true:成功, false:失敗</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>前処理として、HySStockDataの追加検索キー(KeyInfo)に演算ロット情報の一部を設定する</para>
        /// </remarks>
        public override bool RegisterNew(HySStockDataList csStockDataList)
        {
            const string csMyMethodName = "RegisterNew(HySStockDataList)";

            // 追加検索キーをセットする
            csStockDataList.SetCursorFirst();
            for( long i = 0; i < csStockDataList.GetCount(); i++)
            {
                HySStockData csStockData = (HySStockData)csStockDataList.GetCursorData();
                if (!SetKeyInfoOfStockData(csStockData))
                {
                    HySDBALog.WriteOnline(m_csMyClassName, csMyMethodName, "SetKeyInfoOfStockData() returned false");
                    return false;
                }
                csStockDataList.MoveCursorNext();
            }
            // 登録処理実行
            return base.RegisterNew(csStockDataList);
        }

        /// <summary><para>method outline:</para>
        /// <para>1件更新</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = Update(csStockData) </para>
        /// </example>
        /// <param name="csStockData">DB登録データ</param>
        /// <returns>true:成功, false:失敗</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>前処理として、HySStockDataの追加検索キー(KeyInfo)に演算ロット情報の一部を設定する</para>
        /// </remarks>
        public override bool Update(HySStockData csStockData)
        {
            const string csMyMethodName = "Update";

            // 追加検索キーをセットする
            if (!SetKeyInfoOfStockData(csStockData))
            {
                HySDBALog.WriteOnline(m_csMyClassName, csMyMethodName, "SetKeyInfoOfStockData() returned false");
                return false;
            }
            return base.Update(csStockData);
        }

        #endregion

        #region テンプレートメソッド

        /// <summary><para>method outline:</para>
        /// <para>（オーバーライド）データファイルの拡張子を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> string csExt = GetDataFileExtension() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>演算ロット情報データファイルの拡張子</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override string GetDataFileExtension()
        {
            return DATAFILE_EXTENSION;
        }

        /// <summary><para>method outline:</para>
        /// <para>（オーバーライド）データファイルのプレフィックスを取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> string csPreffix = GetDataFilePreffix() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>演算ロット情報データファイルのプレフィックス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override string GetDataFilePreffix()
        {
            return DATAFILE_PREFFIX;
        }

        /// <summary><para>method outline:</para>
        /// <para>（オーバーライド）メタデータリストファイル名を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> string csFileName = GetMetaDataListFileName() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>メタデータリストファイル名</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override string GetMetaDataListFileName()
        {
            return METADATALIST_FILENAME;
        }

        /// <summary><para>method outline:</para>
        /// <para>（オーバーライド）メタデータリスト一時ファイル名を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> string csFileName = GetTmpMetaDataListFileName() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>メタデータリスト一時ファイル名</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override string GetTmpMetaDataListFileName()
        {
            return TMP_METADATALIST_FILENAME;
        }

        /// <summary><para>method outline:</para>
        /// <para>（オーバーライド）メタデータリストダンプファイル名を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> string csFileName = GetMetaDataListDumpFileName() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>メタデータリストダンプファイル名</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override string GetMetaDataListDumpFileName()
        {
            return METADATALIST_DUMP_FILENAME;
        }

        /// <summary><para>method outline:</para>
        /// <para>（オーバーライド）DBパスを取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> string csPath = GetDBBasePath() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>DBパス名</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override string GetDBBasePath()
        {
            return m_csDBPath;
        }

        /// <summary><para>method outline:</para>
        /// <para>（オーバーライド）検索条件準備</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> string csPath = PrepareQuery(csQueryCtlData, ref csComparerList) </para>
        /// </example>
        /// <param name="csQueryCtlData">検索条件</param>
        /// <param name="csComparerList">フィールド値比較デリゲートリスト</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override void PrepareQuery(HySQueryCtlData csQueryCtlData, ref List<HySDBAFieldComparer> csComparerList)
        {
            // 基本部分の検索条件を初期化する
            base.PrepareQuery(csQueryCtlData, ref csComparerList);

            // 演算ロット固有の検索条件を初期化する
            HySQueryEntryData csQueryEntryData;
            // CALC_EXEC_DATE
            if ((csQueryEntryData = csQueryCtlData.GetQueryEntryData(HySCalLotInfoQueryFieldNames.CALC_EXEC_DATE)) != null)
            {
                csComparerList.Add(new HySDBAFieldComparer(csQueryEntryData, delegate(HySStockData csStockData)
                {
                    long lKeyNumber = 0;
                    HySDataHashTable csHash = csStockData.GetKeyInfo(ref lKeyNumber);
                    if (lKeyNumber > 0)
                    {
                        return csHash[HySCalLotInfoQueryFieldNames.CALC_EXEC_DATE];
                    }
                    else
                    {
                        return HySTime.DEFAULT_TIME;
                    }
                }));
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>（仮想メソッド）部分更新データのチェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = CheckUpdatePartialParameter(csModifyData)</para>
        /// </example>
        /// <param name="csModifyData">部分更新データ</param>
        /// <returns>true:更新可能、false:更新不可(非サポートフィールド名等)</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>保存期限区分のみサポートする</para>
        /// </remarks>
        protected override bool CheckUpdatePartialParameter(HySDataHashTable csModifyData)
        {
            const string csMyMethodName = "CheckUpdatePartialParameter";
            HySDataLinkedList csKeyList = csModifyData.GetKeyList();
            // 空チェック
            if (csKeyList == null)
            {
                HySDBALog.WriteOnline(m_csMyClassName, csMyMethodName, "modifyData is empty");
                return false;
            }
            // 更新対象フィールドチェック
            long lKeyCount = csKeyList.GetCount();
            int iOKFieldCount = 0;
            int iNGFieldCount = 0;
            csKeyList.SetCursorFirst();
            for (long lIdx = 0; lIdx < lKeyCount; ++lIdx)
            {
                HySString csFieldName = (HySString)csKeyList.GetCursorData();
                csKeyList.MoveCursorNext();

                if (HySCalLotInfoQueryFieldNames.PRESERVED_PERIOD.Equal(csFieldName))
                {
                    ++iOKFieldCount;
                }
                else
                {
                    HySDBALog.WriteOnline(m_csMyClassName, csMyMethodName, "field not supported",
                        "FieldName", csFieldName,
                        "Value", csModifyData.GetObject(csFieldName));
                    ++iNGFieldCount;
                }
            }
            if (iOKFieldCount == 0)
            {
                HySDBALog.WriteOnline(m_csMyClassName, csMyMethodName, "no valid field specified");
                return false;
            }
            if (iNGFieldCount > 0)
            {
                return false;
            }

            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>（仮想メソッド）部分更新データの適用</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>ApplyUpdatePartialParameter(csStockData, csModifyData)</para>
        /// </example>
        /// <param name="csStockData">適用対象DB保存データ</param>
        /// <param name="csModifyData">部分更新データ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>保存期限区分と保存期限区分変更日を更新する</para>
        /// </remarks>
        protected override void ApplyUpdatePartialParameter(HySStockData csStockData, HySDataHashTable csModifyData)
        {
            HySLong csPreservedPeriodValue = (HySLong)csModifyData.GetObject(HySCalLotInfoQueryFieldNames.PRESERVED_PERIOD);
            if (csPreservedPeriodValue != null)
            {
                csStockData.SetPeservedPeriod((HySStockData.PeservedPeriod)csPreservedPeriodValue.m_lValue);
                csStockData.SetPreservedPeriodModifyTime(GetToday());
            }
        }

        #endregion

        #region privateメソッド

        /// <summary>
        /// DB登録データに追加検索キーを設定する
        /// </summary>
        /// <remarks>
        /// <para>追加する情報は次の通り</para>
        /// <list type="number">
        /// <item>ロットID (LOT_ID)</item>
        /// <item>基準時間 (SIMULATION_TIME)</item>
        /// <item>開始時間 (START_TIME)</item>
        /// <item>終了時間 (END_TIME)</item>
        /// </list>
        /// </remarks>
        /// <param name="csStockData">DB登録データ</param>
        /// <returns>true:成功、false:失敗(必須キーが未設定)</returns>
        private bool SetKeyInfoOfStockData(HySStockData csStockData)
        {
            const string csMyMethodName = "SetKeyInfoOfStockData";

            HySCalcLotInfo csCalcLotInfo;
            //HySCalLotSuppInfo csCalLotSuppInfo;

            // 演算ロット情報を取得
            csCalcLotInfo = csStockData.GetData() as HySCalcLotInfo;
            if (csCalcLotInfo == null)
            {
                HySDBALog.WriteOnline(m_csMyClassName, csMyMethodName, "StockData.GetData is null or not HySCalcLotInfo");
                return false;
            }

            // 補助情報を取得
            //csCalLotSuppInfo = csCalcLotInfo.GetSuppInfo() as HySCalLotSuppInfo;
            //if (csCalLotSuppInfo == null)
            //{
            //    HySDBALog.WriteOnline(m_csMyClassName, csMyMethodName, "CalcLotInfo.GetSuppInfo is null or not HySCalLotSuppInfo");
            //    return false;
            //}

            // 追加検索キーを一旦クリアする
            HySString[] csKeys = new HySString[] {
                HySCalLotInfoQueryFieldNames.LOT_ID,
                HySCalLotInfoQueryFieldNames.CALC_EXEC_DATE
            };
            long lKeyNumber = 0;
            HySDataHashTable csKeyInfo = csStockData.GetKeyInfo(ref lKeyNumber);
            foreach (HySString csKey in csKeys)
            {
                if (csKeyInfo.GetObject(csKey) != null)
                {
                    csKeyInfo.DeleteData(csKey);
                }
            }
            // 追加検索キーに最新データをセットする
            csKeyInfo.AddObject(HySCalLotInfoQueryFieldNames.LOT_ID, csCalcLotInfo.GetCalcLotID());
            csKeyInfo.AddObject(HySCalLotInfoQueryFieldNames.CALC_EXEC_DATE, csCalcLotInfo.GetCalcExecDate());

            csStockData.SetKeyInfo(csKeyInfo);

            return true;
        }

        #endregion

    }
}
