using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyScreenCap.Ctrl {
    /// <summary>
    /// オーナーウィンドウの真中に表示される MessageBox
    /// </summary>
    public class CustomMsgBox {

        /// <summary>
        /// 親ウィンドウ
        /// </summary>
        private Form ownerWindow = null;

        /// <summary>
        /// フックハンドル
        /// </summary>
        private IntPtr hHook = IntPtr.Zero;

        /// <summary>
        /// メッセージボックスを表示する
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="messageBoxText"></param>
        /// <param name="caption"></param>
        /// <param name="button"></param>
        /// <param name="icon"></param>
        /// <returns></returns>
        public static DialogResult Show(
            Form owner,
            string messageBoxText,
            string caption,
            MessageBoxButtons button,
            MessageBoxIcon icon) {

            if (owner.WindowState == FormWindowState.Minimized) {
                return MessageBox.Show(owner, messageBoxText, caption, button, icon);
            } else {
                CustomMsgBox mbox = new CustomMsgBox(owner);
                return mbox.Show(messageBoxText, caption, button, icon);
            }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="window">Owner Window</param>
        private CustomMsgBox(Form window) {
            ownerWindow = window;
        }

        /// <summary>
        /// メッセージボックスを表示する
        /// </summary>
        /// <param name="messageBoxText"></param>
        /// <param name="caption"></param>
        /// <param name="button"></param>
        /// <param name="icon"></param>
        /// <returns></returns>
        private DialogResult Show(
            string messageBoxText,
            string caption,
            MessageBoxButtons button,
            MessageBoxIcon icon) {
            // フックを設定する。
            IntPtr hInstance = WinAPI.GetWindowLong(ownerWindow.Handle, WinAPI.GWL_HINSTANCE);
            IntPtr threadId = WinAPI.GetCurrentThreadId();
            hHook = WinAPI.SetWindowsHookEx(WinAPI.WH_CBT, new WinAPI.HOOKPROC(HookProc), hInstance, threadId);

            return MessageBox.Show(ownerWindow, messageBoxText, caption, button, icon);
        }

        /// <summary>
        /// フックプロシージャ
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam) {

            if (nCode == WinAPI.HCBT_ACTIVATE) {
                WinAPI.RECT rcForm = new WinAPI.RECT(0, 0, 0, 0);
                WinAPI.RECT rcMsgBox = new WinAPI.RECT(0, 0, 0, 0);

                WinAPI.GetWindowRect(ownerWindow.Handle, out rcForm);
                WinAPI.GetWindowRect(wParam, out rcMsgBox);

                // センター位置を計算する。
                int x = (rcForm.Left + (rcForm.Right - rcForm.Left) / 2) - ((rcMsgBox.Right - rcMsgBox.Left) / 2);
                int y = (rcForm.Top + (rcForm.Bottom - rcForm.Top) / 2) - ((rcMsgBox.Bottom - rcMsgBox.Top) / 2);

                WinAPI.SetWindowPos(wParam, 0, x, y, 0, 0, WinAPI.SWP_NOSIZE | WinAPI.SWP_NOZORDER | WinAPI.SWP_NOACTIVATE);

                IntPtr result = WinAPI.CallNextHookEx(hHook, nCode, wParam, lParam);

                // フックを解除する。
                WinAPI.UnhookWindowsHookEx(hHook);
                hHook = IntPtr.Zero;

                return result;

            } else {
                return WinAPI.CallNextHookEx(hHook, nCode, wParam, lParam);
            }
        }
    }
}
