using System;
using System.IO;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using System.Media;

namespace Mix.Tool.ArchiveEditor
{
    public partial class ExportForm : Form
    {
        const uint SC_CLOSE = 0xF060;
        const uint MF_ENABLED = 0x00000000;
        const uint MF_GRAYED = 0x00000001;

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern bool EnableMenuItem(IntPtr hMenu, uint enableItemID, uint enable);

        private delegate void Delegate_Logger_Clear();
        private delegate void Delegate_Logger_Print(Logger.Type type, string str);
        private delegate void Delegate_ArchiveFile_ProcessFile(string fileName, uint size);
        private delegate void Delegate_ArchiveFile_UpdateFileProgress(int progress);
        private delegate void Delegate_ArchiveFile_UpdateTotalProgress(int progress);
        private delegate void Delegate_ArchiveFile_End();

        private Project project = null;
        private bool outputing = false;

        public ExportForm(Project _project)
        {
            project = _project;

            InitializeComponent();
        }

        private void ExportForm_Load(object sender, EventArgs e)
        {
            Logger.ProcClear = new Logger.DelegateProcClear(Logger_Clear);
            Logger.ProcPrint = new Logger.DelegateProcPrint(Logger_Print);
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            Thread mainThread = new Thread(new ParameterizedThreadStart(ExportForm.ThreadMain));
            Mix.Tool.Archiver archiver = new Mix.Tool.Archiver();

            SetOutputing(true);

            archiver.RootDirectoryName = project.RootDirectoryName;
            archiver.InputDirectoryName = project.InputDirectoryName;
            archiver.OutputFileName = project.OutputFileName;
            archiver.Alignment = (uint)project.Alignment;
            archiver.PreCreate = new Mix.Tool.Archiver.DelegatePreCreate(ArchiveFile_PreCreate);
            archiver.ProcessFile = new Mix.Tool.Archiver.DelegateProcessFile(ArchiveFile_ProcessFile);
            archiver.UpdateFileProgress = new Mix.Tool.Archiver.DelegateUpdateFileProgress(ArchiveFile_UpdateFileProgress);
            archiver.UpdateTotalProgress = new Mix.Tool.Archiver.DelegateUpdateTotalProgress(ArchiveFile_UpdateTotalProgress);
            archiver.End = new Mix.Tool.Archiver.DelegateEnd(ArchiveFile_End);

            mainThread.Start(archiver);
        }

        private void Logger_Clear()
        {
            if (textBoxLog.InvokeRequired == true)
            {
                this.Invoke(new Delegate_Logger_Clear(Logger_Clear));
            }
            else
            {
                textBoxLog.Clear();
            }
        }

        private void Logger_Print(Logger.Type type, string str)
        {
            if (textBoxLog.InvokeRequired == true)
            {
                this.Invoke(new Delegate_Logger_Print(Logger_Print), new object[] { type, str });
            }
            else
            {
                textBoxLog.Text += (str + Environment.NewLine);
                textBoxLog.Select(textBoxLog.Text.Length, 0);
                textBoxLog.ScrollToCaret();

                switch (type)
                {
                    case Logger.Type.Warning:
                        SystemSounds.Beep.Play();
                        break;
                    case Logger.Type.Error:
                        SystemSounds.Hand.Play();
                        break;
                }
            }
        }

        private void ArchiveFile_PreCreate(uint fileCount, UInt64 totalFileSize, UInt64 totalSize)
        {
            Logger.Print(Logger.Type.Info, "");
            Logger.Print(Logger.Type.Info, String.Format("    ファイル数 : {0}", fileCount));
            Logger.Print(Logger.Type.Info, String.Format("    全てのファイルの合計サイズ : {0}", Utility.FileSizeToString64((Int64)totalFileSize)));
            Logger.Print(Logger.Type.Info, String.Format("    出力ファイルのサイズ : {0}", Utility.FileSizeToString64((Int64)totalSize)));
            Logger.Print(Logger.Type.Info, "");
        }

        private void ArchiveFile_ProcessFile(string fileName, uint size)
        {
            if (textBoxFile.InvokeRequired == true)
            {
                this.Invoke(new Delegate_ArchiveFile_ProcessFile(ArchiveFile_ProcessFile), new object[] { fileName, size });
            }
            else
            {
                textBoxFile.Text = String.Format("\'{0}\' {1}", fileName, Utility.FileSizeToString(size));
            }
        }

        private void ArchiveFile_UpdateFileProgress(int progress)
        {
            if (progressBarFile.InvokeRequired == true)
            {
                this.Invoke(new Delegate_ArchiveFile_UpdateFileProgress(ArchiveFile_UpdateFileProgress), new object[] { progress });
            }
            else
            {
                progressBarFile.Value = progress;
            }
        }

        private void ArchiveFile_UpdateTotalProgress(int progress)
        {
            if (progressBarTotal.InvokeRequired == true)
            {
                this.Invoke(new Delegate_ArchiveFile_UpdateTotalProgress(ArchiveFile_UpdateTotalProgress), new object[] { progress });
            }
            else
            {
                progressBarTotal.Value = progress;
            }
        }

        private void ArchiveFile_End()
        {
            if (buttonStart.InvokeRequired == true)
            {
                this.Invoke(new Delegate_ArchiveFile_End(ArchiveFile_End));
            }
            else
            {
                SetOutputing(false);
            }
        }

        private void SetOutputing(bool enable)
        {
            IntPtr hMenu = GetSystemMenu(Handle, false);
            if (hMenu != null)
            {
                EnableMenuItem(hMenu, SC_CLOSE, (enable == false) ? MF_ENABLED : MF_GRAYED);
            }

            buttonStart.Enabled = (enable == false);

            outputing = enable;
        }

        [System.Security.Permissions.SecurityPermission(
            System.Security.Permissions.SecurityAction.LinkDemand,
            Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            const int WM_SYSCOMMAND = 0x112;
            const int SC_CLOSE = 0xF060;

            if ((outputing == true ) &&
                (m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE))
            {
                return;
            }

            base.WndProc(ref m);
        }

        private static void ThreadMain(object obj)
        {
            Mix.Tool.Archiver archiver = obj as Mix.Tool.Archiver;
            archiver.Run();
        }
    }
}
