using System;
using System.Windows.Forms;

namespace Mix.Tool
{
    public class FileDirector
    {
        #region Public Delegate

        public delegate bool DelegateNew();
        public delegate bool DelegateOpen(string fileName);
        public delegate bool DelegateSave(string fileName);

        #endregion

        #region Private Value

        private FileDirector.DelegateNew delegNew;
        private FileDirector.DelegateOpen delegOpen;
        private FileDirector.DelegateSave delegSave;

        private Form form = null;
        private bool newFile = true;
        private bool updateFile = false;
        private string title = "";
        private string newFileName = "新規ファイル.txt";
        private string fileName = "新規ファイル.txt";
        private string fileFilter = "テキストファイル|*.txt";

        #endregion

        #region Public Property

        public FileDirector.DelegateNew New
        {
            set { delegNew = value; }
        }

        public FileDirector.DelegateOpen Open
        {
            set { delegOpen = value; }
        }

        public FileDirector.DelegateSave Save
        {
            set { delegSave = value; }
        }

        public string NewName
        {
            get { return newFileName; }
            set { newFileName = value; }
        }

        public string Filter
        {
            get { return fileFilter; }
            set { fileFilter = value; }
        }

        public bool Update
        {
            get { return updateFile; }
            set
            {
                updateFile = value;
                ProcUpdateStatus();
            }
        }

        #endregion

        #region Private Method

        /// <summary>
        /// エラーが発生した際に呼び出します
        /// </summary>
        /// <param name="text">エラーテキスト</param>
        private void ErrorBox(string text)
        {
            MessageBox.Show(text, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// プロセス : 新規作成
        /// </summary>
        private void ProcNew()
        {
            if (delegNew() == true)
            {
                newFile = true;
                updateFile = false;
                fileName = newFileName;

                ProcUpdateStatus();
            }
            else
            {
                ErrorBox("新規作成に失敗しました");
            }
        }

        /// <summary>
        /// プロセス : 開く
        /// </summary>
        private void ProcOpen()
        {
            OpenFileDialog dlg = new OpenFileDialog();

            dlg.Title = "ファイルを開く";
            dlg.Filter = fileFilter;
            dlg.FilterIndex = 1;
            dlg.RestoreDirectory = true;

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                if (delegOpen(dlg.FileName) == true)
                {
                    newFile = false;
                    updateFile = false;
                    fileName = dlg.FileName;

                    ProcUpdateStatus();
                }
                else
                {
                    ErrorBox("ファイル" + " \"" + dlg.FileName + "\" " + "を開くことができませんでした");
                }
            }
        }

        /// <summary>
        /// プロセス : 上書き保存
        /// </summary>
        /// <returns>成功した場合は true を返します</returns>
        private bool ProcSave()
        {
            bool result = false;

            if (delegSave(fileName) == true)
            {
                newFile = false;
                updateFile = false;

                ProcUpdateStatus();

                result = true;
            }
            else
            {
                ErrorBox("ファイル" + " \"" + fileName + "\" " + "の保存に失敗しました");
            }

            return result;
        }

        /// <summary>
        /// プロセス : 名前を付けて保存
        /// </summary>
        /// <returns>成功した場合は true を返します</returns>
        private bool ProcSaveAs()
        {
            bool result = false;

            SaveFileDialog dlg = new SaveFileDialog();

            dlg.Title = "名前を付けて保存";
            dlg.Filter = fileFilter;
            dlg.FilterIndex = 1;
            dlg.FileName = fileName;
            dlg.RestoreDirectory = true;

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                if (delegSave(dlg.FileName) == true)
                {
                    newFile = false;
                    updateFile = false;
                    fileName = dlg.FileName;

                    ProcUpdateStatus();

                    result = true;
                }
                else
                {
                    ErrorBox("ファイル" + " \"" + dlg.FileName + "\" " + "の保存に失敗しました");
                }
            }

            return result;
        }

        /// <summary>
        /// プリプロセス : 「新規作成」「開く」「上書き保存」「名前を付けて保存」の処理の前に呼び出します
        /// </summary>
        /// <returns>成功した場合は true を返します</returns>
        private bool PreProcSave()
        {
            bool result;

            if (updateFile == true)
            {
                DialogResult dlgRet = MessageBox.Show("ファイル" + " \"" + fileName + "\" " + "の内容は変更されています。\n変更を保存しますか？", title, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning);
                switch (dlgRet)
                {
                    case DialogResult.Yes:
                        //はい(変更を保存する)
                        if (newFile == true)
                        {
                            //名前を付けて保存
                            result = ProcSaveAs();
                        }
                        else
                        {
                            //上書き保存
                            result = ProcSave();
                        }
                        break;
                    case DialogResult.No:
                        //いいえ(変更を保存しない)
                        result = true;
                        break;
                    default:
                        //キャンセル
                        result = false;
                        break;
                }
            }
            else
            {
                //保存する必要は無い
                result = true;
            }

            return result;
        }

        /// <summary>
        /// プロセス : ステータスが更新された
        /// </summary>
        private void ProcUpdateStatus()
        {
            form.Text = (updateFile == true) ? "*" : "";
            form.Text += fileName + " - " + title;
        }
        
        #endregion

        #region Public Method

        public FileDirector(Form _form)
        {
            if (_form == null)
            {
                throw new ArgumentNullException("_form");
            }

            form = _form;
            newFile = true;
            updateFile = false;
            title = form.Text;
        }

        public void DoNew()
        {
            if (PreProcSave() == true)
            {
                ProcNew();
            }
        }

        public void DoOpen()
        {
            if (PreProcSave() == true)
            {
                ProcOpen();
            }
        }

        public void DoSave()
        {
            if (newFile == true)
            {
                ProcSaveAs();
            }
            else
            {
                ProcSave();
            }
        }

        public void DoSaveAs()
        {
            ProcSaveAs();
        }

        public bool DoClose()
        {
            return PreProcSave();
        }

        #endregion
    }
}
