using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using BlowfishNET;
using Office = Microsoft.Office.Core;

namespace ExcelTracAddIn
{
    /// <summary>
    /// アドインのオプション
    /// </summary>
    public class ExcelTracAddInOption
    {
        class XML_TAG
        {
            public const string ROOT = "root";

            public const string MENUBAR = "menubar";
            public const string TOP = "top";
            public const string LEFT = "left";
            public const string VISIBLE = "visible";
            public const string POSITION = "position";
            public const string ROWINDEX = "rowindex";

            public const string ACCOUNT_LIST = "accountlist";
            public const string SELECT = "select";
            public const string ACCOUNT = "account";
            public const string URL = "url";
            public const string USER_NAME = "username";
            public const string PASSWORD = "password";

            public const string UPLOAD_VRIFY = "uploadverify";
        }

        /// <summary>
        /// アカウント情報
        /// </summary>
        public class Account
        {
            public string Url;
            public string UserName;
            public string Password;

            public Account( string Url, string UserName, string Password )
            {
                this.Url = Url;
                this.UserName = UserName;
                this.Password = Password;
            }
        }

        /// <summary>
        /// アカウント情報リスト
        /// </summary>
        public List<Account> AccountList
        {
            get;
            set;
        }

        /// <summary>
        /// 選択されたアカウント情報
        /// </summary>
        public Account SelectedAccount
        {
            get
            {
                return AccountList[Selected];
            }
        }

        /// <summary>
        /// アカウントの選択インデックス
        /// </summary>
        public int Selected
        {
            get;
            set;
        }

        /// <summary>
        /// アップロードの際の更新画面表示
        /// </summary>
        public bool UploadVerify
        {
            get;
            set;
        }

        /// <summary>
        /// デフォルトコンストラクタ
        /// </summary>
        public ExcelTracAddInOption()
        {
            Selected = -1;
            AccountList = new List<Account>();

            UploadVerify = true;
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="path">保存ファイルパス</param>
        public ExcelTracAddInOption( string path, ref Office.CommandBar menubar )
            : this()
        {
            Load( path, ref menubar );
        }

        /// <summary>
        /// 子要素の作成
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="parent"></param>
        /// <param name="tag"></param>
        /// <returns></returns>
        private XmlNode AppendChild( XmlDocument xml, XmlNode parent, string tag )
        {
            return parent.AppendChild( xml.CreateElement( tag ) );
        }

        /// <summary>
        /// 子要素の作成
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="parent"></param>
        /// <param name="tag"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        private XmlNode AppendChild( XmlDocument xml, XmlNode parent, string tag, string text )
        {
            XmlNode child = xml.CreateElement( tag );
            child.AppendChild( xml.CreateTextNode( text ) );
            parent.AppendChild( child );

            return child;
        }

        /// <summary>
        /// オプションの保存
        /// </summary>
        /// <param name="path">保存パス</param>
        public void Save( string path, Office.CommandBar menubar )
        {
            // XML として保存
            XmlDocument xml = new XmlDocument();
            xml.AppendChild( xml.CreateXmlDeclaration( "1.0", "utf-8", null ) );

            XmlNode root = xml.CreateElement( XML_TAG.ROOT );

            // メニュー項目の保存
            XmlNode menu = AppendChild( xml, root, XML_TAG.MENUBAR );
            AppendChild( xml, menu, XML_TAG.TOP, menubar.Top.ToString() );
            AppendChild( xml, menu, XML_TAG.LEFT, menubar.Left.ToString() );
            AppendChild( xml, menu, XML_TAG.VISIBLE, menubar.Visible.ToString() );
            AppendChild( xml, menu, XML_TAG.POSITION, ((int)menubar.Position).ToString() );
            AppendChild( xml, menu, XML_TAG.ROWINDEX, menubar.RowIndex.ToString() );


            // アカウントリストと、選択番号の保存
            XmlNode accountList = AppendChild( xml, root, XML_TAG.ACCOUNT_LIST );
            AppendChild( xml, accountList, XML_TAG.SELECT, Selected.ToString() );

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

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

            // 各種設定の保存
            AppendChild( xml, root, XML_TAG.UPLOAD_VRIFY, UploadVerify.ToString() );

            xml.AppendChild( root );

            // 保存
            xml.Save( path );
        }

        /// <summary>
        /// オプションの復元
        /// </summary>
        /// <param name="path">復元パス</param>
        public void Load( string path, ref Office.CommandBar menubar )
        {
            // XML から復元
            XmlDocument xml = new XmlDocument();
            xml.Load( path );

            // 選択番号の復元
            Selected = -1;
            Selected = int.Parse( xml.SelectNodes( "//" + XML_TAG.SELECT )[0].InnerText );

            // メニューの復元
            try {
                menubar.Top = int.Parse( xml.SelectNodes( "//" + XML_TAG.TOP )[0].InnerText );
                menubar.Left = int.Parse( xml.SelectNodes( "//" + XML_TAG.LEFT )[0].InnerText );
                menubar.Visible = bool.Parse( xml.SelectNodes( "//" + XML_TAG.VISIBLE )[0].InnerText );
                menubar.Position = (Office.MsoBarPosition)int.Parse( xml.SelectNodes( "//" + XML_TAG.POSITION )[0].InnerText );
                menubar.RowIndex = int.Parse( xml.SelectNodes( "//" + XML_TAG.ROWINDEX )[0].InnerText );
            }
            catch {
                // エラーの時はデフォルト値を設定
                menubar.Visible = true;
                menubar.Position = Microsoft.Office.Core.MsoBarPosition.msoBarTop;
            }

            // アカウント情報の復元
            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;

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

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

            // 各種設定の復元
            UploadVerify = bool.Parse( xml.SelectNodes( "//" + XML_TAG.UPLOAD_VRIFY )[0].InnerText );
        }
    }
}
