using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MyScreenCap.Ctrl {
    /// <summary>
    /// HotKeyの登録/解除
    /// </summary>
    public partial class HotKeyRegister : UserControl {

        [DllImport("user32.dll")]
        extern static int RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

        [DllImport("user32.dll")]
        extern static int UnregisterHotKey(IntPtr hWnd, int id);

        private const int MOD_ALT = 0x0001;
        private const int MOD_CONTROL = 0x0002;
        private const int MOD_SHIFT = 0x0004;
        private const int WM_HOTKEY = 0x0312;

        private const int HOTKEY_ID = 0x0001;

        private IntPtr hHand;

        [DefaultValue(false)]
        public bool ModCtrl {
            get {
                return this.checkCtrl.Checked;
            }
            set {
                this.checkCtrl.Checked = value;
                SetText();
            }
        }

        [DefaultValue(false)]
        public bool ModAlt {
            get {
                return this.checkAlt.Checked;
            }
            set {
                this.checkAlt.Checked = value;
                SetText();
            }
        }

        [DefaultValue(false)]
        public bool ModShift {
            get {
                return this.checkShift.Checked;
            }
            set {
                this.checkShift.Checked = value;
                SetText();
            }
        }

        public enum HotKeys {
            F1 = Keys.F1,
            F2 = Keys.F2,
            F3 = Keys.F3,
            F4 = Keys.F4,
            F5 = Keys.F5,
            F6 = Keys.F6,
            F7 = Keys.F7,
            F8 = Keys.F8,
            F9 = Keys.F9,
            F10 = Keys.F10,
            F11 = Keys.F11,
            F12 = Keys.F12,
        }

        public HotKeys HotKey {
            get {
                return (HotKeys)int.Parse(this.cmbKey.SelectedValue.ToString());
            }
            set {
                if (Enum.IsDefined(typeof(HotKeys), value)) {
                    this.cmbKey.SelectedValue = (int)value;
                    SetText();
                }
            }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public HotKeyRegister() {
            InitializeComponent();
            SetMode(false);
            SetCmdKey();
            SetText();
            this.OnResize(null);
        }

        /// <summary>
        /// btnEdit Click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnEdit_Click(object sender, EventArgs e) {
            Unregister();
            SetMode(true);
        }

        /// <summary>
        /// btnOk Click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOk_Click(object sender, EventArgs e) {
            if (Register()) {
                SetText();
                SetMode(false);
            }
        }

        /// <summary>
        /// コントロールの表示制御
        /// </summary>
        /// <param name="enable"></param>
        private void SetMode(bool enable) {
            this.btnEdit.Visible = !enable;
            this.checkCtrl.Enabled = enable;
            this.checkAlt.Enabled = enable;
            this.checkShift.Enabled = enable;
            this.cmbKey.Enabled = enable;
            this.btnOk.Enabled = enable;
        }

        /// <summary>
        /// HotKeyRegister Resize
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HotKeyRegister_Resize(object sender, EventArgs e) {
            int gap = 5;
            int cmbMin = 30;
            this.Height = 23;
            this.btnEdit.Bounds = new Rectangle(0, 0, this.Width, this.Height);
            this.checkCtrl.Location = new Point(gap, 3);
            this.checkAlt.Location = new Point(this.checkCtrl.Right + gap, 3);
            this.checkShift.Location = new Point(this.checkAlt.Right + gap, 3);
            if (this.checkShift.Right + cmbMin + this.btnOk.Width + gap * 3 <= this.Width) {
                this.cmbKey.Location = new Point(this.checkShift.Right + gap, 1);
                this.btnOk.Location = new Point(this.Width - this.btnOk.Width - gap, 0);
                this.cmbKey.Width = this.btnOk.Left - gap - this.cmbKey.Left;
            } else {
                this.cmbKey.Location = new Point(this.checkShift.Right + gap, 1);
                this.cmbKey.Width = cmbMin;
                this.btnOk.Location = new Point(this.cmbKey.Right + gap, 0);
            }
        }

        /// <summary>
        /// cmbKeyの初期化
        /// </summary>
        private void SetCmdKey() {
            DataTable dt = new DataTable();
            dt.Columns.Add("Value");
            dt.Columns.Add("Disp");
            foreach (HotKeys key in Enum.GetValues(typeof(HotKeys))) {
                dt.Rows.Add(new object[] { (int)key, key.ToString() });
            }
            this.cmbKey.DataSource = dt;
            this.cmbKey.ValueMember = dt.Columns[0].ColumnName;
            this.cmbKey.DisplayMember = dt.Columns[1].ColumnName;
            this.cmbKey.DropDownStyle = ComboBoxStyle.DropDownList;
        }

        /// <summary>
        /// btnEditにHotKeyの値を設定
        /// </summary>
        private void SetText() {
            this.btnEdit.Text = string.Empty;

            if (this.checkCtrl.Checked) {
                this.btnEdit.Text += "Ctrl";
            }

            if (this.checkAlt.Checked) {
                if (!string.IsNullOrEmpty(this.btnEdit.Text)) {
                    this.btnEdit.Text += " + ";
                }
                this.btnEdit.Text += "Alt";
            }

            if (this.checkShift.Checked) {
                if (!string.IsNullOrEmpty(this.btnEdit.Text)) {
                    this.btnEdit.Text += " + ";
                }
                this.btnEdit.Text += "Shift";
            }

            if (!string.IsNullOrEmpty(this.btnEdit.Text)) {
                this.btnEdit.Text += " + ";
            }
            this.btnEdit.Text += this.cmbKey.Text;
        }

        /// <summary>
        /// HotKeyの登録
        /// </summary>
        /// <returns>true:成功,false:失敗</returns>
        private bool Register() {
            uint fsModifiers = 0;
            if (this.checkCtrl.Checked) {
                fsModifiers |= MOD_CONTROL;
            }
            if (this.checkAlt.Checked) {
                fsModifiers |= MOD_ALT;
            }
            if (this.checkShift.Checked) {
                fsModifiers |= MOD_SHIFT;
            }
            uint vk = uint.Parse(this.cmbKey.SelectedValue.ToString());
            if (RegisterHotKey(hHand, HOTKEY_ID, fsModifiers, vk) != 1) {
                MessageBox.Show("ホットキーは別のプログラムによって既に使用されています。");
                return false;
            }
            return true;
        }

        /// <summary>
        /// HotKeyの解除
        /// </summary>
        public void Unregister() {
            UnregisterHotKey(hHand, HOTKEY_ID);
        }

        /// <summary>
        /// HotKeyが押されたかどうか
        /// </summary>
        /// <param name="m"></param>
        /// <returns>true:押された,false:押されていない</returns>
        public bool HotKeyPressed(Message m) {

            if (m.Msg == WM_HOTKEY) {
                if ((int)m.WParam == HOTKEY_ID) {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// HotKeyRegister Load
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HotKeyRegister_Load(object sender, EventArgs e) {
            Form owner = this.FindForm();
            hHand = owner.Handle;
            owner.Shown += new EventHandler(owner_Shown);
            owner.FormClosed += new FormClosedEventHandler(owner_FormClosed);
        }

        /// <summary>
        /// ownerWindow Shown
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void owner_Shown(object sender, EventArgs e) {
            Register();
        }

        /// <summary>
        /// ownerWindow FormClosed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void owner_FormClosed(object sender, FormClosedEventArgs e) {
            Unregister();
        }

    }
}
