using System;
using System.Windows.Forms;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using MSProject = Microsoft.Office.Interop.MSProject;
using Office = Microsoft.Office.Core;
using CookComputing.XmlRpc;
using TracProxy;

namespace ProjectTracAddIn
{
    public partial class ThisAddIn
    {
        private const string commandBarName = "ProjectTracTicketImpot";

        private Office.CommandBarButton btnDownload = null;
        private Office.CommandBarButton btnUpload = null;
        private Office.CommandBar menubar = null;

        TracProxy.TicketManager trac = null;
        private string url = null;

        private void ThisAddIn_Startup( object sender, System.EventArgs e )
        {
            try {
                // メニューバーを追加
                menubar = Application.CommandBars.Add( commandBarName, missing, missing, true );
                menubar.Visible = true;

                // コマンドバーを上部にドッキングさせる
                Application.CommandBars[commandBarName].Position = Microsoft.Office.Core.MsoBarPosition.msoBarTop;

                // ダウンロードボタン
                btnDownload = (Office.CommandBarButton)menubar.Controls.Add( 1, missing, missing, missing, missing );
                btnDownload.Style = Office.MsoButtonStyle.msoButtonIcon;
                btnDownload.FaceId = 1;
                btnDownload.Tag = "1";
                btnDownload.Picture = ImageConverter.ImageConverter.getImage( Properties.Resources.download );
                btnDownload.TooltipText = "チケットの一覧を Trac から取得";
                btnDownload.Click += new Office._CommandBarButtonEvents_ClickEventHandler( CommandBarButton_DownloadClick );

                // アップロードボタン
                btnUpload = (Office.CommandBarButton)menubar.Controls.Add( 1, missing, missing, missing, missing );
                btnUpload.Style = Office.MsoButtonStyle.msoButtonIcon;
                btnUpload.FaceId = 2;
                btnUpload.Tag = "2";
                btnUpload.Picture = ImageConverter.ImageConverter.getImage( Properties.Resources.upload );
                btnUpload.TooltipText = "変更されたデータを Trac へ送信";
                btnUpload.Click += new Office._CommandBarButtonEvents_ClickEventHandler( CommandBarButton_UploadClick );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message );
            }
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }

        #region VSTO で生成されたコード

        /// <summary>
        /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディタで変更しないでください。
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }
        
        #endregion

        private bool Login()
        {
            if ( trac == null ) {
                // サーバ情報の取得
                LoginInformation logicInfo = new LoginInformation();
                logicInfo.StartPosition = FormStartPosition.CenterParent;
                DialogResult ret = logicInfo.ShowDialog( null );
                if ( ret != DialogResult.OK ) {
                    return false;
                }

                // URL の取得。終端に'/' が入っていなければ付加する
                url = logicInfo.ServerURL;
                if ( url[url.Length - 1] != '/' ) {
                    url += "/";
                }

                // Trac へのアクセス I/F を作成
                trac = new TracProxy.TicketManager();
                //trac.Connect( "http://localhost/trac/SampleProject/login/xmlrpc", "admin", "admin" );
                trac.Connect( url + "login/xmlrpc", logicInfo.UserName, logicInfo.Password );
            }

            return true;
        }

        // タスクの作成
        private void CreateTasks( string query, short baseOutline )
        {
            MSProject.Project pj = Application.ActiveProject;
            TracProxy.ITicket ticket = trac.Ticket;
            int[] tikets = ticket.Query( query );
            foreach ( int i in tikets ) {
                try {
                    // チケットの詳細を取得して表示
                    object[] ret = ticket.GetTicket( i );
                    XmlRpcStruct attributes = (XmlRpcStruct)ret[3];

                    // タスクを作成し、要素を設定
                    MSProject.Task newTask = pj.Tasks.Add( attributes[TicketAttributes.Summary], missing );
                    newTask.ResourceNames = (string)attributes[TicketAttributes.Owner];

                    try {
                        // 開始/終了は設定されていないと今日の日付になる
                        //  開始日/終了日がない場合のために例外を握りつぶす
                        newTask.Start  = attributes[TicketAttributes.DueAssign];
                        newTask.Finish = attributes[TicketAttributes.DueClose];
                    }
                    catch ( Exception ) {
                    }

                    // 詳細はメモに入れておく
                    newTask.Notes = (string)attributes[TicketAttributes.Description];

                    // 進捗率が設定されていないと例外が出るので、ここだけ囲っとく
                    try {
                        newTask.PercentComplete = int.Parse( (string)attributes[TicketAttributes.Complete] );
                    }
                    catch ( Exception ) {
                    }

                    // アウトラインレベル
                    newTask.OutlineLevel = baseOutline;

                    // 期間固定とする
                    newTask.Type = MSProject.PjTaskFixedType.pjFixedDuration;

                    // ハイパーリンクを設定(チケット番号をリンクの表示に隠しておく)
                    newTask.HyperlinkHREF = url + "/ticket/" + ret[0].ToString();
                    newTask.Hyperlink = ret[0].ToString();

                    // ?がつくので期間を見積もりではなくする
                    newTask.Estimated = false;
                }
                catch ( Exception ex ) {
                    MessageBox.Show( ex.Message );
                }
            }
        }

        // チケットのダウンロード
        private void DownloadTicket()
        {
            // 新しいプロジェクトを作成
            Application.FileNew( missing, missing, missing, missing );
            MSProject.Project pj = Application.ActiveProject;

            string statusQuery = "status!=closed";

            TracProxy.ITicket ticket = trac.Ticket;
            string[] milestoneNames = ticket.GetAllMilestones();
            foreach ( string milestoneName in milestoneNames ) {
                // マイルストーンの作成
                MSProject.Task milestone = pj.Tasks.Add( milestoneName, missing );
                milestone.Milestone = true;
                milestone.OutlineLevel = 1;

                // クエリを作成し、その一覧を取得
                CreateTasks( statusQuery + "&milestone=" + milestoneName, 2 );
            }

            // マイルストーンに関連付けられていないチケットを取得
            CreateTasks( statusQuery + "&milestone=", 1 );
        }

        // ダウンロードボタン
        void CommandBarButton_DownloadClick( Office.CommandBarButton Ctrl, ref bool CancelDefault )
        {
            try {
                //// サーバに接続
                bool ret = Login();
                if ( !ret ) {
                    return;
                }

                // 新規プロジェクトを作成し、タスクを登録
                DownloadTicket();

                // Trac へのアップロードを可能にする
                btnUpload.Enabled = true;
            }
            catch ( Exception ex ) {
                trac = null;
                MessageBox.Show( ex.Message );
            }
        }

        // 更新されたかチェックしながらチケットを変更
        bool ValidateChage( ref XmlRpcStruct attributes, MSProject.Task task )
        {
            bool isChange = false;

            if ( (string)attributes[TicketAttributes.Summary] != task.Name ) {
                attributes[TicketAttributes.Summary] = task.Name;
                isChange = true;
            }

            if ( (string)attributes[TicketAttributes.Owner] != task.ResourceNames ) {
                attributes[TicketAttributes.Owner] = task.ResourceNames;
                isChange = true;
            }

            if ( (string)attributes[TicketAttributes.DueAssign] != ((DateTime)task.Start).ToString( "d", null ) ) {
                attributes[TicketAttributes.DueAssign] = ((DateTime)task.Start).ToString( "d", null );
                isChange = true;
            }

            if ( (string)attributes[TicketAttributes.DueClose] != ((DateTime)task.Finish).ToString( "d", null ) ) {
                attributes[TicketAttributes.DueClose] = ((DateTime)task.Finish).ToString( "d", null );
                isChange = true;
            }

            if ( (string)attributes[TicketAttributes.Description] != task.Notes ) {
                attributes[TicketAttributes.Description] = task.Notes;
                isChange = true;
            }

            if ( (string)attributes[TicketAttributes.Complete] != task.PercentComplete.ToString() ) {
                attributes[TicketAttributes.Complete] = task.PercentComplete.ToString();
                isChange = true;
            }

            return isChange;
        }

        void UpdateTikcet()
        {
            MSProject.Project pj = Application.ActiveProject;
            TracProxy.ITicket ticket = trac.Ticket;
            MSProject.Tasks tasks = pj.Tasks;

            ProgressDlg progress = new ProgressDlg();
            progress.Minimum = 0;
            progress.Maximum = tasks.Count;
            progress.Show();

            try {
                foreach ( MSProject.Task task in tasks ) {
                    progress.Value = progress.Value + 1;

                    int ticketNo = 0;

                    // リンクの表示に隠しておいたチケット番号を取得（ない場合はエラーで次へ）
                    try {
                        ticketNo = int.Parse( task.Hyperlink );
                    }
                    catch ( Exception ) {
                        continue;
                    }

                    object[] ret = ticket.GetTicket( ticketNo );
                    XmlRpcStruct attributes = (XmlRpcStruct)ret[3];

                    // チケットを更新
                    if ( ValidateChage( ref attributes, task ) ) {
                        ticket.Update( ticketNo, "MS-Project update", attributes );
                    }
                }
            }
            catch ( Exception ) {
                progress.Close();
                throw;
            }

            progress.Close();
        }

        void CommandBarButton_UploadClick( Office.CommandBarButton Ctrl, ref bool CancelDefault )
        {
            try {
                // サーバに接続
                bool ret = Login();
                if ( !ret ) {
                    return;
                }

                // チケットの更新
                UpdateTikcet();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message );
            }
        }
    }
}
