// <summary>ソースコード：エクスパンダークラス</summary>
// <author>CommonMP</author>

using System;
using System.Collections.Generic;
using System.Text;
using Ionic.Zip;

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

namespace CommonMP.HYSSOP.CoreImpl.HSTools
{
    /// <summary><para>class outline:</para>
    /// <para>エクスパンダークラス</para>
    /// </summary>
    /// <remarks><para>remarks:</para>
    /// <para>無し</para>
    /// </remarks>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2009/12/24][新規作成]</para>
    /// </remarks>
    public class HySDotNetZipExpander : HySExpander
    {
        /// <summary>クラス名文字列</summary>
        static private readonly string CLASS_NAME = "HySDotNetZipExpander";

        /// <summary> 展開対象エントリリスト </summary>
        private List<HySStringRoot> m_targetEntryList = new List<HySStringRoot>();

        /// <summary> アーカイブファイルパス </summary>
        private HySString m_archiveFileFullPath = null;

        /// <summary> アーカイブファイル情報 </summary>
        ZipFile m_csZip = null;

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>HySDotNetZipExpander zipExpander = new HySDotNetZipExpander(archiveFileFullPath)</para>
        /// </example>
        /// <param name="archiveFileFullPath">アーカイブファイルパス</param>
        /// <returns>生成されたインスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public HySDotNetZipExpander(
            HySString archiveFileFullPath
            )
        {
            m_archiveFileFullPath = archiveFileFullPath;
        }

        /// <summary><para>method outline:</para>
        /// <para>展開対象エントリ追加</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> AddTargetEntry(targetEntry) </para>
        /// </example>
        /// <param name="targetEntry">展開対象エントリ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void AddTargetEntry(
            HySStringRoot targetEntry
            )
        {
            m_targetEntryList.Add(targetEntry);
        }

        /// <summary><para>method outline:</para>
        /// <para>展開対象エントリ追加</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> AddTargetEntry(targetEntryList);</para>
        /// </example>
        /// <param name="targetEntryList">展開対象エントリリスト</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void AddTargetEntry(
            List<HySStringRoot> targetEntryList
            )
        {
            foreach (HySStringRoot targetEntry in targetEntryList)
            {
                AddTargetEntry(targetEntry);
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>展開対象エントリ取得</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>List targetEntryList = GetTargetEntry(); </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>展開対象エントリリスト</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public List<HySStringRoot> GetTargetEntry()
        {
            return m_targetEntryList;
        }

        /// <summary><para>method outline:</para>
        /// <para>展開実行</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Expand( outFolderFullPath ); </para>
        /// </example>
        /// <param name="outFolderFullPath">出力先フォルダフルパス</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void Expand(
            HySStringRoot outFolderFullPath
            )
        {
            const string methodName = "Expand";

            ZipFile csZip = ZipFile.Read(m_archiveFileFullPath.ToString(), System.Text.Encoding.GetEncoding("shift_jis"));

            // ZipFileクラスのExtractAll()利用時の上書き設定例
            //csZip.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently;

            try
            {   
                // 展開処理実行
                ExpandSub(outFolderFullPath, ref csZip);
            }
            catch (Ionic.Zip.ZipException Exp)
            {
                HySLog.LogOut(HySLog.ONLINE, CLASS_NAME, methodName, Exp.ToString());
                throw Exp;
            }
            finally
            {

            }

            if (csZip != null)
            {// 解放
                csZip.Dispose();
            }
        }

        # region J# 固有処理
        ///// <summary><para>method outline:</para>
        ///// <para>展開実行</para>
        ///// </summary>
        ///// <example><para>usage:</para>
        ///// <para> Expand( outFolderFullPath ); </para>
        ///// </example>
        ///// <param name="outFolderFullPath">出力先フォルダフルパス</param>
        ///// <returns>無し</returns>
        ///// <exception cref="">無し</exception>
        ///// <remarks><para>remarks:</para>
        ///// <para>無し</para>
        ///// </remarks>
        //public void Expand(
        //    HySStringRoot outFolderFullPath
        //    )
        //{
        //    const string methodName = "Expand";

        //    java.io.FileInputStream fileInputStream = new java.io.FileInputStream(
        //        m_archiveFileFullPath.ToString()
        //        );
        //    java.util.zip.ZipInputStream zipInputStream = new java.util.zip.ZipInputStream(
        //        fileInputStream
        //        );

        //    try
        //    {
        //        // 展開処理実行
        //        ExpandSub(outFolderFullPath, ref fileInputStream, ref zipInputStream);
        //    }
        //    catch (java.util.zip.ZipException Exp)
        //    {
        //        HySLog.LogOut(HySLog.ONLINE, CLASS_NAME, methodName, Exp.ToString());
        //        throw Exp;
        //    }
        //    catch (java.io.IOException Exp)
        //    {
        //        HySLog.LogOut(HySLog.ONLINE, CLASS_NAME, methodName, Exp.ToString());
        //        throw Exp;
        //    }
        //    finally
        //    {
        //        // ストリームを閉じる
        //        if ((object)zipInputStream != null)
        //        {
        //            zipInputStream.close();
        //        }
        //        if ((object)fileInputStream != null)
        //        {
        //            fileInputStream.close();
        //        }
        //    }
        //}
        # endregion

        /// <summary><para>method outline:</para>
        /// <para>全エントリ取得</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>GetAllEntryName(); </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>エントリ名リスト</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public List<HySStringRoot> GetAllEntryName()
        {
            const string methodName = "GetAllEntryName";
            List<HySStringRoot> entryNameList = new List<HySStringRoot>();

            // 展開するZIPファイルの読み込み
            ZipFile csZip = ZipFile.Read(m_archiveFileFullPath.ToString(), System.Text.Encoding.GetEncoding("shift_jis"));

            try
            {
                // ZIP内のファイル情報を取得する
                foreach (ZipEntry csZipEntry in csZip)
                {
                    HySString entryName = new HySString(csZipEntry.FileName);
                    // 体裁を整える。文字列内の"/"を置換
                    entryName = FormatEntry(entryName);
                    entryNameList.Add(entryName);
                }
            }
            catch (Ionic.Zip.ZipException Exp)
            {
                HySLog.LogOut(HySLog.ONLINE, CLASS_NAME, methodName, Exp.ToString());
                throw Exp;
            }
            finally
            {

            }

            if (csZip != null)
            {// 解放
                csZip.Dispose();
            }

            return entryNameList;
        }

        # region J# 固有処理
        ///// <summary><para>method outline:</para>
        ///// <para>全エントリ取得</para>
        ///// </summary>
        ///// <example><para>usage:</para>
        ///// <para>GetAllEntryName(); </para>
        ///// </example>
        ///// <param name="">無し</param>
        ///// <returns>エントリ名リスト</returns>
        ///// <exception cref="">無し</exception>
        ///// <remarks><para>remarks:</para>
        ///// <para>無し</para>
        ///// </remarks>
        //public List<HySStringRoot> GetAllEntryName()
        //{
        //    const string methodName = "GetAllEntryName";
        //    List<HySStringRoot> entryNameList = new List<HySStringRoot>();

        //    // 展開するZIPファイルの読み込み
        //    java.io.FileInputStream fileInputStream = new java.io.FileInputStream(m_archiveFileFullPath.ToString());
        //    java.util.zip.ZipInputStream zipInputStream = new java.util.zip.ZipInputStream(fileInputStream);

        //    try
        //    {
        //        // ZIP内のファイル情報を取得して体裁を整える
        //        java.util.zip.ZipEntry zipEntry;
        //        while ((zipEntry = zipInputStream.getNextEntry()) != null)
        //        {
        //            HySString entryName = new HySString(zipEntry.getName());
        //            entryName = FormatEntry(entryName);
        //            entryNameList.Add(entryName);
        //        }
        //    }
        //    catch (java.util.zip.ZipException Exp)
        //    {
        //        HySLog.LogOut(HySLog.ONLINE, CLASS_NAME, methodName, Exp.ToString());
        //        throw Exp;
        //    }
        //    catch (java.io.IOException Exp)
        //    {
        //        HySLog.LogOut(HySLog.ONLINE, CLASS_NAME, methodName, Exp.ToString());
        //        throw Exp;
        //    }
        //    finally
        //    {
        //        // ストリームを閉じる
        //        if ((object)zipInputStream != null)
        //        {
        //            zipInputStream.close();
        //        }
        //        if ((object)fileInputStream != null)
        //        {
        //            fileInputStream.close();
        //        }
        //    }
        //    return entryNameList;
        //}
        # endregion

        /// <summary><para>method outline:</para>
        /// <para>エントリ名体裁整理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>FormatEntry(entryName); </para>
        /// </example>
        /// <param name="entryName">エントリ名</param>
        /// <returns>エントリ名</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private HySString FormatEntry(
            HySString entryName
            )
        {
            entryName = entryName.Replace("/", "\\");

            return entryName;
        }

        /// <summary><para>method outline:</para>
        /// <para>対象エントリであるかのチェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>IsTargetEntry(entryName); </para>
        /// </example>
        /// <param name="entryName">エントリ名</param>
        /// <returns>true:対象エントリ false:対象外エントリ</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private bool IsTargetEntry(
            HySString entryName
            )
        {
            // エントリ名の体裁を整える
            HySString isEntryName = FormatEntry(entryName);
            bool result = false;

            // エントリ名が展開対象に含まれるかチェックする
            foreach (HySString targetEntry in m_targetEntryList)
            {
                if (isEntryName == FormatEntry(targetEntry))
                {
                    result = true;
                    break;
                }
            }
            return result;
        }

        /// <summary><para>method outline:</para>
        /// <para>展開実行サブメソッド</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>ExpandSub(outFolderFullPath,csZip)</para>
        /// </example>
        /// <param name="outFolderFullPath">出力先フォルダフルパス</param>
        /// <param name="csZip">Zip入出力クラス</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void ExpandSub(HySStringRoot outFolderFullPath, ref ZipFile csZip)
        {
            foreach (ZipEntry csZipEntry in csZip)
            {
                HySString entryName = new HySString(csZipEntry.FileName);
                // 体裁を整える。文字列内の"/"を置換
                //if (entryName.ToString().EndsWith("/") == true)
                //{
                    entryName = FormatEntry(entryName);
                //}
                // 展開対象のエントリの場合展開処理を実行
                if (IsTargetEntry(entryName) == true)
                {
                    // 展開処理実行
                    try
                    {
                        // 解凍時、既にファイルがある場合は上書き(更新処理用)
                        csZipEntry.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently;
                        csZipEntry.Extract(outFolderFullPath.ToString());
                    }
                    catch (Ionic.Zip.ZipException Exp)
                    {
                        throw Exp;
                    }
                    finally
                    {

                    }
                }
            }
        }

        # region J# 固有処理
        ///// <summary><para>method outline:</para>
        ///// <para>展開実行サブメソッド</para>
        ///// </summary>
        ///// <example><para>usage:</para>
        ///// <para>ExpandSub(outFolderFullPath,fileInputStream,zipInputStream)</para>
        ///// </example>
        ///// <param name="outFolderFullPath">出力先フォルダフルパス</param>
        ///// <param name="fileInputStream">ファイル入力ストリーム</param>
        ///// <param name="zipInputStream">zip入力ストリーム</param>
        ///// <returns>無し</returns>
        ///// <exception cref="">無し</exception>
        ///// <remarks><para>remarks:</para>
        ///// <para>無し</para>
        ///// </remarks>
        //private void ExpandSub(HySStringRoot outFolderFullPath,
        //    ref java.io.FileInputStream fileInputStream,
        //    ref java.util.zip.ZipInputStream zipInputStream
        //    )
        //{
        //    java.util.zip.ZipEntry zipEntry;
        //    while ((zipEntry = zipInputStream.getNextEntry()) != null)
        //    {
        //        // 展開対象のエントリの場合展開処理を実行
        //        HySString entryName = new HySString(zipEntry.getName());
        //        if (IsTargetEntry(entryName) == true)
        //        {
        //            // 出力先パス設定
        //            string outFullPath = System.IO.Path.Combine(
        //                outFolderFullPath.ToString(),
        //                entryName.ToString()
        //            );

        //            // エントリが非ディレクトリ時の処理
        //            if (!zipEntry.isDirectory())
        //            {

        //                // 出力先ディレクトリ作成
        //                System.IO.DirectoryInfo dirInfo = System.IO.Directory.GetParent(outFullPath);
        //                if (System.IO.Directory.Exists(dirInfo.ToString()) == false)
        //                {
        //                    System.IO.Directory.CreateDirectory(dirInfo.ToString());
        //                }

        //                // 展開処理実行
        //                java.io.FileOutputStream fileOutputStream = new java.io.FileOutputStream(
        //                    outFullPath
        //                    );
        //                try
        //                {
        //                    int len;
        //                    sbyte[] buffer = new sbyte[8192];

        //                    while ((len = zipInputStream.read(buffer, 0, buffer.Length)) > 0)
        //                    {
        //                        fileOutputStream.write(buffer, 0, len);
        //                    }
        //                }
        //                catch (java.util.zip.ZipException Exp)
        //                {
        //                    throw Exp;
        //                }
        //                catch (java.io.IOException Exp)
        //                {
        //                    throw Exp;
        //                }
        //                finally
        //                {
        //                    fileOutputStream.close();
        //                }
        //            }
        //            // エントリがディレクトリ時の処理
        //            else
        //            {
        //                // ディレクトリ作成
        //                if (System.IO.Directory.Exists(outFullPath) == false)
        //                {
        //                    System.IO.Directory.CreateDirectory(outFullPath);
        //                }
        //            }
        //        }
        //    }
        //}
        # endregion

        /// <summary><para>method outline:</para>
        /// <para>Zipファイル読込み</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRnt = Read()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>0:正常　-1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public long Read()
        {
            long lRtn = -1;     // リターン値

            m_csZip = ZipFile.Read(m_archiveFileFullPath.ToString(), System.Text.Encoding.GetEncoding("shift_jis"));
            if (m_csZip != null)
            {//読込み成功
                lRtn = 0;
            }

            return lRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>展開実行</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> EditExpand( outFolderFullPath ); </para>
        /// </example>
        /// <param name="outFolderFullPath">出力先フォルダフルパス</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void EditExpand(
            HySStringRoot outFolderFullPath
            )
        {
            const string methodName = "EditExpand";

            try
            {
                if (m_csZip != null)
                {
                    // 展開処理実行
                    ExpandSub(outFolderFullPath, ref m_csZip);
                }
            }
            catch (Ionic.Zip.ZipException Exp)
            {
                HySLog.LogOut(HySLog.ONLINE, CLASS_NAME, methodName, Exp.ToString());
                throw Exp;
            }
            finally
            {

            }
        }

        /// <summary><para>method outline:</para>
        /// <para>エントリーファイル名変更</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> long lRtn = ChangeFileName( csOrgFileName, csNewFileName ); </para>
        /// </example>
        /// <param name="csOrgFileName">オリジナルファイルパス</param>
        /// <param name="csNewFileName">変更ファイルパス</param>
        /// <returns>0:変更成功 -1:変更失敗</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public long ChangeFileName(HySStringRoot csOrgFileName, HySStringRoot csNewFileName)
        {
            long lRtn = -1;

            if (m_csZip != null)
            {// 読込み済み
                ZipEntry entry = m_csZip[csOrgFileName.ToString()];
                if (entry != null)
                {
                    entry.ProvisionalAlternateEncoding = Encoding.GetEncoding("shift_jis");
                    entry.FileName = csNewFileName.ToString();
                    lRtn = 0;
                }
            }

            return lRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>ファイル破棄処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Dispose(); </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void Dispose()
        {
            if (m_csZip != null)
            {// 解放
                m_csZip.Dispose();
                m_csZip = null;
            }
        }

    }
}
