// <summary>ソースコード：ツールインポータークラス</summary>
// <author>CommonMP</author>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

using CommonMP.HYSSOP.Interface.HSController;
using CommonMP.HYSSOP.Interface.HSData;
using CommonMP.HYSSOP.Interface.HSTools;
using CommonMP.HYSSOP.Interface.HSViewer;
using CommonMP.HYSSOP.CoreImpl;
using CommonMP.HYSSOP.CoreImpl.HSData;
using CommonMP.HYSSOP.CoreImpl.HSTools;
using CommonMP.HYSSOP.OptionImpl.HSViewer.DotNetViewer;

namespace CommonMP.HYSSOP.OptionImpl.HSToolImportViewer
{
    /// <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 HSToolImporter
    {
        /// <summary> アーカイブファイル </summary>
        HySString m_archiveFileFullPath;

        /// <summary> XMLタグ　tools </summary>
        static public readonly string xml_TOOLS = "tools";
        /// <summary> XMLタグ　tool </summary>
        static public readonly string xml_TOOL = "tool";
        /// <summary> XMLタグ　dll </summary>
        static public readonly string xml_DLL = "dll";
        /// <summary> XMLタグ　name </summary>
        static public readonly string xml_NAME = "name";
        /// <summary> XMLタグ　package </summary>
        static public readonly string xml_PACKAGE = "package";
        /// <summary> XMLタグ　filepath </summary>
        static public readonly string xml_FILEPATH = "filepath";


        /// <summary> 削除管理コード　ファイル[F] </summary>
        static private readonly string TOOL_KIND_FILE = "[F]";
        /// <summary> 削除管理コード　ディレクトリ[D] </summary>
        static private readonly string TOOL_KIND_DIR = "[D]";

        /// <summary><para>method outline:</para>
        /// <para>入力実行</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> int result = Import(archiveFileFullPath) </para>
        /// </example>
        /// <param name="archiveFileFullPath">アーカイブファイルパス</param>
        /// <returns><para>0: 正常終了 -1:ZIP形式変換エラー</para>
        /// <para>-2:入出力エラー -3:サポート対象外データ -4:インストール情報作成異常</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks> 
//        static public int Import(
        public int Import(
            HySString archiveFileFullPath
            )
        {
            // アーカイブファイル
            m_archiveFileFullPath = archiveFileFullPath;

            try
            {//
                HySExpander zipExpander = new HySDotNetZipExpander(archiveFileFullPath);

                // エントリ名取得
                List<HySStringRoot> entryList = zipExpander.GetAllEntryName();

                // 指定されたアーカイブがサポート対象か判定する
                bool result = IsSupportArchive(
                    archiveFileFullPath,
                    entryList
                    );
                if (result == false)
                {
                    //HySLog.LogOut(
                    //    HySLog.ONLINE,
                    //    "HSToolImporter",
                    //    "Import",
                    //    "archiveFileFullPath:" + archiveFileFullPath.ToString()
                    //    );
                    HSToolImportViewerProgram.ErrorLOG("HSToolImporter.Import", "archiveFileFullPath:" + archiveFileFullPath.ToString());
                    return (-3);
                }

                //// 展開対象パスを作成
                //entryList = CreateTargetEntry(entryList);
                //// 作成したパスを展開対象エントリに指定
                //zipExpander.AddTargetEntry(entryList);

                //
                Hashtable csEntryDir = new Hashtable();
                zipExpander.Read();
                entryList = CreateTarget(entryList, ref zipExpander, ref csEntryDir);

                // ホームディレクトリパス取得
                HySString homeDirectory = HySEnvInf.GetHomeDirectory();
//                zipExpander.Expand(homeDirectory);
                zipExpander.EditExpand(homeDirectory);

                // インストール情報作成
                if (MakeImportFileInfo(entryList, csEntryDir) != 0)
                {
                    return -4;
                }
            }
            // Zipファイル形式エラー
            catch (Ionic.Zip.ZipException exp)
            {
                //HySLog.LogOut(
                //    HySLog.ONLINE,
                //    "HSToolImporter",
                //    "Import",
                //    "アーカイブ展開処理で例外発生:" + exp.ToString() +
                //    "archiveFileFullPath:" + archiveFileFullPath.ToString()
                //    );
                HSToolImportViewerProgram.ErrorLOG("HSToolImporter.Import", "アーカイブ展開処理で例外発生:" + exp.ToString() + "archiveFileFullPath:" + archiveFileFullPath.ToString());
                return -1;
            }
            catch (System.IO.FileNotFoundException exp)
            {
                //HySLog.LogOut(HySLog.ONLINE, "HSToolImporter", "Import",
                //    "アーカイブ展開処理で例外発生:" + exp.ToString() + " " +
                //    "archiveFileFullPath:" + archiveFileFullPath.ToString()
                //    );
                HSToolImportViewerProgram.ErrorLOG("HSToolImporter.Import", "アーカイブ展開処理で例外発生:" + exp.ToString() + "archiveFileFullPath:" + archiveFileFullPath.ToString());
                return -2;
            }
            return 0;
        }

        # region J# 固有処理
        ///// <summary><para>method outline:</para>
        ///// <para>入力実行</para>
        ///// </summary>
        ///// <example><para>usage:</para>
        ///// <para> int result = Import(archiveFileFullPath) </para>
        ///// </example>
        ///// <param name="archiveFileFullPath">アーカイブファイルパス</param>
        ///// <returns><para>0: 正常終了 -1:ZIP形式変換エラー</para>
        ///// <para>-2:入出力エラー -3:サポート対象外データ</para></returns>
        ///// <exception cref="">無し</exception>
        ///// <remarks><para>remarks:</para>
        ///// <para>無し</para>
        ///// </remarks> 
        //static public int Import(
        //    HySString archiveFileFullPath
        //    )
        //{
        //    try
        //    {
        //        HySExpander zipExpander = new HySDotNetZipExpander(archiveFileFullPath);

        //        // エントリ名取得
        //        List<HySStringRoot> entryList = zipExpander.GetAllEntryName();

        //        // 指定されたアーカイブがサポート対象か判定する
        //        bool result = IsSupportArchive(
        //            archiveFileFullPath,
        //            entryList
        //            );
        //        if (result == false)
        //        {
        //            HySLog.LogOut(
        //                HySLog.ONLINE,
        //                "McLibraryImporter",
        //                "Import",
        //                "archiveFileFullPath:" + archiveFileFullPath.ToString()
        //                );
        //            return (-3);
        //        }
        //        // 展開対象パスを作成
        //        entryList = CreateTargetEntry(entryList);

        //        // 作成したパスを展開対象エントリに指定
        //        zipExpander.AddTargetEntry(entryList);

        //        // ホームディレクトリパス取得
        //        HySString homeDirectory = HySEnvInf.GetHomeDirectory();
        //        zipExpander.Expand(homeDirectory);
        //    }
        //    // Zipファイル形式エラー
        //    catch (java.util.zip.ZipException exp)
        //    {
        //        HySLog.LogOut(
        //            HySLog.ONLINE,
        //            "McLibraryImporter",
        //            "Import",
        //            "アーカイブ展開処理で例外発生:" + exp.ToString() +
        //            "archiveFileFullPath:" + archiveFileFullPath.ToString()
        //            );
        //        return -1;
        //    }
        //    // 入出力エラー
        //    catch (java.io.IOException exp)
        //    {
        //        HySLog.LogOut(
        //            HySLog.ONLINE,
        //            "McLibraryImporter",
        //            "Import",
        //            "アーカイブ展開処理で例外発生:" + exp.ToString() + "" +
        //            "archiveFileFullPath:" + archiveFileFullPath.ToString()
        //            );
        //        return -1;
        //    }
        //    catch (System.IO.FileNotFoundException exp)
        //    {
        //        HySLog.LogOut(HySLog.ONLINE, "McLibraryImporter", "Import",
        //            "アーカイブ展開処理で例外発生:" + exp.ToString() + " " +
        //            "archiveFileFullPath:" + archiveFileFullPath.ToString()
        //            );
        //        return -2;
        //    }
        //    return 0;
        //}
        # endregion

        /// <summary><para>method outline:</para>
        /// <para>エラーメッセージ取得</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> HySString message = GetErrorMessage(errorCode) </para>
        /// </example>
        /// <param name="errorCode">エラーコード</param>
        /// <returns><para>エラーメッセージ</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
//        static public HySString GetErrorMessage(
        public HySString GetErrorMessage(
            int errorCode
            )
        {
            string errorComment = "";
            switch (errorCode)
            {
                case (-1):
                    errorComment = "ファイルにアクセスしようとして異常が発生しました。";
                    break;
                case (-2):
                    errorComment = "ディスク上に存在しないファイルにアクセスしようとして失敗しました。";
                    break;
                case (-3):
                    errorComment = "指定されたアーカイブはサポート対象外のファイルです。";
                    break;
                default:
                    break;
            }
            HySString message = new HySString(errorComment);
            return message;
        }

        /// <summary><para>method outline:</para>
        /// <para>サポートするアーカイブかチェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool result = IsSupportArchive(archiveFileFullPath, entryList) </para>
        /// </example>
        /// <param name="archiveFileFullPath">アーカイブファイルパス</param>
        /// <param name="entryList">エントリ名リスト</param>
        /// <returns><para>true:サポート対象 false:サポート対象外</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>アーカイブのエントリ内に実行形式ファイルが存在する場合はtrueを返却し、
        /// 存在しない場合はfalseを返却する</para>
        /// </remarks>
//        static private bool IsSupportArchive(
        private bool IsSupportArchive(
            HySString archiveFileFullPath,
            List<HySStringRoot> entryList
            )
        {
            bool isSupport = false;
            // エントリ名に実行形式ファイルが存在するか確認する
            for (int i = 0; i < entryList.Count; i++)
            {
                HySString fileName = (HySString)entryList[i];
                if ((fileName.ToString().StartsWith("bin\\")) && (fileName.ToString().EndsWith(".dll")))
                {
                    isSupport = true;
                    break;
                }
            }
            if (isSupport == false)
            {
                //HySLog.LogOut(
                //    HySLog.ONLINE,
                //    "HSToolImporter",
                //    "IsSupportArchive",
                //    "アーカイブに実行形式ファイルが含まれていません。 archiveFileFullPath:" + archiveFileFullPath.ToString()
                //    );
                HSToolImportViewerProgram.ErrorLOG("HSToolImporter.IsSupportArchive", "アーカイブに実行形式ファイルが含まれていません。 archiveFileFullPath:" + archiveFileFullPath.ToString());
                return false;
            }

            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>インストール情報作成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> long lRtc = MakeImportFileInfo(entryList, csEntryDir) </para>
        /// </example>
        /// <param name="entryList">エントリ名リスト</param>
        /// <param name="csEntryDir">エントリディレクトリ名リスト</param>
        /// <returns><para>0:正常　-1:異常(情報書込み)　-2:異常(ファクトリ取得)</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private long MakeImportFileInfo(List<HySStringRoot> entryList, Hashtable csEntryDir)
        {
            long lRtn = -2;
            HySString csDllName = new HySString("");
            HySString csHomeDir = HySEnvInf.GetHomeDirectory();
            HySString csToolName = null;

            for (int i = 0; i < entryList.Count; i++)
            {
                // エントリ名の要素を確認する
                // 展開対象エントリ名ならば展開対象エントリリストに追加する
                HySString entry = (HySString)entryList[i];
                if ((entry.ToString().StartsWith("bin\\")) && (entry.ToString().EndsWith(".dll")))
                {
                    csDllName.SetString(entry);
                    csDllName.Remove(0, 4);
                    if (GetToolName(csDllName, out csToolName) == true)
                    {// ユーザーツール
                        break;
                    }
                }
            }

            if (csDllName.Equal(new HySString("")) != true)
            {// インストール情報ファイル書き込み

                lRtn = WriteImportFileInfo(csDllName, csToolName, m_archiveFileFullPath, entryList, csEntryDir);
            }
            else
            {// DLL無し

                HSToolImportViewerProgram.ErrorLOG("HSToolImporter.MakeImportFileInfo", "Dll名取得失敗");
            }

            return lRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>インストール情報ファイル書き込み</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> long lRtc = WriteImportFileInfo(csDllName, csToolName, csPackageName, entryList) </para>
        /// </example>
        /// <param name="csDllName">DLL名称</param>
        /// <param name="csToolName">ツール名称</param>
        /// <param name="csPackageName">パッケージ名称</param>
        /// <param name="entryList">エントリ名リスト</param>
        /// <param name="csEntryDir">エントリディレクトリ名リスト</param>
        /// <returns><para>0:正常　-1:異常</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private long WriteImportFileInfo(HySString csDllName, HySString csToolName, HySString csPackageName, List<HySStringRoot> entryList, Hashtable csEntryDir)
        {
            long lRtn = 0;

            HySXmlNode csRootNode = null;           // ルートノード
            HySXmlNode csBodyNode = null;           // Bodyノード
            HySXmlNode csChildNode = null;          // 子ノード

            try
            {
                // 名称を編集ワークへ格納
                HySString csName = csDllName.Clone();

                // インストール管理ファイル名作成
                HySString csSaveFile = HySEnvInf.GetHomeDirectory() + "\\SystemData\\AddinTools\\" + csName.Replace(".dll", ".xml");

                HySXmlWriter csXmlFile = new HySXmlWriter(csSaveFile);

                // ルートノード作成
                csRootNode = csXmlFile.CreateRoot(xml_TOOLS);

                // ツールノード作成
                csBodyNode = csXmlFile.CreateElement(xml_TOOL);
                csBodyNode.SetAttribute(xml_DLL, csDllName.ToString());         // DLL名称
                csBodyNode.SetAttribute(xml_NAME, csToolName.ToString());       // ツール名称
                csBodyNode.SetAttribute(xml_PACKAGE, csPackageName.ToString()); // パッケージファイル名（フルパス）

                // インストールされるファイル名を保存
                for (int iLoop = 0; iLoop < entryList.Count; iLoop++)
                {
                    csChildNode = HySXmlNode.CreateElement(xml_FILEPATH, csXmlFile);
                    csChildNode.SetAttribute(xml_NAME, TOOL_KIND_FILE + HySEnvInf.GetHomeDirectory().ToString() + "\\" + entryList[iLoop].ToString());
                    csBodyNode.AppendChild(csChildNode);                     // Bodyノードに追加
                }

                foreach( string csdir in csEntryDir.Keys)
                {
                    csChildNode = HySXmlNode.CreateElement(xml_FILEPATH, csXmlFile);
                    csChildNode.SetAttribute(xml_NAME, TOOL_KIND_DIR + HySEnvInf.GetHomeDirectory().ToString() + "\\" + csdir);
                    csBodyNode.AppendChild(csChildNode);                     // Bodyノードに追加
                }

                csRootNode.AppendChild(csBodyNode);     // ルートノードに追加

                // ファイル保存
                if (csXmlFile.Save() != true)
                {// 異常
                    HSToolImportViewerProgram.ErrorLOG("HSToolImporter.WriteImportFileInfo", "ツールインストール情報保存失敗");
                    lRtn = -1;
                }
            }
            catch
            {// 異常
                HSToolImportViewerProgram.ErrorLOG("HSToolImporter.WriteImportFileInfo", "ツールインストール情報保存失敗");
                lRtn = -1;
            }

            return lRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>ツール名称取得</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = GetToolName(csDllName, csToolName) </para>
        /// </example>
        /// <param name="csDllName">DLL名称</param>
        /// <param name="csToolName">ツール名称</param>
        /// <returns><para>ture:ユーザツール false:ユーザツール以外</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private bool GetToolName(HySString csDllName, out HySString csToolName)
        {
            bool bRtn = false;
            csToolName = csDllName;
            Assembly csAssembly = null; // アセンブリ

            Module csModule = null;     // モジュール
            Type csType = null;         // モジュールタイプ
            String csPackageName;       // パッケージ名称
            String csClassName;         // クラス名称

            HySFactory csFactory = null;       // ファクトリクラス

            try
            {//
                csAssembly = Assembly.LoadFrom(@csDllName.ToString());         // アセンブリ取り込み
                csModule = csAssembly.GetModule(csDllName.ToString());         // モジュール取得
                if (csModule != null)
                {
                    csClassName = "HYSSOP_USRVIEWERJOB_FACTORY_CREATOR_IMPLE";// ←Defineクラスに定義のこと
                    csPackageName = "CommonMP.HYSSOP._SYSTEM_";　　　　　　　 // ←Defineクラスに定義のこと
                    csType = csModule.GetType(csPackageName + "." + csClassName);// モジュールタイプ取得
                    if (csType != null)
                    {   // 該当クラス有無
                        CommonMP.HYSSOP._SYSTEM_.HYSSOP_USRVIEWERJOB_FACTORY_CREATOR csFctCreator = null;
                        try
                        {
                            // ファクトリクリエータクラス生成
                            csFctCreator = (CommonMP.HYSSOP._SYSTEM_.HYSSOP_USRVIEWERJOB_FACTORY_CREATOR)Activator.CreateInstance(csType);
                            // 此処でエラーを発生するとExceptionを発生して終了する
                            // 従って、エラー発生時にTry：Catchが必要
                        }
                        catch
                        {
                            HSToolImportViewerProgram.ErrorLOG("HSToolImporter.GetToolName", "ファクトリクリエータインスタンス生成異常");
                        }
                        if (csFctCreator != null)
                        {
                            bRtn = true;

                            csFactory = csFctCreator.CreateFactory();
                            if (csFactory != null)
                            {
                                HySUserToolInfoData csUserToolInfoData = ((HySDotNetAddInBaseJobFactory)csFactory).CreateToolInf();

                                if (csUserToolInfoData != null)
                                {// ツール情報取得成功
                                    csToolName = csUserToolInfoData.GetToolName();
                                    csUserToolInfoData = null;
                                }
                                else
                                {// 異常
                                    HSToolImportViewerProgram.ErrorLOG("HSToolImporter.GetToolName", "ツール情報取得失敗");
                                }

                            }
                            else
                            {// 異常
                                HSToolImportViewerProgram.ErrorLOG("HSToolImporter.GetToolName", "ファクトリクラス生成異常");
                            }
                            csFctCreator = null;
                        }
                    }

                    csModule = null;    
                }

            }
            catch
            {// 異常
//                HySLog.LogOut(HySLog.ONLINE, "HySLauncherViewerJob::GetUserToolInfo", "Assembly.LoadFrom Fail");
                HSToolImportViewerProgram.ErrorLOG("HSToolImporter.GetToolName", "アセンブリ情報取得失敗");
                return bRtn;
            }

            return bRtn;
        }


        /// <summary><para>method outline:</para>
        /// <para>展開対象エントリ追加</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> List entryList = CreateTarget(entryList, csZipData, csEntryDir) </para>
        /// </example>
        /// <param name="entryList">エントリ名リスト</param>
        /// <param name="csZipData">圧縮ファイル情報</param>
        /// <param name="csEntryDir">エントリディレクトリ名リスト</param>
        /// <returns><para>展開対象エントリ名リスト</para></returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public List<HySStringRoot> CreateTarget(List<HySStringRoot> entryList, ref HySExpander csZipData, ref Hashtable csEntryDir)
        {
            List<HySStringRoot> targetEntryList = new List<HySStringRoot>();


            for (int i = 0; i < entryList.Count; i++)
            {
                // エントリ名の要素を確認する
                // 展開対象エントリ名ならば展開対象エントリリストに追加する
                HySString entry = (HySString)entryList[i];
                bool binResult = entry.ToString().StartsWith("bin\\");
                bool toolIconResult = entry.ToString().StartsWith("ToolIcon\\");
                bool toolManualResult = entry.ToString().StartsWith("ToolManual\\");
                bool toolProjectResult = entry.ToString().StartsWith("VsToolProject\\");

                if (binResult == true ||
                    toolIconResult == true ||
                    toolManualResult == true
                    )
                {
                    targetEntryList.Add(entry);
                    csZipData.AddTargetEntry(entry);
                }
                else if(toolProjectResult)
                {
                    int iCase = entry.IndexOf("\\");
                    if (iCase > 1)
                    {
                        HySString csPathStr = new HySString();
                        entry.Substring(iCase + 1, ref csPathStr);
                        HySString csNewEntry = new HySString("..\\Source\\HYSSOP\\AddInSysTools\\") + csPathStr;

                        // プロジェクト格納位置に変更
                        csZipData.ChangeFileName(entry, csNewEntry);
                        // 展開リストに追加
                        csZipData.AddTargetEntry(csNewEntry);

                        iCase = csPathStr.IndexOf("\\");
                        if (iCase > 1)
                        {
                            string csDirName = "..\\Source\\HYSSOP\\AddInSysTools\\" + csPathStr.ToString().Substring(0, iCase);
                            if (csEntryDir.Contains(csDirName) == false)
                            {// ディレクトリを追加
                                csEntryDir.Add(csDirName, new HySString(csDirName));
                            }
                        }
                    }
                }
            }

            return targetEntryList;
        }
    }
}
