using System;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BTS.Trac;
using BTS.Trac.Forms;
using BTS.Trac.Forms.Helper;
using CustomUIControls;
using KeyHookLib;

namespace TaskTrayTrac
{
    public partial class FormTracTaskTray : Form
    {
        delegate void TicketAlartProc( int[] ChangedTicketIDs );
        delegate void UpdateTickeViewProc( List<Ticket> Tikets, TaskTrayTracOption Option );

        #region フィールド
        /// <summary>
        /// チケットアラートのためのデリゲート
        /// </summary>
        TicketAlartProc TicketAlart = null;
        UpdateTickeViewProc UpdateTickeView = null;

        /// <summary>
        /// アプリケーション名
        /// </summary>
        public const string AppName = "TaskTrayTrac";

        /// <summary>
        /// アプリの終了中
        /// </summary>
        bool IsAppCloseed = false;

        /// <summary>
        /// メニューの表示中
        /// </summary>
        bool IsMenuShown = false;

        /// <summary>
        /// ファイル保存フォルダ
        /// </summary>
        string BaseFolder = "";

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

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

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

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

        /// <summary>
        /// オプション
        /// </summary>
        TaskTrayTracOption Option = new TaskTrayTracOption();

        /// <summary>
        /// チケット更新スレッド
        /// </summary>
        private Thread TicketUpdateThread = null;

        /// <summary>
        /// タスクトレイアラート
        /// </summary>
        TaskbarNotifier Notifier = new TaskbarNotifier();

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

        /// <summary>
        /// チケット一覧画面
        /// </summary>
        private FormViewTicket FormViewTicket = new FormViewTicket();

        /// <summary>
        /// ショートカットキーチケット登録
        /// </summary>
        private ShortcutKey ShortcutTicketCreate = null;
        #endregion

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

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

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

                // ショートカットキーフックを作成
                ShortcutTicketCreate = new ShortcutKey(new ShortcutkeyPlessedHandler(ShortcutTicketCreateHandler));

                // 設定の復元
                SettingLoad();

                // ショートカットキーを登録
                ShortcutTicketCreate.Key = Option.ShortcutTicketCreate.Key;
                ShortcutTicketCreate.KeyShift = Option.ShortcutTicketCreate.Shift;
                ShortcutTicketCreate.KeyCtrl = Option.ShortcutTicketCreate.Ctrl;
                ShortcutTicketCreate.KeyAlt = Option.ShortcutTicketCreate.Alt;

                // チケット更新タイマの設定
                timerTicketUpdate.Interval = Utility.MiniteToSecond( Option.TicketUpdate.Interval );
                timerTicketUpdate.Tick += new EventHandler( timerTicketUpdate_Tick );

                TicketAlart += TicketUpdateAlart;
                Notifier.ContentClick += new EventHandler( Notifier_ContentClick );

                UpdateTickeView += new UpdateTickeViewProc( FormViewTicket.UpdateTicketView );

                FormViewTicket.UpdateTicket += new FormViewTicket.UpdateTicketProc( this.StartUpdateTicket );

                // 表示サイズの設定
                if ( Option.ViewLocation.Location != null ) {
                    FormViewTicket.Location = Option.ViewLocation.Location;
                }
                if ( Option.ViewLocation.Size != null ) {
                    FormViewTicket.Size = Option.ViewLocation.Size;
                }

                // 接続先一覧の更新
                UpdateConnectMenu();

                // ログイン
                Login();

                // Trac に接続されていればチケット自動更新タイマを稼働
                if ( Trac.IsConnected ) {
                    timerTicketUpdate.Start();
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// フォームがロードされたときに呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load( object sender, EventArgs e )
        {

        }

        /// <summary>
        /// チケット更新の開始
        /// </summary>
        public void StartUpdateTicket()
        {
            TicketUpdateThread = new Thread( UpdateTicket );
            TicketUpdateThread.Start();
        }

        /// <summary>
        /// チケット更新スレッド
        /// </summary>
        private void UpdateTicket()
        {
            try {
                // チケットの更新状況を確認し、更新されていたらアラートを出力
                int[] newIDs = Ticket.GetRecentChanges( Option.TicketUpdate.PrevUpdateTime );
                Trace.WriteLine( newIDs.Length + "  " + Option.TicketUpdate.PrevUpdateTime.ToUniversalTime().ToString() );
                Notifier.Invoke( TicketAlart, newIDs );

                // 今回の時間を次回に使う(Trac は UTC)
                Option.TicketUpdate.PrevUpdateTime = DateTime.UtcNow;

                // チケットを更新する
                int[] ticketIDs = Ticket.Query( Option.TicketUpdate.Query );
                List<Ticket> newTickets = new List<Ticket>( ticketIDs.Length );
                foreach ( int id in ticketIDs ) {
                    newTickets.Add( new Ticket( id ) );
                }

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

        /// <summary>
        /// チケットの状態が変わった時のアラート
        /// </summary>
        private void TicketUpdateAlart( int[] ChangedTicketIDs )
        {
            try {
                // タスクトレイの接続先情報
                string connect = "接続先：" + Option.SelectedAccount.ProjectName;
                TaskTrayMenu_ConnectSite.Text = connect;
                TaskTray.Text = connect + "\n" +
                            "全チケット数：" + Ticket.Query( "status!=closed" ).Length + "\n" +
                            "担当チケット数：" + Ticket.Query( "owner=$USER&status!=closed" ).Length + "\n" +
                            "関連チケット数：" + Ticket.Query( "cc=~$USER&status!=closed" ).Length;

                // 更新されたチケットがあればアラート
                if ( Option.TicketUpdate.EnableAlart && ( ChangedTicketIDs.Length != 0 ) ) {
                    Notifier.SetBackgroundBitmap( "Resources/trac_banner.bmp", Color.FromArgb( 255, 0, 255 ) );
                    Notifier.TitleRectangle = new Rectangle( new Point( 70, 10 ), new Size( 100, 30 ) );
                    Notifier.ContentRectangle = new Rectangle( new Point( 0, 10 ), new Size( 400, 70 ) );

                    Notifier.Show( Option.SelectedAccount.ProjectName,
                                ChangedTicketIDs.Length.ToString() + "件のチケットが更新されています",
                                300, Option.TicketUpdate.AlartTime * 1000, 300 );
                }
            }
            catch ( Exception ex ) {
                Trace.WriteLine( ex.Message );
            }
        }

        /// <summary>
        /// アラートをクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Notifier_ContentClick( object sender, EventArgs e )
        {
            try {
                Utility.ShowTracSite( "wiki/MyTickets" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <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 Login()
        {
            if ( Option.Selected != -1 ) {
                Trac.Connect( Option.SelectedAccount.Url,
                              Option.SelectedAccount.UserName,
                              Option.SelectedAccount.Password );

                // チケットの状態を更新
                StartUpdateTicket();

                // メニューを有効にする
                TaskTrayMenu_ChangeServer.Enabled = true;
                TaskTrayMenu_UpdateTicket.Enabled = true;
                TaskTrayMenu_CreateTicket.Enabled = true;
                TaskTrayMenu_ViewTicket.Enabled = true;
                TaskTrayMenu_MoveTrac.Enabled = true;

                // プロジェクトの変更
                TicketListView.ChangeProject( Option.SelectedAccount.ProjectName );
            }
        }

        /// <summary>
        /// 接続先メニューを追加
        /// </summary>
        public void UpdateConnectMenu()
        {
            // 接続先のサブメニューを作成
            TaskTrayMenu_ChangeServer.DropDownItems.Clear();
            foreach ( TracAccount ac in Option.AccountList ) {
                ToolStripMenuItem subMenu = new ToolStripMenuItem();
                subMenu.Text = ac.ProjectName;
                subMenu.Click += new EventHandler( subMenu_CheckedChanged );

                TaskTrayMenu_ChangeServer.DropDownItems.Add( subMenu );
            }

            // 接続メニューを無効にする
            TaskTrayMenu_ChangeServer.Enabled = false;
            TaskTrayMenu_UpdateTicket.Enabled = false;
            TaskTrayMenu_CreateTicket.Enabled = false;
            TaskTrayMenu_ViewTicket.Enabled = false;
            TaskTrayMenu_MoveTrac.Enabled = false;

            // 選択メニューをチェックする
            if ( TaskTrayMenu_ChangeServer.DropDownItems.Count != 0 ) {
                TaskTrayMenu_ChangeServer.Enabled = true;

                if ( Option.Selected != -1 ) {
                    TaskTrayMenu_UpdateTicket.Enabled = true;
                    TaskTrayMenu_CreateTicket.Enabled = true;
                    TaskTrayMenu_ViewTicket.Enabled = true;
                    TaskTrayMenu_MoveTrac.Enabled = true;

                    ToolStripMenuItem selectedMenu = TaskTrayMenu_ChangeServer.DropDownItems[Option.Selected] as ToolStripMenuItem;
                    if ( selectedMenu != null ) {
                        selectedMenu.Checked = true;
                    }
                }
            }
        }

        /// <summary>
        /// ショートカットキー検出ハンドラ
        /// </summary>
        private void ShortcutTicketCreateHandler()
        {
            // 有効の場合のみ処理する
            if (!Option.ShortcutTicketCreate.Enable)
            {
                return;
            }

            // チケット作成が無効の場合は処理しない
            if (!TaskTrayMenu_CreateTicket.Enabled)
            {
                return;
            }

            try
            {
                ShortcutTicketCreate.HookEnabled = false;
                IsMenuShown = true;

                FormTicket formTicket = new FormTicket(Option.SelectedAccount.ProjectName);
                DialogResult ret = formTicket.ShowDialog();
                if (ret == DialogResult.OK)
                {
                    StartUpdateTicket();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                IsMenuShown = false;
                ShortcutTicketCreate.HookEnabled = true;
            }
        }

        /// <summary>
        /// 閉じるボタン（キャンセルする）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosing( object sender, FormClosingEventArgs e )
        {
            try {
                // ×ボタンなどなら終了処理のキャンセルとフォームの非表示
                if ( !IsAppCloseed ) {
                    e.Cancel = true;
                    Visible = false;
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        #region タスクトレイ
        /// <summary>
        /// チケット一覧の表示
        /// </summary>
        private void ViewTicket()
        {
            try {
                // 表示されていなければ、モードレスダイアログとして表示
                if ( !FormViewTicket.Visible ) {
                    FormViewTicket.Show( Tickets, Option );
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// チェックの変更
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void subMenu_CheckedChanged( object sender, EventArgs e )
        {
            try {
                ToolStripMenuItem chekedItem = sender as ToolStripMenuItem;
                if ( chekedItem != null ) {
                    // チェック先が変わってログインできたら、再ログインして状態を変える
                    int newIndex = TaskTrayMenu_ChangeServer.DropDownItems.IndexOf( chekedItem );
                    if ( Option.Selected != newIndex ) {
                        bool isConnected = Trac.TryConnect( Option.AccountList[newIndex].Url,
                                                            Option.AccountList[newIndex].UserName,
                                                            Option.AccountList[newIndex].Password );
                        if ( !isConnected ) {
                            throw new Exception( "接続できませんでした。接続先を確認してください" );
                        }

                        // チェックを入れなおす
                        foreach ( ToolStripMenuItem item in TaskTrayMenu_ChangeServer.DropDownItems ) {
                            item.Checked = false;
                        }

                        chekedItem.Checked = true;
                        Option.Selected = newIndex;
                        Login();
                    }
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 終了メニュー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_Close_Click( object sender, EventArgs e )
        {
            try {
                // 表示サイズの更新してフォームを閉じる
                Option.ViewLocation.Location = FormViewTicket.Location;
                Option.ViewLocation.Size = FormViewTicket.Size;
                FormViewTicket.FormClose();

                // 設定の保存
                SettingSave();

                TaskTray.Visible = false;
                IsAppCloseed = true;
                Application.Exit();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 設定メニュー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_Edit_Click( object sender, EventArgs e )
        {
            try {
                ShortcutTicketCreate.HookEnabled = false;
                IsMenuShown = true;

                FormOption formOption = new FormOption( Option );
                DialogResult ret = formOption.ShowDialog();
                if ( ret == DialogResult.OK ) {
                    // 選択された接続先にログインする
                    Option = formOption.Option;
                    Login();

                    // コンテキストメニューの更新
                    UpdateConnectMenu();

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

                    // ショートカットキーの設定更新
                    ShortcutTicketCreate.Key = Option.ShortcutTicketCreate.Key;
                    ShortcutTicketCreate.KeyShift = Option.ShortcutTicketCreate.Shift;
                    ShortcutTicketCreate.KeyCtrl = Option.ShortcutTicketCreate.Ctrl;
                    ShortcutTicketCreate.KeyAlt = Option.ShortcutTicketCreate.Alt;

                    // 設定の保存
                    SettingSave();
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
            finally {
                IsMenuShown = false;
                ShortcutTicketCreate.HookEnabled = true;
            }
        }

        /// <summary>
        /// タスクトレイアイコンのダブルクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTray_DoubleClick( object sender, EventArgs e )
        {
            ViewTicket();
        }

        /// <summary>
        /// チケットの更新
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_UpdateTicket_Click( object sender, EventArgs e )
        {
            try {
                StartUpdateTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// チケットの作成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_CreateTicket_Click( object sender, EventArgs e )
        {
            try {
                ShortcutTicketCreate.HookEnabled = false;
                IsMenuShown = true;

                FormTicket formTicket = new FormTicket( Option.SelectedAccount.ProjectName );
                DialogResult ret = formTicket.ShowDialog();
                if ( ret == DialogResult.OK ) {
                    StartUpdateTicket();
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
            finally {
                IsMenuShown = false;
                ShortcutTicketCreate.HookEnabled = true;
            }
        }

        /// <summary>
        /// チケット一覧の表示
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_ViewTicket_Click( object sender, EventArgs e )
        {
            ViewTicket();
        }

        /// <summary>
        /// メニューを開いたとき
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_Opening( object sender, CancelEventArgs e )
        {
            if ( IsMenuShown || FormViewTicket.IsMenuShown ) {
                e.Cancel = true;
            }
        }

        /// <summary>
        /// トップページ
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_MoveTop_Click( object sender, EventArgs e )
        {
            try {
                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 TaskTrayMenu_MoveTimeline_Click( object sender, EventArgs e )
        {
            try {
                Utility.ShowTracSite( "timeline" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// ロードマップ
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_MoveRoadmap_Click( object sender, EventArgs e )
        {
            try {
                Utility.ShowTracSite( "roadmap" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// リポジトリブラウザ
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_MoveBrowser_Click( object sender, EventArgs e )
        {
            try {
                Utility.ShowTracSite( "browser" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// カレンダー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_MoveCalendar_Click( object sender, EventArgs e )
        {
            try {
                Utility.ShowTracSite( "ticketcalendar" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// ガントチャート
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_MoveGantt_Click( object sender, EventArgs e )
        {
            try {
                Utility.ShowTracSite( "ticketgantt" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 管理画面
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTrayMenu_MoveAdmin_Click( object sender, EventArgs e )
        {
            try {
                Utility.ShowTracSite( "admin" );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// タイマハンドラ
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timerTicketUpdate_Tick( object sender, EventArgs e )
        {
            try {
                StartUpdateTicket();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, AppName, MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }
        #endregion
    }
}
