using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using BTS.Trac;
using BTS.Trac.Forms;
using BTS.Trac.Forms.Helper;
using VisualStudioTracAddIn;
using EnvDTE;
using EnvDTE80;

namespace VisualStudioTracAddIn
{
    public partial class FormTracAddIn : UserControl
    {
        /// <summary>
        /// アプリケーション名称
        /// </summary>
        public const string AppName = "VS Trac AddIn";

        /// <summary>
        /// 未接続メッセージ
        /// </summary>
        public const string NotConnect = "Trac へ接続されていません";
        public const string NotSelected = "チケットが選択されていません";

        /// <summary>
        /// アカウントのフォルダ
        /// </summary>
        string AccountForder = "";

        /// <summary>
        /// アカウントのファイルパス
        /// </summary>
        string AccountPath = "";

        /// <summary>
        /// オプションのパス
        /// </summary>
        string OptionPath = "";

        /// <summary>
        /// カラムパス
        /// </summary>
        string ColumnOptionPath = "";


        /// <summary>
        /// アプリケーションのオプション
        /// </summary>
        ApplicationOption Option = new ApplicationOption();

        public DTE2 ApplicationObject = null;

        /// <summary>
        /// チケット一覧
        /// </summary>
        private List<Ticket> Tickets = new List<Ticket>( 0 );

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public FormTracAddIn()
        {
            InitializeComponent();

            // パスの設定
            string BaseFolder = Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData );
            OptionPath = BaseFolder + "\\VisualStudioTracAddInOption.xml";
            ColumnOptionPath = BaseFolder + "\\VisualStudioTracAddInColumn.xml";

            AccountForder = BaseFolder + "\\TracAccount";
            AccountPath = AccountForder + "\\TracAccount.xml";

            // オプションの復元
            SettingLoad();

            // コンボボックスの表示
            ShowComboBox();

            // チケット更新タイマの設定
            timerTicketUpdate.Interval = Utility.MiniteToSecond( Option.TicketUpdate.Interval );
            timerTicketUpdate.Start();
        }

        /// <summary>
        /// 設定の保存
        /// </summary>
        private void SettingSave()
        {
            // 設定の保存
            Option.Save( OptionPath );

            // アカウントフォルダの作成
            if ( !Directory.Exists( AccountForder ) ) {
                Directory.CreateDirectory( AccountForder );
            }

            // アカウントの保存
            Option.AccountList.Save( AccountPath );

            // カラムの保存
            TicketListView.Save( ColumnOptionPath );
        }

        /// <summary>
        /// 設定の復元
        /// </summary>
        private void SettingLoad()
        {
            // 設定の復元
            if ( File.Exists( OptionPath ) ) {
                Option.Load( OptionPath );
            }

            // アカウントの復元
            if ( File.Exists( AccountPath ) ) {
                Option.AccountList.Load( AccountPath );
            }

            // カラムの復元
            if ( File.Exists( ColumnOptionPath ) ) {
                TicketListView.Load( ColumnOptionPath );
            }
        }

        /// <summary>
        /// コンボボックスの表示
        /// </summary>
        private void ShowComboBox()
        {
            // コンボボックスの初期化
            toolStripComboBox_Project.Items.Clear();
            foreach ( TracAccount account in Option.AccountList ) {
                toolStripComboBox_Project.Items.Add( account.ProjectName );
            }

            // アカウントが選択されていればコンボボックスを選択状態にする
            if ( Option.Selected != -1 ) {
                toolStripComboBox_Project.SelectedIndex = Option.Selected;
            }
        }

        /// <summary>
        /// チケットの作成
        /// </summary>
        private void CreateTicket()
        {
            if ( !Trac.IsConnected ) {
                throw new Exception( NotConnect );
            }

            FormTicket formTicket = new FormTicket( Option.SelectedAccount.ProjectName );
            DialogResult ret = formTicket.ShowDialog();
            if ( ret == DialogResult.OK ) {
                UpdateTicket();
            }
        }

        /// <summary>
        /// チケットの編集
        /// </summary>
        private void EditTicket()
        {
            if ( !Trac.IsConnected ) {
                throw new Exception( NotConnect );
            }

            if ( listTicket.SelectedIndices.Count == 0 ) {
                throw new Exception( NotSelected );
            }

            // 選択行の2番目(ID)を取得
            int selectedIndex = listTicket.SelectedIndices[0];
            int id = int.Parse( listTicket.SelectedItems[0].SubItems[1].Text );
            Ticket selectedTicket = null;
            foreach ( Ticket ticket in Tickets ) {
                if ( ticket.ID == id ) {
                    selectedTicket = ticket;
                    break;
                }
            }

            FormTicket formTicket = new FormTicket( selectedTicket, Option.SelectedAccount.ProjectName );
            DialogResult ret = formTicket.ShowDialog();
            if ( ret == DialogResult.OK ) {
                UpdateTicket();
            }
        }

        /// <summary>
        /// 設定ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButton_Option_Click( object sender, EventArgs e )
        {
            FormOption formOption = new FormOption( Option );
            DialogResult ret = formOption.ShowDialog();
            if ( ret == DialogResult.OK ) {
                Option = formOption.Option;
                ShowComboBox();

                // タイマの再起動
                timerTicketUpdate.Stop();
                timerTicketUpdate.Interval = Utility.MiniteToSecond( Option.TicketUpdate.Interval );
                timerTicketUpdate.Start();

                SettingSave();
            }

            //Solution sln = ApplicationObject.Solution;
            //if ( string.IsNullOrEmpty( sln.FullName ) ) {
            //    return;
            //}

            //// ファイル名からソリューションを取得
            //string SolutionName = Path.GetFileNameWithoutExtension( sln.FullName );
        }

        /// <summary>
        /// ダウンロードボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButtonDownload_Click( object sender, EventArgs e )
        {
            try {
                UpdateTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// チケットの作成ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButtonCreateTicket_Click( object sender, EventArgs e )
        {
            try {
                CreateTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// チケットの編集ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButtonUpdateTicket_Click( object sender, EventArgs e )
        {
            try {
                EditTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        ///  Trac のサイトへ移動ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButtonMoveTracSite_Click( object sender, EventArgs e )
        {
            try {
                if ( !Trac.IsConnected ) {
                    throw new Exception( NotConnect );
                }

                Utility.ShowTracSite( "" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 選択が変わった時に呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripComboBox_Project_SelectedIndexChanged( object sender, EventArgs e )
        {
            try {
                Option.Selected = toolStripComboBox_Project.SelectedIndex;
                Trac.Connect( Option.SelectedAccount.Url, Option.SelectedAccount.UserName,
                                Option.SelectedAccount.Password );

                // 表示更新
                TicketListView.ChangeProject( Option.SelectedAccount.ProjectName );
                TicketListView.UpdateTicketColumn();

                // チケットの更新
                UpdateTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// ダブルクリックで呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listTicket_MouseDoubleClick( object sender, MouseEventArgs e )
        {
            try {
                EditTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// チケットの更新
        /// </summary>
        private void UpdateTicket()
        {
            try {
                if ( !Trac.IsConnected ) {
                    throw new Exception( NotConnect );
                }

                Enabled = false;
                bgWorkerTicketUpdate.RunWorkerAsync();
            }
            catch ( Exception ex ) {
                Enabled = true;
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }
        
        /// <summary>
        /// スレッド
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgWorkerTicketUpdate_DoWork( object sender, DoWorkEventArgs e )
        {
            try {
                // チケットを更新する
                int[] ticketIDs = Ticket.Query( Option.TicketUpdate.Query );

                // チケットの個数を取得
                bgWorkerTicketUpdate.ReportProgress( 0, ticketIDs.Length );

                List<Ticket> newTickets = new List<Ticket>( ticketIDs.Length );
                for ( int i = 0; i < ticketIDs.Length; ++i ) {
                    newTickets.Add( new Ticket( ticketIDs[i] ) );

                    // 進捗を通知
                    bgWorkerTicketUpdate.ReportProgress( i + 1, ticketIDs.Length );
                }

                // 全部取得したらチケット一覧を更新
                Tickets = newTickets;
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 進捗
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgWorkerTicketUpdate_ProgressChanged( object sender, ProgressChangedEventArgs e )
        {
            // 初期化
            if ( e.ProgressPercentage == 0 ) {
                toolStripProgressBarTicketUpdate.Maximum = (int)e.UserState;
            }

            // 進捗設定
            toolStripProgressBarTicketUpdate.Value = e.ProgressPercentage;
        }

        /// <summary>
        /// スレッド終了
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgWorkerTicketUpdate_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e )
        {
            try {
                toolStripProgressBarTicketUpdate.Value = 0;

                listTicket.Clear();
                foreach ( Ticket ticket in Tickets ) {
                    listTicket.Add( ticket );
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
            finally {
                Enabled = true;
            }
        }

        /// <summary>
        /// <summary>
        /// 更新メニュー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RightClickMenu_Update_Click( object sender, EventArgs e )
        {
            try {
                UpdateTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 作成メニュー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RightClickMenu_Create_Click( object sender, EventArgs e )
        {
            try {
                CreateTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// 編集メニュー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RightClickMenu_Edit_Click( object sender, EventArgs e )
        {
            try {
                EditTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
            finally {
            }
        }

        /// <summary>
        /// Trac のサイトへ移動メニュー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RightClickMenu_TracSite_Click( object sender, EventArgs e )
        {
            try {
                if ( listTicket.SelectedIndices.Count == 0 ) {
                    return;
                }

                // 選択チケットの URL を開く
                int selectedIndex = listTicket.SelectedIndices[0];
                Utility.ShowTracSite( "ticket/" + Tickets[selectedIndex].ID.ToString() );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 右クリックメニューが開くときに呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rightClickMenu_Opening( object sender, CancelEventArgs e )
        {
            try {
                // リストが選択されていなければ選択できないメニュー
                bool visible = listTicket.SelectedIndices.Count != 0;
                RightClickMenu_TracSite.Visible = visible;
                RightClickMenu_Edit.Visible = visible;
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// タイムアウト
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerTicketUpdate_Tick( object sender, EventArgs e )
        {
            try {
                if ( Trac.IsConnected ) {
                    UpdateTicket();
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }
    }
}
