using System;
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 CookComputing.XmlRpc;

namespace BTS.Trac.Forms
{
    using TicketType = TracNameAndValueField<ITicketType>;
    using Severity = TracNameAndValueField<ISeverity>;
    using Priority = TracNameAndValueField<IPriority>;

    /// <summary>
    /// チケットの作成/編集画面
    /// </summary>
    public partial class FormTicket : Form
    {
        /// <summary>
        /// チケットのフィールド
        /// </summary>
        XmlRpcStruct[] TicketFields = null;

        /// <summary>
        /// カスタムフィールド
        /// </summary>
        List<TicketCustomField> CustomField = new List<TicketCustomField>();

        /// <summary>
        /// 分類
        /// </summary>
        string[] AllTicketTypeNames = null;

        /// <summary>
        /// 優先度
        /// </summary>
        string[] AllPriorityNames = null;

        /// <summary>
        /// マイルストーン
        /// </summary>
        string[] AllMilestoneNames = null;

        /// <summary>
        /// コンポーネント
        /// </summary>
        string[] AllComponentNames = null;

        /// <summary>
        /// バージョン
        /// </summary>
        string[] AllVersionNames = BTS.Trac.Version.GetAll();

        /// <summary>
        /// 重要度
        /// </summary>
        string[] AllSeverityNames = Severity.GetAll();

        /// <summary>
        /// チケット
        /// </summary>
        public Ticket NewTicket
        {
            get;
            private set;
        }

        /// <summary>
        /// プロジェクト名称
        /// </summary>
        private string ProjectName;

        /// <summary>
        /// 作成/編集
        /// </summary>
        bool IsCreate = true;

        /// <summary>
        /// 更新履歴
        /// </summary>
        private List<TicketChangeLog> ChangeLogs = null;

        /// <summary>
        /// グループごとのコメント
        /// </summary>
        private Dictionary<int, string> Commnet = new Dictionary<int,string>();

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

            NewTicket = new Ticket();
            IsCreate = true;
            this.ProjectName = ProjectName;

            Text = this.ProjectName + " : チケットの作成";

            buttonCreate.Text = "作成(&S)";
            buttonCreateNext.Enabled = true;
            buttonCreateNext.Visible = true;
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="ticket">編集するチケット</param>
        public FormTicket( Ticket ticket, string ProjectName )
            : this( ProjectName )
        {
            NewTicket = ticket;
            IsCreate = false;

            Text = this.ProjectName + " : チケットの編集";

            buttonCreate.Text = "編集(&E)";
            buttonCreateNext.Enabled = false;
            buttonCreateNext.Visible = false;
        }

        private void FormTicket_Load( object sender, EventArgs e )
        {

        }

        #region 画面表示処理
        /// <summary>
        /// 表示初期化
        /// </summary>
        /// <param name="IsSetDefaultValue">選択をデフォルト値にするか（作成と編集で変える）</param>
        private void Initialize()
        {
            // カスタムフィールドの表示位置
            Point[] CaptionBase = new Point[2] { 
                    new Point( 4, 403 ),
                    new Point( 273, 403 ),
                };
            Point[] ValueBase = new Point[2] {
                    new Point( 105, 400 ),
                    new Point( 379, 400 ),
                };

            // 入力項目の初期化
            textBoxSummary.Text = "";
            textBoxDescription.Text = "";
            textBoxKeyword.Text = "";
            textBoxCC.Text = "";
            textBoxOwner.Text = "";

            // 報告者
            textBoxReporter.Text = Trac.UserName;

            // 分類
            comboBoxType.Items.Clear();
            comboBoxType.Items.Add( "" );
            foreach ( string name in AllTicketTypeNames ) {
                comboBoxType.Items.Add( name );
            }

            // 優先度
            comboBoxPriority.Items.Clear();
            comboBoxPriority.Items.Add( "" );
            foreach ( string name in AllPriorityNames ) {
                comboBoxPriority.Items.Add( name );
            }

            // マイルストーン
            comboBoxMilestone.Items.Clear();
            comboBoxMilestone.Items.Add( "" );
            foreach ( string name in AllMilestoneNames ) {
                comboBoxMilestone.Items.Add( name );
            }

            // コンポーネント
            comboBoxComponent.Items.Clear();
            comboBoxComponent.Items.Add( "" );
            foreach ( string name in AllComponentNames ) {
                comboBoxComponent.Items.Add( name );
            }

            // バージョン
            comboBoxVersion.Items.Clear();
            comboBoxVersion.Items.Add( "" );
            foreach ( string name in AllVersionNames ) {
                comboBoxVersion.Items.Add( name );
            }

            // 重要度
            comboBoxSeverity.Items.Clear();
            comboBoxSeverity.Items.Add( "" );
            foreach ( string name in AllSeverityNames ) {
                comboBoxSeverity.Items.Add( name );
            }

            // デフォルト値の設定
            foreach ( XmlRpcStruct field in TicketFields ) {
                string fieldName = field["name"].ToString();
                if ( fieldName == "type" ) {
                    SetDefaultValue( field, ref comboBoxType );
                }
                else if ( fieldName == "milestone" ) {
                    SetDefaultValue( field, ref comboBoxMilestone );
                }
                else if ( fieldName == "component" ) {
                    SetDefaultValue( field, ref comboBoxComponent );
                    // コンポーネントに関連連れられている担当者を設定
                    SetOwner( field["value"].ToString() );
                }
                else if ( fieldName == "version" ) {
                    SetDefaultValue( field, ref comboBoxVersion );
                }
                else if ( fieldName == "severity" ) {
                    SetDefaultValue( field, ref comboBoxSeverity );
                }
                else if ( fieldName == "priority" ) {
                    SetDefaultValue( field, ref comboBoxPriority );
                }

                // カスタムフィールドの作成
                if ( field.Contains( "custom" ) ) {
                    int controlWidth = 25;
                    int columun =  (CustomField.Count & 1) == 0 ? 0 : 1;
                    int raw = (CustomField.Count / 2) * controlWidth;

                    // カスタムフィールドの作成
                    XmlRpcAttributes attributes = new XmlRpcAttributes( field );
                    TicketCustomField customField = new TicketCustomField( attributes );
                    CustomField.Add( customField );

                    customField.Caption.Location = new Point( CaptionBase[columun].X, CaptionBase[columun].Y + raw );
                    customField.ValueControl.Location = new Point( ValueBase[columun].X, ValueBase[columun].Y + raw );

                    // コントロールを登録
                    tabPageTicketBaseInfo.Controls.Add( customField.Caption );
                    tabPageTicketBaseInfo.Controls.Add( customField.ValueControl );

                    // コントロールを登録したらフォームたちを下に伸ばす
                    if ( columun == 0 ) {
                        // フォームを下に伸ばす
                        Height += controlWidth;

                        // タブを下に伸ばす
                        tabControlTicketInformation.Height +=  controlWidth;

                        // ボタンを下にずらす
                        buttonCreateNext.Top += controlWidth;
                        buttonCreate.Top += controlWidth;
                        buttonCancel.Top += controlWidth;
                    }
                }
            }
        }

        /// <summary>
        /// 更新するチケット情報を設定
        /// </summary>
        private void UpdateEditTicket()
        {
            Text = this.ProjectName + " : チケットの編集 : #" + NewTicket.ID.ToString() + " (" + NewTicket.Summary + ")";

            // コンボボックスの選択項目
            if ( !string.IsNullOrEmpty( NewTicket.Type ) ) {
                int index = comboBoxType.Items.IndexOf( NewTicket.Type );
                if ( index != -1 ) {
                    comboBoxType.SelectedIndex = index;
                }
            }

            if ( !string.IsNullOrEmpty( NewTicket.Milestone ) ) {
                int index = comboBoxMilestone.Items.IndexOf( NewTicket.Milestone );
                if( index != -1 ) {
                    comboBoxMilestone.SelectedIndex = index;
                }
            }

            if ( !string.IsNullOrEmpty( NewTicket.Component ) ) {
                int index = comboBoxComponent.Items.IndexOf( NewTicket.Component );
                if ( index != -1 ) {
                    comboBoxComponent.SelectedIndex = index;
                }
            }

            if ( !string.IsNullOrEmpty( NewTicket.Version ) ) {
                int index = comboBoxVersion.Items.IndexOf( NewTicket.Version );
                if ( index != -1 ) {
                    comboBoxVersion.SelectedIndex = index;
                }
            }

            if ( !string.IsNullOrEmpty( NewTicket.Priority ) ) {
                int index = comboBoxPriority.Items.IndexOf( NewTicket.Priority );
                if ( index != -1 ) {
                    comboBoxPriority.SelectedIndex = index;
                }
            }

            // 入力項目の設定
            textBoxSummary.Text = NewTicket.Summary;
            textBoxDescription.Text = NewTicket.Description.Replace( "\n", "\r\n" );
            textBoxKeyword.Text = NewTicket.Keywords;
            textBoxCC.Text = NewTicket.Cc;
            textBoxReporter.Text = NewTicket.Reporter;
            textBoxOwner.Text = NewTicket.Owner;

            // カスタムフィールドに値を反映
            foreach ( TicketCustomField field in CustomField ) {
                string value = NewTicket.GetField<string>( field.Name );
                if ( !string.IsNullOrEmpty( value ) ) {
                    field.Value = value;
                }
            }
        }

        /// <summary>
        /// 更新履歴の表示
        /// </summary>
        private void UpdateChangeLog()
        {
            // 作成＆更新日時を表示
            labelCreateDate.Text = NewTicket.CreateTime.ToString();
            labelLastModify.Text = NewTicket.ModifiedTime.ToString();

            // チェンジログを表示
            foreach ( TicketChangeLog log in ChangeLogs ) {
                ListViewGroup group = new ListViewGroup( log.Modified.ToString() );
                // グループに登録されていなければ登録する
                int groupIndex = 0;
                for ( groupIndex = 0; groupIndex < listViewChangeLog.Groups.Count; ++groupIndex ) {
                    if ( listViewChangeLog.Groups[groupIndex].Header == group.Header ) {
                        break;
                    }
                }
                if ( groupIndex == listViewChangeLog.Groups.Count ) {
                    groupIndex = listViewChangeLog.Groups.Add( group );
                }

                // コメントを保存
                if ( log.Name == "comment" ) {
                    Commnet.Add( groupIndex, log.After );
                }
                // ほかはアイテムとして表示
                else {
                    // アイテムを登録
                    ListViewItem item = new ListViewItem( log.Name );
                    item.SubItems.Add( log.Before );
                    item.SubItems.Add( log.After );
                    item.Group = listViewChangeLog.Groups[groupIndex];

                    listViewChangeLog.Items.Add( item );
                }
            }

            // 更新がコメントだけの場合はコメントだけという文言を追加しておく
            // でないと、グループが表示されない
            foreach ( ListViewGroup group in listViewChangeLog.Groups ) {
                if ( group.Items.Count == 0 ) {
                    ListViewItem item = new ListViewItem( "コメントのみ" );
                    item.Group = group;

                    listViewChangeLog.Items.Add( item );
                }
            }
        }
        #endregion 

        /// <summary>
        /// チケットの作成
        /// </summary>
        private void CreateTicket()
        {
            string summary = textBoxSummary.Text;
            if ( string.IsNullOrEmpty( summary ) ) {
                throw new Exception( "概要を入力してください" );
            }

            // チケットの作成
            if ( NewTicket == null ) {
                NewTicket = new Ticket();
            }

            NewTicket.Summary = summary;
            NewTicket.Description = textBoxDescription.Text.Replace( "\r\n", "\n" );
            NewTicket.Reporter = textBoxReporter.Text;
            NewTicket.Owner = textBoxOwner.Text;

            NewTicket.Type = comboBoxType.Text;
            NewTicket.Priority = comboBoxPriority.Text;
            NewTicket.Milestone = comboBoxMilestone.Text;
            NewTicket.Component = comboBoxComponent.Text;
            NewTicket.Version = comboBoxVersion.Text;
            // 重要度がない

            NewTicket.Keywords = textBoxKeyword.Text;
            NewTicket.Cc = textBoxCC.Text;

            // カスタムフィールドの登録
            foreach ( TicketCustomField field in CustomField ) {
                NewTicket.SetCustomField( field.Name, field.Value );
            }

            if ( IsCreate ) {
                NewTicket.Create();

                MessageBox.Show( "チケットが作成されました\nID : " + NewTicket.ID, "チケットの作成", MessageBoxButtons.OK, MessageBoxIcon.Information );
            }
            else {
                NewTicket.Update( "Update from TaskTrayTrac" );

                MessageBox.Show( "チケットが更新されました\nID : " + NewTicket.ID, "チケットの更新", MessageBoxButtons.OK, MessageBoxIcon.Information );
            }
        }

        #region ボタン押下処理
        /// <summary>
        /// 作成ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonCreate_Click( object sender, EventArgs e )
        {
            try {
                CreateTicket();

                DialogResult = DialogResult.OK;
                Close();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, "チケット作成/編集", MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 作成して次へボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonCreateNext_Click( object sender, EventArgs e )
        {
            try {
                CreateTicket();
                Initialize();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, "チケット作成/編集", MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// キャンセルボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonCancel_Click( object sender, EventArgs e )
        {

        }
        #endregion

        #region コンボボックス系の処理
        /// <summary>
        /// コンボボックスの選択が変わったら呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBoxComponent_SelectedIndexChanged( object sender, EventArgs e )
        {
            SetOwner( comboBoxComponent.SelectedItem.ToString() );
        }

        /// <summary>
        /// デフォルト値をコンボボックスに設定
        /// </summary>
        /// <param name="field"></param>
        /// <param name="combo"></param>
        private void SetDefaultValue( XmlRpcStruct field, ref ComboBox combo )
        {
            string value = field["value"].ToString();
            if ( !string.IsNullOrEmpty( value ) ) {
                combo.SelectedIndex = combo.Items.IndexOf( value );
            }
        }

        /// <summary>
        /// コンポーネントに関連付けられている担当者を設定
        /// </summary>
        /// <param name="componentName"></param>
        private void SetOwner( string componentName )
        {
            if ( !string.IsNullOrEmpty( componentName ) ) {
                BTS.Trac.Component defaultComponent = new BTS.Trac.Component( componentName );
                textBoxOwner.Text = defaultComponent.Owner;
            }
        }
        #endregion

        /// <summary>
        /// 説明のタブが切り替わった
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tabControlDiscription_SelectedIndexChanged( object sender, EventArgs e )
        {
            try {
                TabControl tab = sender as TabControl;
                if ( (tab != null) && (tab.SelectedIndex == 1) ) {
                    string text = textBoxDescription.Text;
                    webBrowserPreview.DocumentText = Wiki.WikiToHtml( text.Replace( "\r\n", "\n" ) );
                }
            }
            finally {
            }
        }

        #region チケット情報の更新処理
        /// <summary>
        /// 表示直前で呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormTicket_Shown( object sender, EventArgs e )
        {
            // 作成の場合は更新履歴は表示しない
            if ( IsCreate ) {
                tabControlTicketInformation.Controls.Remove( tabPageTicketModifyInfo );
            }

            // 表示無効
            Enabled = false;

            // 表示処理を開始する
            backgroundWorker.RunWorkerAsync();
        }

        /// <summary>
        /// スレッド処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_DoWork( object sender, DoWorkEventArgs e )
        {
            try {
                // チケットフィールドの更新
                TicketFields = Ticket.GetTicketFields();
                AllTicketTypeNames = TicketType.GetAll();
                AllPriorityNames = Priority.GetAll();
                AllMilestoneNames = Milestone.GetAll();
                AllComponentNames = BTS.Trac.Component.GetAll();
                AllVersionNames = BTS.Trac.Version.GetAll();
                AllSeverityNames = Severity.GetAll();

                // 編集の場合は更新履歴を取得
                if ( !IsCreate ) {
                    ChangeLogs = NewTicket.ChangeLog();
                }
            }
            catch {
            }
        }

        /// <summary>
        /// スレッド処理の終了
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e )
        {
            try {
                // 表示の初期化
                Initialize();

                // 更新
                if ( !IsCreate ) {
                    UpdateEditTicket();
                    UpdateChangeLog();
                }
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, "チケット作成/編集", MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
            finally {
                Enabled = true;
            }
        }
        #endregion

        /// <summary>
        /// 選択が変わった
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listViewChangeLog_SelectedIndexChanged( object sender, EventArgs e )
        {
            // 選択されたアイテムのグループ（日付）のコメントを表示する
            if ( listViewChangeLog.SelectedItems.Count != 0 ) {
                int groupIndex = listViewChangeLog.Groups.IndexOf( listViewChangeLog.SelectedItems[0].Group );
                if ( groupIndex != -1 ) {
                    textBoxComment.Text = Commnet[groupIndex].Replace( "\n", "\r\n" );
                }
            }
        }
    }
}
