using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Win32;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;  // for DllImport


public class Win32API 
{
    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow(string lpszClass, string lpszWindow);

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
}

namespace GuiEdit
{
    /// <summary>
    /// Window1.xaml の相互作用ロジック
    /// </summary>
    /// 
    public class Global_Val
    {
        // グローバル変数の宣言
        static public int KDP_line_num = -1;  
    }

    public partial class Window1 : Window
    {
        public Window1()
        {
            // Dialog上の部品初期化
            InitializeComponent();

            // 引数から dot.nodokaのパスを取得する。
            string file_name = get_arg();
            
            // file open 
            // todo: 任意のフォーマット(ANSI,Shift-JIS, UTF-8, UTF-16)対応
            // ファイルからテキストを読み出し。
            //MessageBox.Show(file_name);

            this.statusBar1.Content = file_name;
            read_dotnodoka(file_name);

            // keymap Global の検索
            int keymap_Global_line_num = get_keymap_Global();
            if (keymap_Global_line_num == -1)
            {
                // 見つからなかったので、新規ファイルと判断して、下記文を挿入。
                this.listBox1.Items.Insert(0, "# [EOF]");
                this.listBox1.Items.Insert(0, "");
                this.listBox1.Items.Insert(0, "keymap Global");
                if (get_layout())
                    this.listBox1.Items.Insert(0, "include \"109.nodoka\"");
                else
                    this.listBox1.Items.Insert(0, "include \"104.nodoka\"");

                this.listBox1.Items.Insert(0, "");
                this.listBox1.Items.Insert(0, "# dot.nodoka    generated by GuiEdit");
            }

            // def option KeyboardDelay 検索
            KeyboardDelayParam KDP = get_def_option_KeyboardDelay();

            if (KDP.line_num != -1)
            {
                // 読み込んだ設定値をUIに反映
                if (KDP.bEnable)
                    this.checkBox1.IsChecked = true;

                // delayA,B 値域チェック
                if (KDP.delayA < 100)
                    KDP.delayA = 100;
                if (KDP.delayA > 3000)
                    KDP.delayA = 3000;

                if (KDP.delayB < 5)
                    KDP.delayB = 5;
                if (KDP.delayB > 500)
                    KDP.delayB = 500;

            }
            else
            {
                // まだ dot.nodoka では未設定だったのでシステムの設定値を取出す
                int tmp_delayA = SystemParameters.KeyboardDelay;
                if (tmp_delayA < 0)
                    tmp_delayA = 0;         // 250, 500, 750, 1000
                if (tmp_delayA > 3)
                    tmp_delayA = 3;

                int tmp_delayB = SystemParameters.KeyboardSpeed;
                if (tmp_delayB <= 0)
                    tmp_delayB = 0;         // 0: 2.5/s
                if (tmp_delayB > 31)
                    tmp_delayB = 31;        // 31: 30/s  maybe y = 1/(x+2.5)

                KDP.delayA = tmp_delayA * 250 + 250;
                KDP.delayB = (10 * 1000) / ((tmp_delayB * 10)  + 25);
                
            }

            this.slider1.Value = KDP.delayA;
            this.slider2.Value = KDP.delayB;

            Global_Val.KDP_line_num = KDP.line_num;
        }

        private static string get_arg()
        {
            // 引数から dot.nodoka ファイルのパスを取得する
            string[] cmds;
            cmds = System.Environment.GetCommandLineArgs();

            string file_name = "dot.nodoka";
            if (cmds.Length >= 2)
            {
                file_name = cmds[1];
            }

            return file_name;
        }

        public struct KeyboardDelayParam
        {
            public bool bEnable;
            public int line_num, delayA, delayB;

            public KeyboardDelayParam(int mline_num, bool bmEnable, int mdelayA, int mdelayB)
            {
                line_num = mline_num;
                bEnable = bmEnable;
                delayA = mdelayA;
                delayB = mdelayB;
            }
        }

        public int get_keymap_Global()
        {
            int i;
            string line;
            int num = this.listBox1.Items.Count;
            for (i = 0; i < num; i++)
            {
                line = this.listBox1.Items.GetItemAt(i).ToString();
                line = line.TrimStart(null); // 文頭ホワイトスペースを取り除く

                if (line.StartsWith("#"))
                {
                    // コメント
                    continue;
                }
                else if (line.Length == 0)
                {
                    // 空行
                    continue;
                }
                else
                {
                    string[] line1 = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                    // keymap Global文検出。
                    if (line1[0].StartsWith("keymap"))
                        if (line1[1].StartsWith("Global"))
                        {
                            return i;
                        }
                }
             }
             return -1;
        }

        public int get_include_104_109()
        {
            int line_num = -1;
            return line_num;
        }

        public bool get_layout()
        {
            // 操作するレジストリ・キーの名前
            string rKeyName64 = @"Software\Wow6432Node\appletkan\\nodoka";
            string rKeyName86 = @"Software\appletkan\\nodoka";
            // 取得処理を行う対象となるレジストリの値の名前
            string rGetValueName = "layout";

            try
            {
                RegistryKey rKey = Registry.LocalMachine.OpenSubKey(rKeyName86);
                string layout = (string)rKey.GetValue(rGetValueName);
                rKey.Close();

                if (layout.StartsWith("109"))
                    return true;
            }
            catch (NullReferenceException)
            {
                try
                {
                    RegistryKey rKey = Registry.LocalMachine.OpenSubKey(rKeyName64);
                    string layout = (string)rKey.GetValue(rGetValueName);
                    rKey.Close();
                    if (layout.StartsWith("109"))
                        return true;
                }
                catch (NullReferenceException)
                {
                    return false;
                }
            }
            return false;
        }


        public KeyboardDelayParam get_def_option_KeyboardDelay()
        {
            int i;
            int num = this.listBox1.Items.Count;
            KeyboardDelayParam KDP = new KeyboardDelayParam();
            KDP.line_num = -1;
            int line_num = -1;
            bool bEnable = false;
            int delayA = 0;
            int delayB = 0;

            for (i = num-1; i >= 0; i--)    // 文末から検索する。
            {
                if (PerseLine_def_option_KeyboardDelay(this.listBox1.Items.GetItemAt(i).ToString(), out line_num, out bEnable, out delayA, out delayB) == true)
                {
                    KDP.line_num = i;
                    KDP.bEnable = bEnable;
                    KDP.delayA = delayA;
                    KDP.delayB = delayB;
                    break;
                }
            }
            return KDP;
        }

        public bool read_dotnodoka(string file_name) 
        {
            try 
            {
                using (StreamReader sr = new StreamReader(file_name, Encoding.GetEncoding("Shift_JIS"))) 
                {
                    string line;
                    int i = 1;
                    while ((line = sr.ReadLine()) != null) 
                    {
                        this.listBox1.Items.Add(line);
                        i++;
                    }
                    sr.Close();
                }
            }
            catch (Exception e) 
            {
                // Let the user know what went wrong.
                //MessageBox.Show(e.Message, "dot.nodoka Editor");  // ファイルが見つからないとここでエラーとなるが何もしない。
                return false;
            }
            
            return true;
        }

        public bool write_dotnodoka(string file_name)
        {
            //MessageBox.Show(file_name);

            try
            {
                // backupを作成する。
                string randomname = System.IO.Path.GetRandomFileName();
                System.IO.File.Copy(@file_name, @file_name + "." + randomname + ".bak", true);
            }
            catch (Exception e)
            {
                // 新規の場合などでも、ここでエラーとなるので、特に何もしない。
            }

            try
            {
                using (StreamWriter sw = new StreamWriter(file_name, false, Encoding.GetEncoding("Shift_JIS")))
                {
                    int i;
                    int num = this.listBox1.Items.Count;
                    for (i = 0; i < num; i++)
                    {
                        sw.WriteLine(this.listBox1.Items.GetItemAt(i));
                    }
                    sw.Flush();
                    sw.Close();
                }
            }
            catch (Exception e)
            {
                // Let the user know what went wrong.
                MessageBox.Show(e.Message, "dot.nodoka Editor");
                return false;
            }

            //this.listBox1.Items.Clear();
            return true;
        }

        private bool PerseLine_def_option_KeyboardDelay(string line, out int line_num, out bool bEnable, out int delayA, out int delayB)
        {
            line_num = -1;
            bEnable = false;
            delayA = 0;
            delayB = 0;

            line = line.TrimStart(null); // 文頭ホワイトスペースを取り除く

            if (line.StartsWith("#"))
            {
                // コメント
                return false;
            }
            else if (line.Length == 0)
            {
                // 空行
                return false;
            }
            else
            {
                string[] line1 = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                // def option KeyboardDelay文検出。
                if (line1[0].StartsWith("def"))
                    if (line1[1].StartsWith("option"))
                        if (line1[2] == ("KeyboardDelay"))
                        {
                            if (line1[4].StartsWith("enable"))
                                bEnable = true;
                            else
                                bEnable = false;

                            delayA = Convert.ToInt32(line1[5]);
                            delayB = Convert.ToInt32(line1[6]);

                            return true;
                        }
                return false;
            }
        }


        private void button1_Click(object sender, RoutedEventArgs e)
        {
            // Cancel button
            this.Close();
        }

        private void button3_Click(object sender, RoutedEventArgs e)
        {
            // reload button
            UInt32 WM_COMMAND = 0x0111;
            Int32 ID_MENUITEM_reload = 40002;

            // UI setting to ListBox1 and save dot.nodoka
            update_data();

            // clear textbox1
            this.textBox1.Text = "";

            // reload
            IntPtr i_hwnd = Win32API.FindWindow("nodokaTasktray", null);
            Win32API.SendMessage(i_hwnd, WM_COMMAND, ID_MENUITEM_reload, 0);

            KeyboardDelayParam KDP = get_def_option_KeyboardDelay();
            Global_Val.KDP_line_num = KDP.line_num;

        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            // OK button
            
            UInt32 WM_COMMAND = 0x0111;
            Int32 ID_MENUITEM_reload = 40002;

            // UI setting to ListBox1 and save dot.nodoka
            update_data();

            // reload
            IntPtr i_hwnd = Win32API.FindWindow("nodokaTasktray", null);
            Win32API.SendMessage(i_hwnd, WM_COMMAND, ID_MENUITEM_reload, 0);

            // close
            this.Close();
        }

        private void update_data()
        {
            string sEnable;
            string sdelayA;
            string sdelayB;
            string write_data;

            int line_num = get_keymap_Global() + 1;     // keymap Globalの次の行

            if (Global_Val.KDP_line_num != -1)
            {
                line_num = Global_Val.KDP_line_num;
                this.listBox1.Items.RemoveAt(line_num);
            }

            // GUIの情報を追加
            if (this.checkBox1.IsChecked == true)
                sEnable = "enable";
            else
                sEnable = "disable";

            sdelayA = this.slider1.Value.ToString();
            sdelayB = this.slider2.Value.ToString();

            write_data = "def option KeyboardDelay = " + sEnable + " " + sdelayA + " " + sdelayB;
            this.listBox1.Items.Insert(line_num, write_data);

            // file save
            write_dotnodoka(get_arg());
        }
    }
}
