// <summary>ソースコード：ツールのパッケージ化　ツールエクスポータークラス</summary>
// <author>CommonMP</author>

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

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

namespace CommonMP.HYSSOP.OptionImpl.HySToolExport
{
    /// <summary><para>class outline:</para>
    /// <para>パッケージ出力　ツールエクスポータークラス</para>
    /// </summary>
    /// <remarks><para>remarks:</para>
    /// <para>無し</para>
    /// </remarks>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.3.0][2012/12/10][新規作成]</para>
    /// </remarks>
    public class HySToolExporter
    {
        /// <summary><para>method outline:</para>
        /// <para>出力実行</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> int iResult = Export(csExportInfo) </para>
        /// </example>
        /// <param name="csExportInfo">ライブラリ出力情報</param>
        /// <returns><para>0: 正常終了 -4:ZIP形式変換エラー -5:入出力エラー</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public int Export(HySToolExportInfo csExportInfo)
        {
            HySString csArchiveFillFullPath = null;
            try
            {
                // アーカイブ対象エントリ作成
                List<KeyValuePair<HySStringRoot, HySStringRoot>> csEntryList = CreateTargetEntry(csExportInfo);

                // エントリを追加
                HySArchiver csZipArchiver = new HySDotNetZipArchiver();
                csZipArchiver.AddEntry(csEntryList);

                // アーカイブ出力実行
                csArchiveFillFullPath = csExportInfo.GetArchiveFileFullpath();
                csZipArchiver.Archive(csArchiveFillFullPath);
            }
            // Zipファイル形式エラー
            catch (Ionic.Zip.ZipException exp)
            {
                DeleteFile(csArchiveFillFullPath);
                HySToolExportProgram.ErrorLOG("HySToolExporter.Export",
                    "アーカイブ出力処理で例外発生:" + exp.ToString() + " " +
                    "csArchiveFillFullPath:" + csArchiveFillFullPath.ToString()
                    );
                return (-4);
            }
            catch (System.UnauthorizedAccessException exp)
            {
                DeleteFile(csArchiveFillFullPath);
                HySToolExportProgram.ErrorLOG("HySToolExporter.Export",
                    "アーカイブ出力処理で例外発生:" + exp.ToString() + " " +
                    "csArchiveFillFullPath:" + csArchiveFillFullPath.ToString()
                    );
                return (-4);
            }
            catch (System.IO.FileNotFoundException exp)
            {
                DeleteFile(csArchiveFillFullPath);
                HySToolExportProgram.ErrorLOG("HySToolExporter.Export",
                    "アーカイブ出力処理で例外発生:" + exp.ToString() + " " +
                    "csArchiveFillFullPath:" + csArchiveFillFullPath.ToString()
                    );
                return (-5);
            }
            return 0;
        }

        /// <summary><para>method outline:</para>
        /// <para>ツール出力対象ファイルエントリ取得</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> List csEntries = CreateTargetEntry(csExportInfo) </para>
        /// </example>
        /// <param name="csExportInfo">ツール出力情報</param>
        /// <returns><para>エントリ情報リスト</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static private List<KeyValuePair<HySStringRoot, HySStringRoot>> CreateTargetEntry(HySToolExportInfo csExportInfo)
        {
            List<KeyValuePair<HySStringRoot, HySStringRoot>> csEntries = new List<KeyValuePair<HySStringRoot, HySStringRoot>>();

            // プロジェクトフォルダパス取得
            HySString csProjectFolderFullpath = csExportInfo.GetProjectFolderFullpath();

            // Ver1.5 追加（プラットフォーム取得）
            string sPlatform = "\\x86";

            if (System.Environment.Is64BitProcess == true)
            {
                sPlatform = "\\x64";
            }
            
            //-----------------------------------------
            // 実行形式ファイル(.dll、.exe)のエントリ設定
            //-----------------------------------------
            // ツールプロジェクトの実行形式ファイル設定
            HySDataLinkedList csBinaryFullpathList = csExportInfo.GetBinaryFullpathList();

            HySString csEntryRootFolPath = csProjectFolderFullpath + new HySString("\\bin\\Release");
          //HySString csEntryRootFolPath = csProjectFolderFullpath + "\\bin" + sPlatform + "\\Release"; // Ver1.5 追加（プラットフォーム取得）

            List<KeyValuePair<HySStringRoot, HySStringRoot>> csBinaryEntries = CreateTargetEntrySub(
                csEntryRootFolPath,
                csBinaryFullpathList,
                new HySString("bin")
                );
            csEntries.AddRange(csBinaryEntries);
            
            //-----------------------------------------
            // ツールアイコン(.ico)のエントリ設定
            //-----------------------------------------
            // ToolIconファイルのエントリ名とファイルフルパスをリストにセット
            HySDataLinkedList csToolIconFullpathList = csExportInfo.GetToolIconFullpathList();

            List<KeyValuePair<HySStringRoot, HySStringRoot>> csEntryList = CreateTargetEntrySub(
                csProjectFolderFullpath,
                csToolIconFullpathList
                );
            csEntries.AddRange(csEntryList);

            //-----------------------------------------
            // ツール解説書(.pdf)のエントリ設定
            //-----------------------------------------
            // ToolManualファイルのエントリ名とファイルフルパスをリストにセット
            HySDataLinkedList csManualFullpathList = csExportInfo.GetManualFullPathList();

            csEntryList = CreateTargetEntrySub(
                csProjectFolderFullpath,
                csManualFullpathList
                );
            csEntries.AddRange(csEntryList);

            //-----------------------------------------
            // 開発コードのエントリ設定
            //-----------------------------------------
            // 開発コード出力要否を判定する
            if (csExportInfo.GetOutputSourceCode())
            {
                // プロジェクト名取得
                string[] sSplitFolderPath = csProjectFolderFullpath.ToString().Split('\\');

                string sProjectName = "";
                if (sSplitFolderPath[sSplitFolderPath.Length - 1] == "")
                {
                    sProjectName = sSplitFolderPath[sSplitFolderPath.Length - 2];
                }
                else
                {
                    sProjectName = sSplitFolderPath[sSplitFolderPath.Length - 1];
                }

                // ツールプロジェクトの開発コード設定
                HySDataLinkedList csDevSrcFullPathList = csExportInfo.GetDevelopmentSourceFullPathList();
                List<KeyValuePair<HySStringRoot, HySStringRoot>> csOutPutSrcEntries = CreateTargetEntrySub(
                    csProjectFolderFullpath,
                    csDevSrcFullPathList,
                    new HySString(@"VsToolProject\" + sProjectName)
                    );
                csEntries.AddRange(csOutPutSrcEntries);
            }
 
            return csEntries;
        }

        /// <summary><para>method outline:</para>
        /// <para>ツール出力対象ファイルエントリ作成サブメソッド</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> List csEntries = CreateTargetEntrySub(csProjectFolderFullPath, csFileList) </para>
        /// </example>
        /// <param name="csProjectFolderFullPath">プロジェクトフォルダフルパス</param>
        /// <param name="csFileList">ファイルリスト</param>
        /// <returns><para>エントリ情報リスト</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static private List<KeyValuePair<HySStringRoot, HySStringRoot>> CreateTargetEntrySub(
            HySString csProjectFolderFullpath,
            HySDataLinkedList csFileList
            )
        {
            List<KeyValuePair<HySStringRoot, HySStringRoot>> csEntries =
                new List<KeyValuePair<HySStringRoot,HySStringRoot>>();

            HySString csEntryName = new HySString();
            HySString csFilePath = new HySString();
            for (int i = 0; i < (int)csFileList.GetCount(); i++)
            {
                // プロジェクト名より後ろの文字列をエントリ名として、
                csFilePath =(HySString)csFileList.GetData(i);
                //---------------------------------------------------------------------
                // エントリ名作成
                //   プロジェクトパス配下のデータをエントリ名とする
                // 【例】
                //   プロジェクトフォルダフルパス(csProjectFolderFullpath)："C:\Project"
                //   ファイルパス(csFilePath)："C:\Project\ToolIcon\icon.ico"
                //   の場合、エントリ名"ToolIcon\icon.ico"を作成する
                //---------------------------------------------------------------------
                csEntryName = new HySString(
                    csFilePath.ToString().Remove(0, (csProjectFolderFullpath.ToString().Length) + 1));
                KeyValuePair<HySStringRoot, HySStringRoot> csKeyValuePair =
                    new KeyValuePair<HySStringRoot, HySStringRoot>(csEntryName, csFilePath);
                csEntries.Add(csKeyValuePair);
            }
            return csEntries;
        }

        /// <summary><para>method outline:</para>
        /// <para>ツール出力対象ファイルエントリ作成サブメソッド(上位フォルダ指定)</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> List csEntries = CreateTargetEntrySub(csEntryRootFolderFullPath, csFullPathList, csEntryTopFolderNam) </para>
        /// </example>
        /// <param name="csEntryRootFolderFullPath">エントリのルートフォルダとなるフォルダパス</param>
        /// <param name="csFileFullPathList">エントリ対象ファイルパスのリスト</param>
        /// <param name="csEntryTopFolderName">エントリの上位フォルダ名("[root]\XXXX\"のXXXXの部分)</param>
        /// <returns><para>エントリ情報リスト</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>本メソッドはエントリの上位フォルダの名称を指定する場合に使用する。
        /// エントリ対象ファイルパスがない場合は要素数0のリストを返却する</para>
        /// </remarks>
        static private List<KeyValuePair<HySStringRoot, HySStringRoot>> CreateTargetEntrySub(
            HySString csEntryRootFolderFullPath,
            HySDataLinkedList csFileFullPathList,
            HySString csEntryTopFolderName
            )
        {
            // (エントリ名、絶対ファイルパス)のキーペアリストを生成
            List<KeyValuePair<HySStringRoot, HySStringRoot>> csEntries =
                new List<KeyValuePair<HySStringRoot, HySStringRoot>>();

            // エントリ対象ファイルパスリストの要素数分、キーペア(エントリ)を作成
            csFileFullPathList.SetCursorFirst();
            for (long lLp = 0; lLp < csFileFullPathList.GetCount(); lLp++)
            {
                HySString csFilePath = (HySString)csFileFullPathList.GetCursorData();
                //---------------------------------------------------------------------------
                // エントリ名作成(上位フォルダ指定)
                //   指定されたルートパスを上位フォルダ名で置換したデータをエントリ名とする
                // 【例】
                //   エントリルートパス(csEntryRootFolderFullPath)："C:\Project"
                //   エントリ上位フォルダ名(csEntryTopFolderName)："VsToolProject"
                //   ファイルパス(csFilePath)："C:\Project\classA.cs"
                //   の場合、エントリ名"VsToolProject\classA.cs"を作成する
                //---------------------------------------------------------------------------
                HySString csEntryName = csFilePath.Clone().Remove(0, csEntryRootFolderFullPath.GetLength() + 1);
                csEntryName = csEntryTopFolderName + new HySString("\\") + csEntryName;
                KeyValuePair<HySStringRoot, HySStringRoot> csEntry =
                    new KeyValuePair<HySStringRoot, HySStringRoot>(csEntryName, csFilePath);
                csEntries.Add(csEntry);
                csFileFullPathList.MoveCursorNext();
            }
            return csEntries;
        }

        /// <summary><para>method outline:</para>
        /// <para>ファイル削除</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> DeleteFile(csFileFullPath) </para>
        /// </example>
        /// <param name="csFileFullPath">ファイルフルパス</param>
        /// <returns><para>無し</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static private void DeleteFile(HySString csFileFullPath)
        {
            bool bResult = HySFileUtility.ExistFile(csFileFullPath);
            if(bResult == true)
            {
                HySFileUtility.Delete(csFileFullPath);
            }
        }
    }
}
