using System;
using System.Threading;
using System.Xml;
using System.Collections.Generic;
using System.Diagnostics;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using BTS.Trac;
using BTS.Trac.Forms;

namespace TaskTrayTrac
{
    /// <summary>
    /// オプションのUI
    /// </summary>
    public partial class FormOption : Form
    {
        private bool IsCloseCancel = false;

        /// <summary>
        /// オプション
        /// </summary>
        public TaskTrayTracOption Option
        {
            get;
            private set;
        }

        /// 一時的にキー設定を保持する
        /// 
        private TaskTrayTracOption.ShortcutKey ShortcutTicketCreate = new TaskTrayTracOption.ShortcutKey();

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="Option"></param>
        public FormOption( TaskTrayTracOption Option )
        {
            InitializeComponent();

            this.Option = Option;

            // コンボボックスの作成
            foreach ( TracAccount Account in Option.AccountList ) {
                comboSelectUrl.Items.Add( Account.ProjectName );
            }

            comboSelectUrl.SelectedIndex = Option.Selected;
            checkBoxAutoRun.Checked = Option.IsAutoRun;

            // 周期を設定
            textBoxInterval.Text = Option.TicketUpdate.Interval.ToString();
            textBoxQuery.Text = Option.TicketUpdate.Query;

            checkBoxEnableAlart.Checked = Option.TicketUpdate.EnableAlart;
            textBoxAlartTime.Text = Option.TicketUpdate.AlartTime.ToString();
            ChangeAlartState();

            // ショートカットキーの初期表示
            checkBoxSCTicketCreate.Checked = Option.ShortcutTicketCreate.Enable;
            checkBoxSCTicketCreate_CheckedChanged(this, null);
            KeyEventArgs kevent = new KeyEventArgs(
                Option.ShortcutTicketCreate.Key |
                (Option.ShortcutTicketCreate.Shift ? Keys.Shift : Keys.None) |
                (Option.ShortcutTicketCreate.Ctrl ? Keys.Control : Keys.None) |
                (Option.ShortcutTicketCreate.Alt ? Keys.Alt : Keys.None)
                );
            textBoxSCTicketCreate_KeyDown(this, kevent);

            // バージョン情報
            labelVersion.Text = ExeVersion.Version;
        }

        /// <summary>
        /// フォームの表示直前動作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormOption_Load( object sender, EventArgs e )
        {

        }

        /// <summary>
        /// 自動起動の有効/無効切り替え
        /// </summary>
        /// <param name="enable"></param>
        private void EnableAutoRun( bool enable )
        {
            // Runキーを開く
            using ( RegistryKey regkey = Registry.CurrentUser.OpenSubKey(
                            @"Software\Microsoft\Windows\CurrentVersion\Run", true ) ) {
                // 有効にする場合は、値の名前に製品名、値のデータに実行ファイルのパスを指定
                if ( enable ) {
                    regkey.SetValue( Application.ProductName, "\"" + Application.ExecutablePath + "\"" );
                }
                // 無効にする場合は、値を削除
                else {
                    if ( regkey.GetValue( Application.ProductName ) != null ) {
                        regkey.DeleteValue( Application.ProductName );
                    }
                }
            }
        }

        /// <summary>
        /// アカウントの追加ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonAccountAdd_Click( object sender, EventArgs e )
        {
            FormTracLogin form = new FormTracLogin();
            DialogResult ret = form.ShowDialog();
            if ( ret == DialogResult.OK ) {
                Option.AccountList.Add( form.Account );

                // コンボボックスに追加し、それを選択状態にする
                comboSelectUrl.Items.Add( form.Account.ProjectName );
                comboSelectUrl.SelectedIndex = comboSelectUrl.Items.Count - 1;
            }
        }

        /// <summary>
        /// アカウントの編集ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonAccountEdit_Click( object sender, EventArgs e )
        {
            int SelectedIndex = comboSelectUrl.SelectedIndex;
            if ( SelectedIndex == -1 ) {
                return;
            }

            FormTracLogin form = new FormTracLogin( Option.AccountList[SelectedIndex] );
            DialogResult ret = form.ShowDialog();
            if ( ret == DialogResult.OK ) {
                Option.AccountList[SelectedIndex] = form.Account;

                // コンボボックスを入れなおし、選択しなおし
                comboSelectUrl.Items.RemoveAt( SelectedIndex );
                comboSelectUrl.Items.Insert( SelectedIndex, form.Account.ProjectName );
                comboSelectUrl.SelectedIndex = SelectedIndex;
            }
        }

        /// <summary>
        /// アカウントの削除ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonAccountDelete_Click( object sender, EventArgs e )
        {
            // 選択された項目を削除する
            int SelectedIndex = comboSelectUrl.SelectedIndex;
            if ( SelectedIndex == -1 ) {
                return;
            }

            comboSelectUrl.Items.RemoveAt( SelectedIndex );
            Option.AccountList.RemoveAt( SelectedIndex );

            // アカウント情報がなくなった
            if ( comboSelectUrl.Items.Count == 0 ) {
                Option.Selected = -1;
            }
            // アイテム数と選択番号が同じになった（最後の要素の削除した）場合、
            // 直前のインデックスを選択する
            else if ( comboSelectUrl.Items.Count == SelectedIndex ) {
                Option.Selected = comboSelectUrl.SelectedIndex = SelectedIndex - 1;
            }
            // その他（削除後の街頭インデックスを選択させる）
            else {
                Option.Selected = comboSelectUrl.SelectedIndex = SelectedIndex;
            }
        }

        /// <summary>
        /// OKボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonOK_Click( object sender, EventArgs e )
        {
            try {
                // チケット更新周期を取得
                int interval = int.Parse( textBoxInterval.Text );
                if ( (interval < 1) || (60 < interval) ) {
                    throw new Exception( "チケット更新周期は1～60分です" );
                }

                // アラート表示時間を取得
                int alartTime = int.Parse( textBoxAlartTime.Text );
                if ( (alartTime < 1) || (60 < alartTime) ) {
                    throw new Exception( "アラート表示周期は1～60秒です" );
                }

                if (textBoxSCTicketCreate.Text == "")
                {
                    throw new Exception("ショートカットキーが指定されていません");
                }

                Option.TicketUpdate.Interval = interval;
                Option.TicketUpdate.Query = textBoxQuery.Text;
                Option.TicketUpdate.AlartTime = alartTime;
                Option.TicketUpdate.EnableAlart = checkBoxEnableAlart.Checked;

                // チケット登録のショートカット登録
                Option.ShortcutTicketCreate = ShortcutTicketCreate;

                // アカウントの選択状態を取得
                Option.Selected = comboSelectUrl.SelectedIndex;

                // 自動起動状態を変更
                if ( Option.IsAutoRun != checkBoxAutoRun.Checked ) {
                    EnableAutoRun( checkBoxAutoRun.Checked );
                    Option.IsAutoRun = checkBoxAutoRun.Checked;
                }

                Close();
            }
            catch ( Exception ex ) {
                IsCloseCancel = true;
                MessageBox.Show( ex.Message, FormTracTaskTray.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// キャンセルボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonCancel_Click( object sender, EventArgs e )
        {
            try {
                Close();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, FormTracTaskTray.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// アラートの変更
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBoxEnableAlart_CheckedChanged( object sender, EventArgs e )
        {
            ChangeAlartState();
        }

        /// <summary>
        /// アラート入力項目の変更
        /// </summary>
        private void ChangeAlartState()
        {
            labelAlartTimePrefix.Enabled = checkBoxEnableAlart.Checked;
            textBoxAlartTime.Enabled = checkBoxEnableAlart.Checked;
            labelAlartTimePostfix.Enabled = checkBoxEnableAlart.Checked;
        }

        /// <summary>
        /// フォームのクローズ中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormOption_FormClosing( object sender, FormClosingEventArgs e )
        {
            if ( IsCloseCancel ) {
                e.Cancel = true;
                IsCloseCancel = false;
            }
        }

        /// <summary>
        /// SF.jp へのリンク
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void linkLabelSFjp_LinkClicked( object sender, LinkLabelLinkClickedEventArgs e )
        {
            try {
                Process.Start( "http://sourceforge.jp/projects/shibuya-trac/wiki/contrib%2FTaskTrayTrac" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, FormTracTaskTray.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// blog へのリンククリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void linkLabelBlog_LinkClicked( object sender, LinkLabelLinkClickedEventArgs e )
        {
            try {
                Process.Start( linkLabelBlog.Text );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, FormTracTaskTray.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// メールアドレスのリンククリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void linkLabelEMail_LinkClicked( object sender, LinkLabelLinkClickedEventArgs e )
        {
            try {
                Process.Start( "mailto:" + linkLabelEMail.Text );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, FormTracTaskTray.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// チケット登録のショートカットキー登録テキストボックス
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxSCTicketCreate_KeyPress(object sender, KeyPressEventArgs e)
        {
            // キー入力を無効化
            e.Handled = true;
        }
        /// <summary>
        /// チケット登録のショートカットキー登録テキストボックス
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxSCTicketCreate_KeyDown(object sender, KeyEventArgs e)
        {
            KeysConverter kc = new KeysConverter();
            string display = kc.ConvertToString(e.KeyCode);
            if (e.KeyCode != Keys.ShiftKey &&
                e.KeyCode != Keys.ControlKey &&
                e.KeyCode != Keys.Menu)
            {
                ShortcutTicketCreate.Key = e.KeyCode;
                if (e.Shift)
                {
                    ShortcutTicketCreate.Shift = true;
                    display += " + Shift";
                }
                else
                {
                    ShortcutTicketCreate.Shift = false;
                }
                if (e.Control)
                {
                    ShortcutTicketCreate.Ctrl = true;
                    display += " + Ctrl";
                }
                else
                {
                    ShortcutTicketCreate.Ctrl = false;
                }
                if (e.Alt)
                {
                    ShortcutTicketCreate.Alt = true;
                    display += " + Alt";
                }
                else
                {
                    ShortcutTicketCreate.Alt = false;
                }

                textBoxSCTicketCreate.Text = display;
            }
        }

        /// <summary>
        /// ショートカットキーの有効無効
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBoxSCTicketCreate_CheckedChanged(object sender, EventArgs e)
        {
            ShortcutTicketCreate.Enable = textBoxSCTicketCreate.Enabled = checkBoxSCTicketCreate.Checked;
            
        }
    }

    /// <summary>
    /// オプションのデータ
    /// </summary>
    public class TaskTrayTracOption
    {
        class XML_TAG
        {
            public const string ROOT = "root";

            // ウィンドウ情報
            public const string VIEW_WINDOW = "view_window";
            public const string X = "x";
            public const string Y = "y";
            public const string WIDTH = "width";
            public const string HEIGHT = "height";

            // アカウント情報
            public const string SELECT = "select";

            // 自動実行
            public const string AUTO_RUN = "autorun";

            // チケットの自動更新
            public const string TICKET_UPDATE = "ticket_update";
            public const string INTERVAL = "interval";
            public const string QUERY = "query";
            public const string ENABLE_ALART = "enable_alart";
            public const string ALART_TIME = "alart_time";
            public const string PREV_UPDATE_TIME = "prev_update_time";

            // ショートカットキーの設定
            public const string SHORTCUT = "shortcut";
            public const string SC_TICKET_CREATE_ENABLE = "sc_TicketCreateEnable";
            public const string SC_TICKET_CREATE_KEY = "sc_TicketCreateKey";
            public const string SC_TICKET_CREATE_SHIFT = "sc_TicketCreateShift";
            public const string SC_TICKET_CREATE_CTRL = "sc_TicketCreateCtrl";
            public const string SC_TICKET_CREATE_ALT = "sc_TicketCreateAlt";

        }

        /// <summary>
        /// チケットの自動更新
        /// </summary>
        public class TicketAutoUpdate
        {
            public int Interval = 3;
            public string Query = "status!=closed";
            public bool EnableAlart = true;
            public int AlartTime = 3;
            public DateTime PrevUpdateTime = DateTime.Today;
        }

        // ショートカットキー
        public class ShortcutKey
        {
            public bool Enable = true;
            public Keys Key = Keys.T;
            public bool Shift = false;
            public bool Ctrl = true;
            public bool Alt = true;

            /// <summary>
            /// コンストラクタ
            /// </summary>
            /// <param name="sck"></param>
            public ShortcutKey()
            {
            }

            /// <summary>
            /// コピーコンストラクタ
            /// </summary>
            /// <param name="sck"></param>
            public ShortcutKey(ShortcutKey sck)
            {
                this.Key = sck.Key;
                this.Shift = sck.Shift;
                this.Ctrl = sck.Ctrl;
                this.Alt = sck.Alt;
            }
        }

        /// <summary>
        /// ウィンドウの表示位置
        /// </summary>
        public class WindowLocation
        {
            public Point Location = new Point();
            public Size Size = new Size( 700, 350 );
        }

        /// <summary>
        /// アカウント情報リスト
        /// </summary>
        public TracAccountList AccountList
        {
            get;
            set;
        }

        /// <summary>
        /// アカウントの選択インデックス
        /// </summary>
        public int Selected
        {
            get;
            set;
        }

        /// <summary>
        /// 選択されたアカウント情報
        /// </summary>
        public TracAccount SelectedAccount
        {
            get
            {
                return (Selected != -1) ? AccountList[Selected] : null;
            }
        }

        /// <summary>
        /// チケットの自動更新
        /// </summary>
        public TicketAutoUpdate TicketUpdate
        {
            get;
            set;
        }

        /// <summary>
        /// チケット作成のショートカットキー
        /// </summary>
        public ShortcutKey ShortcutTicketCreate
        {
            get;
            set;
        }

        /// <summary>
        /// 自動起動の有効/無効状態
        /// </summary>
        public bool IsAutoRun
        {
            get;
            set;
        }

        /// <summary>
        /// チケット一覧画面の表示位置
        /// </summary>
        public WindowLocation ViewLocation
        {
            get;
            set;
        }

        /// <summary>
        /// デフォルトコンストラクタ
        /// </summary>
        public TaskTrayTracOption()
        {
            Selected = -1;

            AccountList = new TracAccountList();
            ViewLocation = new WindowLocation();

            IsAutoRun = false;
            TicketUpdate = new TicketAutoUpdate();
            ShortcutTicketCreate = new ShortcutKey();
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="path">保存ファイルパス</param>
        public TaskTrayTracOption( string path )
            : this()
        {
            Load( path );
        }

        /// <summary>
        /// オプションの保存
        /// </summary>
        /// <param name="path">保存パス</param>
        public void Save( string path )
        {
            // XML として保存
            XmlDocument xml = new XmlDocument();
            xml.AppendChild( xml.CreateXmlDeclaration( "1.0", "utf-8", null ) );

            XmlNode root = xml.CreateElement( XML_TAG.ROOT );

            // チケット一覧画面の表示位置保存
            XmlNode viewWindow = XmlHelper.AppendChild( xml, root, XML_TAG.VIEW_WINDOW );
            XmlHelper.AppendChild( xml, viewWindow, XML_TAG.X, ViewLocation.Location.X.ToString() );
            XmlHelper.AppendChild( xml, viewWindow, XML_TAG.Y, ViewLocation.Location.Y.ToString() );
            XmlHelper.AppendChild( xml, viewWindow, XML_TAG.WIDTH, ViewLocation.Size.Width.ToString() );
            XmlHelper.AppendChild( xml, viewWindow, XML_TAG.HEIGHT, ViewLocation.Size.Height.ToString() );

            // アカウント選択の保存
            XmlHelper.AppendChild( xml, root, XML_TAG.SELECT, Selected.ToString() );

            // 自動起動の保存
            XmlHelper.AppendChild( xml, root, XML_TAG.AUTO_RUN, IsAutoRun.ToString() );

            // チケットの自動更新
            XmlNode ticketUpdate = XmlHelper.AppendChild( xml, root, XML_TAG.TICKET_UPDATE );
            XmlHelper.AppendChild( xml, ticketUpdate, XML_TAG.INTERVAL, TicketUpdate.Interval.ToString() );
            XmlHelper.AppendChild( xml, ticketUpdate, XML_TAG.QUERY, TicketUpdate.Query );
            XmlHelper.AppendChild( xml, ticketUpdate, XML_TAG.ENABLE_ALART, TicketUpdate.EnableAlart.ToString() );
            XmlHelper.AppendChild( xml, ticketUpdate, XML_TAG.ALART_TIME, TicketUpdate.AlartTime.ToString() );
            XmlHelper.AppendChild( xml, ticketUpdate, XML_TAG.PREV_UPDATE_TIME, TicketUpdate.PrevUpdateTime.ToBinary().ToString() );

            // ショートカットキー
            XmlNode shortcut = XmlHelper.AppendChild(xml, root, XML_TAG.SHORTCUT);
            XmlHelper.AppendChild(xml, shortcut, XML_TAG.SC_TICKET_CREATE_ENABLE, ShortcutTicketCreate.Enable.ToString());
            KeysConverter kc = new KeysConverter();
            XmlHelper.AppendChild(xml, shortcut, XML_TAG.SC_TICKET_CREATE_KEY, kc.ConvertToString(ShortcutTicketCreate.Key));
            XmlHelper.AppendChild(xml, shortcut, XML_TAG.SC_TICKET_CREATE_SHIFT, ShortcutTicketCreate.Shift.ToString());
            XmlHelper.AppendChild(xml, shortcut, XML_TAG.SC_TICKET_CREATE_CTRL, ShortcutTicketCreate.Ctrl.ToString());
            XmlHelper.AppendChild(xml, shortcut, XML_TAG.SC_TICKET_CREATE_ALT, ShortcutTicketCreate.Alt.ToString());

            xml.AppendChild( root );

            // 保存
            xml.Save( path );
        }

        /// <summary>
        /// オプションの復元
        /// </summary>
        /// <param name="path">復元パス</param>
        public void Load( string path )
        {
            // XML から復元
            XmlDocument xml = new XmlDocument();
            xml.Load( path );

            try {
                // チケット一覧画面の表示位置復元
                ViewLocation = new WindowLocation();
                ViewLocation.Location = new Point()
                {
                    X = int.Parse( xml.SelectNodes( "//" + XML_TAG.X )[0].InnerText ),
                    Y = int.Parse( xml.SelectNodes( "//" + XML_TAG.Y )[0].InnerText )
                };
                ViewLocation.Size = new Size()
                {
                    Width = int.Parse( xml.SelectNodes( "//" + XML_TAG.WIDTH )[0].InnerText ),
                    Height = int.Parse( xml.SelectNodes( "//" + XML_TAG.HEIGHT )[0].InnerText )
                };

                // 自動起動
                IsAutoRun = bool.Parse( xml.SelectNodes( "//" + XML_TAG.AUTO_RUN )[0].InnerText );

                // チケットの自動更新
                TicketUpdate.Interval = int.Parse( xml.SelectNodes( "//" + XML_TAG.INTERVAL )[0].InnerText );
                TicketUpdate.Query = xml.SelectNodes( "//" + XML_TAG.QUERY )[0].InnerText;
                TicketUpdate.EnableAlart = bool.Parse( xml.SelectNodes( "//" + XML_TAG.ENABLE_ALART )[0].InnerText );
                TicketUpdate.AlartTime = int.Parse( xml.SelectNodes( "//" + XML_TAG.ALART_TIME )[0].InnerText );
                TicketUpdate.PrevUpdateTime = DateTime.FromBinary( long.Parse( xml.SelectNodes( "//" + XML_TAG.PREV_UPDATE_TIME )[0].InnerText ) );

                // ショートカットキーの設定
                KeysConverter kc = new KeysConverter();
                ShortcutTicketCreate.Enable = bool.Parse(xml.SelectNodes("//" + XML_TAG.SC_TICKET_CREATE_ENABLE)[0].InnerText);
                ShortcutTicketCreate.Key = (Keys)kc.ConvertFrom(xml.SelectNodes("//" + XML_TAG.SC_TICKET_CREATE_KEY)[0].InnerText);
                ShortcutTicketCreate.Shift = bool.Parse(xml.SelectNodes("//" + XML_TAG.SC_TICKET_CREATE_SHIFT)[0].InnerText);
                ShortcutTicketCreate.Ctrl = bool.Parse(xml.SelectNodes("//" + XML_TAG.SC_TICKET_CREATE_CTRL)[0].InnerText);
                ShortcutTicketCreate.Alt = bool.Parse(xml.SelectNodes("//" + XML_TAG.SC_TICKET_CREATE_ALT)[0].InnerText);

                // 選択番号の復元
                Selected = -1;
                Selected = int.Parse( xml.SelectNodes( "//" + XML_TAG.SELECT )[0].InnerText );
            }
            catch {
                ViewLocation = new WindowLocation();
            }
        }
    }
}
