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.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using BTS.Trac;
using BTS.Trac.Forms;
using VersionInfo;

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

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

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

            this.Option = Option;

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

            comboSelectUrl.SelectedIndex = Option.Selected;

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

            // バージョン情報
            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="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分です" );
                }

                Option.TicketUpdate.Interval = interval;
                Option.TicketUpdate.Query = textBoxQuery.Text;

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

                Close();
            }
            catch ( Exception ex ) {
                IsCloseCancel = true;
                MessageBox.Show( ex.Message, FormTracAddIn.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, FormTracAddIn.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <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%2FVisualStudioTracAddIn" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, FormTracAddIn.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, FormTracAddIn.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, FormTracAddIn.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }
    }

    /// <summary>
    /// オプションのデータ
    /// </summary>
    public class ApplicationOption
    {
        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 TICKET_UPDATE = "ticket_update";
            public const string INTERVAL = "interval";
            public const string QUERY = "query";
            public const string PREV_UPDATE_TIME = "prev_update_time";
        }

        /// <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;
        }

        /// <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 bool IsAutoRun
        {
            get;
            set;
        }

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

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

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

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

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="path">保存ファイルパス</param>
        public ApplicationOption( 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() );

            // チケットの自動更新
            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.PREV_UPDATE_TIME, TicketUpdate.PrevUpdateTime.ToBinary().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 )
                };

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

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