using System;
using System.Xml;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using BTS.Trac;
using BlowfishNET;

namespace BTS.Trac.Forms
{
    /// <summary>
    /// ログイン情報画面
    /// </summary>
    public partial class FormTracLogin : Form
    {
        /// <summary>
        /// 入力されたアカウント情報
        /// </summary>
        public TracAccount Account
        {
            get;
            private set;
        }

        /// <summary>
        /// デフォルトコンストラクタ
        /// </summary>
        public FormTracLogin()
        {
            InitializeComponent();

            Account = null;
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="Account">初期表示アカウント</param>
        public FormTracLogin( TracAccount Account )
            : this()
        {
            serverUrl.Text = Account.Url;
            userName.Text = Account.UserName;
            password.Text = Account.Password;
            textBoxProjectName.Text = Account.ProjectName;
        }

        /// <summary>
        /// 接続テスト
        /// </summary>
        private void TryConnect()
        {
            bool ret = Trac.TryConnect( serverUrl.Text, userName.Text, password.Text );
            if ( !ret ) {
                throw new Exception( "接続できませんでした。設定を確認してください" );
            }
        }

        /// <summary>
        /// OKボタン処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonOK_Click( object sender, EventArgs e )
        {
            try {
                Close();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, "アカウント設定", MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// キャンセルボタン処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click( object sender, EventArgs e )
        {
            try {
                Close();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, "アカウント設定", MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// 接続テスト
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonConnectTest_Click( object sender, EventArgs e )
        {
            try {
                TryConnect();
                MessageBox.Show( "接続できました", "接続テスト", MessageBoxButtons.OK, MessageBoxIcon.Information );
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message, "接続テスト", MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
        }

        /// <summary>
        /// フォームが閉じる瞬間に呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormTracLogin_FormClosing( object sender, FormClosingEventArgs e )
        {
            // OKボタンでの終了処理中
            if ( DialogResult == DialogResult.OK ) {
                try {
                    if ( string.IsNullOrEmpty( textBoxProjectName.Text ) ) {
                        throw new Exception( "プロジェクト名を入力してください" );
                    }

                    TryConnect();
                    // 接続できたらインスタンスを生成
                    Account = new TracAccount( serverUrl.Text, userName.Text, password.Text, textBoxProjectName.Text );
                }
                catch ( Exception ex ) {
                    // 接続できなければキャンセルする
                    e.Cancel = true;

                    MessageBox.Show( ex.Message, "接続テスト", MessageBoxButtons.OK, MessageBoxIcon.Error );
                }
            }
        }
    }

    /// <summary>
    /// アカウント情報
    /// </summary>
    public class TracAccount
    {
        /// <summary>
        /// URL
        /// </summary>
        public string Url;

        /// <summary>
        /// ユーザ名
        /// </summary>
        public string UserName;

        /// <summary>
        /// パスワード
        /// </summary>
        public string Password;

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

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="Url"></param>
        /// <param name="UserName"></param>
        /// <param name="Password"></param>
        public TracAccount( string Url, string UserName, string Password, string ProjectName )
        {
            this.Url = Url;
            this.UserName = UserName;
            this.Password = Password;
            this.ProjectName = ProjectName;
        }
    }

    /// <summary>
    /// Trac アカウントリスト管理
    /// </summary>
    public class TracAccountList : IEnumerable
    {
        class XML_TAG
        {
            public const string ROOT = "root";

            public const string ACCOUNT_LIST = "accountlist";
            public const string ACCOUNT = "account";
            public const string URL = "url";
            public const string USER_NAME = "username";
            public const string PASSWORD = "password";
            public const string PROJECT_NAME = "project_name";
        }

        /// <summary>
        /// アカウントリスト
        /// </summary>
        private List<TracAccount> AccountList = new List<TracAccount>();

        /// <summary>
        /// リストの数を取得
        /// </summary>
        public int Count
        {
            get
            {
                return AccountList.Count;
            }
        }

        /// <summary>
        /// インデクサ
        /// </summary>
        /// <param name="index">インデックス</param>
        /// <returns>アカウント</returns>
        public TracAccount this[int index]
        {
            get
            {
                return AccountList[index];
            }

            set
            {
                AccountList[index] = value;
            }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public TracAccountList()
        {
        }

        /// <summary>
        /// 反復子の取得
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator()
        {
            return AccountList.GetEnumerator();
        }

        /// <summary>
        /// アカウントの追加
        /// </summary>
        /// <param name="Account">追加するアカウント</param>
        public void Add( TracAccount Account )
        {
            AccountList.Add( Account );
        }

        /// <summary>
        /// アカウントのクリア
        /// </summary>
        public void Clear()
        {
            AccountList.Clear();
        }

        /// <summary>
        /// アカウントの削除
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAt( int index )
        {
            AccountList.RemoveAt( index );
        }

        /// <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 accountList = XmlHelper.AppendChild( xml, root, XML_TAG.ACCOUNT_LIST );

            // アカウント情報の保存
            foreach ( TracAccount ac in AccountList ) {
                XmlNode account = XmlHelper.AppendChild( xml, accountList, XML_TAG.ACCOUNT );
                XmlHelper.AppendChild( xml, account, XML_TAG.URL, ac.Url );
                XmlHelper.AppendChild( xml, account, XML_TAG.USER_NAME, ac.UserName );
                XmlHelper.AppendChild( xml, account, XML_TAG.PROJECT_NAME, ac.ProjectName );

                BlowfishSimple blf = new BlowfishSimple( ac.Url );
                XmlHelper.AppendChild( xml, account, XML_TAG.PASSWORD, blf.Encrypt( ac.Password ) );
            }

            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 );

            // アカウント情報の復元
            AccountList.Clear();
            XmlNodeList Accounts = xml.SelectNodes( "//" + XML_TAG.ACCOUNT );
            foreach ( XmlNode node in Accounts ) {
                string url = node.SelectNodes( "./" + XML_TAG.URL )[0].InnerText;
                string user = node.SelectNodes( "./" + XML_TAG.USER_NAME )[0].InnerText;
                string projectName = node.SelectNodes( "./" + XML_TAG.PROJECT_NAME )[0].InnerText;

                BlowfishSimple blf = new BlowfishSimple( url );
                string pass = blf.Decrypt( node.SelectNodes( "./" + XML_TAG.PASSWORD )[0].InnerText );

                AccountList.Add( new TracAccount( url, user, pass, projectName ) );
            }
        }
    }
}
