using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Hitsuji.Framework.DataClient.Model;
using Hitsuji.Framework.Thread;
using Hitsuji.Framework.Utils;
using PostCardHitsuji.DataClient.DAO;
using PostCardHitsuji.DataClient.Model;
using PostCardHitsuji.Global;
using PostCardHitsuji.Ui.RowPanel;

namespace PostCardHitsuji.Ui.Controls
{
    public partial class NewAddressUserControl : UserControl
    {
        public NewAddressUserControl()
        {
            InitializeComponent();
            searchPanel1.Label1 = "〒番号";
            searchPanel1.Label2 = "住所";
            searchPanel1.Label3 = "";
            searchPanel1.Label4 = "";

            this.Load += new EventHandler(load);
        }

        private void load(object sender, EventArgs ev)
        {
            //検索パネル
            searchPanel1.SearchTextChangedEvent += new EventHandler(setRowPanelVisiblity);
            searchPanel1.ButtonRefreshClickedEvent += new EventHandler(refreshRowPanelInfos);
            
            //データ検索
            var parameter = new AddressContentModel();
            parameter.Enable = "";
            var paramHash2 = new System.Collections.Hashtable();
            paramHash2.Add("param", parameter);
            paramHash2.Add("callback", new Action<object>(callback_Search));
            ThreadRunner.doProcess(paramHash2, doSearch, "address_search", true);
        }

        /// <summary>
        /// 一覧の各パネルの表示/非表示切り替え
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ev"></param>
        private void setRowPanelVisiblity(object sender, EventArgs ev)
        {
            var textPostal = searchPanel1.Text1;
            var textAddress = searchPanel1.Text2;
            foreach (var ctrl in flowLayoutPanel1.Controls)
            {
                if (ctrl as InfoRowPanel2 == null) continue;

                var row = ctrl as InfoRowPanel2;
                var model = row.Model as AddressContentModel;
                var isVisible_ConditionPostal = textPostal.Equals("") ||
                                                ValueUtil.tryGetString(model.postalPre).IndexOf(textPostal) >= 0;
                var isVisible_ConditionAddress = textAddress.Equals("") ||
                                                 ValueUtil.tryGetString(model.address1).IndexOf(textAddress) >= 0 ||
                                                 ValueUtil.tryGetString(model.address2).IndexOf(textAddress) >= 0;
                row.Visible = model.Id.Equals("") ||
                             (isVisible_ConditionPostal &&
                              isVisible_ConditionAddress);
            }
        }

        /// <summary>
        /// UI上のパネル情報を更新していく
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ev"></param>
        private void refreshRowPanelInfos(object sender, EventArgs ev)
        {
            //一覧更新ボタン押下時の処理
            //データ検索
            var paramRefresh = new AddressContentModel();
            paramRefresh.Enable = "";
            var paramRefreshHash = new System.Collections.Hashtable();
            paramRefreshHash.Add("param", paramRefresh);
            paramRefreshHash.Add("callback", new Action<object>(
                outputList =>
                {
                    //全てのパネルのモデルを抽出したデータで更新してく
                    foreach (var row in flowLayoutPanel1.Controls)
                    {
                        var rowPanel = row as InfoRowPanel2;
                        if (rowPanel == null) return;
                        foreach (var m in outputList as List<AddressContentModel>)
                        {
                            if ((rowPanel.Model as AddressContentModel).Id.Equals(m.Id))
                            {
                                rowPanel.Model = m;
                                break;
                            }
                        }
                    }
                }));
            ThreadRunner.doProcess(paramRefreshHash, doSearch, "address_searchForRefresh", false);
        }

        /// <summary>
        /// 検索
        /// </summary>
        public void doSearch(object paramHash)
        {
            using (var daoFactory = new DaoFactory())
            {
                var param = (paramHash as System.Collections.Hashtable)["param"] as AddressContentModel;
                var callback = (paramHash as System.Collections.Hashtable)["callback"] as Action<object>;
                try
                {
                    //DAO生成
                    var dao = (AddressDao)daoFactory.getDao<AddressContentModel>(GlobalSettings.addressDao_);
                    dao.inModel = param;

                    //データ取得
                    dao.orderDictionary.Add("id", "asc");
                    var resultDataList = dao.selectSimple(null) as List<AddressContentModel>;

                    if (resultDataList == null) return;

                    if (callback != null)
                        callback(resultDataList);
                }
                catch (Exception ex)
                {
                    System.Windows.Forms.MessageBox.Show(ex.ToString());
                }
            }
        }

        /// <summary>
        /// 検索後の処理
        /// 一覧にパネルを表示していく
        /// </summary>
        /// <param name="modelList"></param>
        private void callback_Search(object modelList)
        {
            var modelList_ = modelList as System.Collections.IList;
            InfoRowPanel2 rowPanel = null;
            List<BaseRowPanel> detailList = new List<BaseRowPanel>();
            foreach (AddressContentModel model in modelList_)
            {
                //更新用のパネルを生成
                rowPanel = createRowPanel(model, BaseRowPanel.PanelTypes.UpdateType);
                detailList.Add(rowPanel);
            }
            //新規登録用パネル
            var mod = new AddressContentModel();
            detailList.Add(createRowPanel(mod, BaseRowPanel.PanelTypes.InsertType));

            //[bindAction アクション] 情報表示用パネルを追加していく具体的な処理内容
            Action bindAction =
                () => { flowLayoutPanel1.Controls.AddRange(detailList.ToArray()); };
            
            if (InvokeRequired) this.Invoke(bindAction);
            else bindAction();
        }

        private InfoRowPanel2 createRowPanel(AddressContentModel model, BaseRowPanel.PanelTypes type)
        {
            InfoRowPanel2 rowPanel = new InfoRowPanel2(1, 2);
            rowPanel.EditPanel = new AddressFloatRowPanel();
            rowPanel.PanelType = type;
            rowPanel.OnModelChangedEvent += new EventHandler(rowPanel_OnModelChangedEvent);
            rowPanel.SettingModelToEditPanelEvent += new EventHandler(rowPanel_SettingModelToEditPanelEvent);
            rowPanel.OnButtonUpdateClickedEvent += new EventHandler(editPanel_OnButtonUpdateClicked);
            rowPanel.Model = model;
            return rowPanel;
        }

        /// <summary>
        /// モデルオブジェクト更新時の処理
        /// パネルに表示する文字列を更新
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ev"></param>
        private void rowPanel_OnModelChangedEvent(object sender, EventArgs ev)
        {
            var row = sender as InfoRowPanel2;
            var mod = row.Model as AddressContentModel;
            if (row.Model == null) return;
            row.Title = "ID:" + mod.Id;
            var buff = new System.Text.StringBuilder();
            buff.Append("【〒】").Append("　").AppendLine(mod.Enable.Equals("TRUE") ? "有効" : "無効")
                .Append("　").AppendLine(ValueUtil.tryGetString(mod.postalPre) + " - " + ValueUtil.tryGetString(mod.postalPost))
                .AppendLine("【住所】")
                .Append("　").AppendLine(ValueUtil.tryGetString(mod.address1))
                .Append("　").AppendLine(ValueUtil.tryGetString(mod.address2));

            row.Info = buff.ToString();
        }

        private void rowPanel_OnPropertyChanged(object sender, EventArgs ev)
        {

        }

        private void rowPanel_SettingModelToEditPanelEvent(object sender, EventArgs ev)
        {
            InfoRowPanel2 rowPanel = sender as InfoRowPanel2;
            AddressFloatRowPanel editPanel = rowPanel.EditPanel as AddressFloatRowPanel;
            editPanel.Model = rowPanel.Model;
        }

        /// <summary>
        /// 更新ボタン押下処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ev"></param>
        private void editPanel_OnButtonUpdateClicked(object sender, EventArgs ev)
        {
            var row = sender as InfoRowPanel2;
            var param = (row.EditPanel as AddressFloatRowPanel).MargedModel.DeepCopy() as AddressContentModel;
            var checkResults = param.IsAbsoluteData();
            if (checkResults.Count > 0)
            {
                MessageBox.Show(this, checkResults[0].Content, "データ確認", MessageBoxButtons.OK);
                return;
            }
            
            if (MessageBox.Show(this,
                "データベースを更新します。よろしいですか？",
                "更新確認",
                MessageBoxButtons.OKCancel) != DialogResult.OK)
                return;

            Action<AddressContentModel> act = res =>
            {
                row.Model = res;
                MessageBox.Show("更新完了！！");
                if (row.PanelType == BaseRowPanel.PanelTypes.InsertType)
                {
                    //新規登録用だったパネルを更新用に昇格
                    row.PanelType = BaseRowPanel.PanelTypes.UpdateType;
                    //新たな新規登録用パネルを追加
                    var mod = new AddressContentModel();
                    flowLayoutPanel1.Controls.Add(createRowPanel(mod, BaseRowPanel.PanelTypes.InsertType));
                }
            };

            if (param.Id.Equals("")) insert(param, row.Model, act);
            else update(param, act);
        }

        /// <summary>
        /// DB更新
        /// </summary>
        /// <param name="model"></param>
        private void update(AddressContentModel model, Action<AddressContentModel> callback)
        {
            using (var daoFactory = new DaoFactory())
            {
                daoFactory.beginTransaction();
                try
                {
                    //DAO生成
                    var dao = (AddressDao)daoFactory.getDao<AddressContentModel>(GlobalSettings.addressDao_);
                    dao.inModel = model;
                    dao.updateSimple(null);

                    daoFactory.commitTransaction();

                    if (callback != null)
                        callback(model);
                }
                catch (Exception ex)
                {
                    daoFactory.rollbackTransaction();
                    System.Windows.Forms.MessageBox.Show(ex.ToString());
                }
            }
        }

        /// <summary>
        /// DB登録
        /// </summary>
        /// <param name="model"></param>
        private void insert(AddressContentModel model, 
                            BaseContentModel org, 
                            Action<AddressContentModel> callback)
        {
            using (var daoFactory = new DaoFactory())
            {
                daoFactory.beginTransaction();
                try
                {
                    //データ処理
                    var dao = (AddressDao)daoFactory.getDao<AddressContentModel>(GlobalSettings.addressDao_);
                    //新規登録時、ＩＤが振られていないため（最新+1）を設定
                    model.Id = org.Id = (dao.selectLatestId() + 1).ToString();
                    //DB登録
                    dao.inModel = model;
                    dao.insertSimple(null);

                    daoFactory.commitTransaction();

                    if (callback != null)
                        callback(model);
                }
                catch (Exception ex)
                {
                    daoFactory.rollbackTransaction();
                    System.Windows.Forms.MessageBox.Show(ex.ToString());
                }
            }
        }

    }
}
