using System;
using ChaKi.Common;
using ChaKi.Entity.Corpora;
using ChaKi.Entity.Search;
using ChaKi.Entity.Settings;
using ChaKi.GUICommon;
using ChaKi.Service.Database;
using ChaKi.Entity;
using ChaKi.ToolDialogs;
using System.Collections.Generic;
using ChaKi.Entity.Corpora.Annotations;

namespace ChaKi
{
    public class ChaKiModel
    {
        /// <summary>
        /// CurrentCorpusが変化したときの通知イベント
        /// </summary>
        public static event CurrentChangedDelegate OnCurrentChanged;

        public static ChaKiModel Instance = new ChaKiModel();

        private ChaKiModel()
        {
            History = SearchHistory.Root;
            CurrentSearchConditions = new SearchConditions();
        }

        /// <summary>
        /// システムで唯一保持される、カレントコーパスの参照
        /// この値はさまざまな場合に変更される
        /// 変更要因：
        /// (1) Search Conditions/Corpusタブでユーザがコーパスのリストボックスの選択状態を変更したとき
        /// (2) 検索実行中に、検索対象のコーパスが変化したとき
        /// (3) KwicViewのカレント選択行が変更されたとき（選択行の元コーパスに変更される）
        /// (4) KwicViewでマウスHoverイベントが発生したとき（Hover行の元コーパスに変更される）
        /// 参照するクラス：
        /// (a) このクラス自身が、CurrentCorpusの設定により非表示属性を決定する
        /// (b) PropertyBoxが、CurrentCorpusの設定により非表示属性を決定する
        /// (c) GuidePanelが、表示更新前にCurrentCorpusの設定により非表示属性を決定する
        /// なお、CurrentCorpus == nullの場合は、デフォルトの属性がすべて表示される。
        /// </summary>
        public static Corpus CurrentCorpus
        {
            get
            {
                return Instance.m_currentCorpus;
            }
            set
            {
                Instance.m_currentCorpus = value;
                if (OnCurrentChanged != null)
                {
                    OnCurrentChanged(Instance.m_currentCorpus, -1);
                }
            }
        }

        private Corpus m_currentCorpus;

        public SearchHistory History { get; private set; }
        public SearchConditions CurrentSearchConditions { get; set; }

        public static IList<Corpus> CurrentCorpusList
        {
            get
            {
                return Instance.CurrentSearchConditions.SentenceCond.Corpora;
            }
        }

        public void Reset()
        {
            History.Reset();
            CurrentSearchConditions.Reset();
        }

        public void DeleteHistory(SearchHistory hist)
        {
            History.Delete(hist);
        }

        /// <summary>
        /// モデルの初期化を行う。アプリケーション開始時に呼び出される。
        /// ・CurrentCorpusを前回最後に使用した状態にする.
        /// ・CurrentSearchConditions.CollCondを前回最後に使用した状態にする.
        /// </summary>
        public void Initialize()
        {
            Reset();

            ChaKiModel.CurrentCorpus = null;
            foreach (Corpus c in UserSettings.GetInstance().LastCorpus)
            {
                try
                {
                    if (c.DBParam.DBType != "SQLite")
                    {
                        // PasswordはDBParameters経由では保存されないので、defファイルを読み直す.
                        c.DBParam.ParseDefFile(c.DBParam.DBPath);
                    }
                    DBService dbs = DBService.Create(c.DBParam);

                    // TagSelectorの内容をLoadMandatoryCorpusInfo()のcallbackによって設定する
                    TagSelector.ClearAllTags();

                    dbs.LoadSchemaVersion(c);
                    // Schemaチェック
                    if (c.Schema.Version != CorpusSchema.CurrentVersion)
                    {
                        DBSchemaConversion dlg = new DBSchemaConversion(dbs, c);
                        dlg.DoConversion();
                    }

                    dbs.LoadMandatoryCorpusInfo(c, (s, t) => { TagSelector.PreparedSelectors[s].AddTag(t); });

                    if (ChaKiModel.CurrentCorpus == null)
                    {
                        ChaKiModel.CurrentCorpus = c;
                    }
                }
                catch (Exception ex)
                {
                    ErrorReportDialog err = new ErrorReportDialog("Cannot load default corpus", ex);
                    err.ShowDialog();
                    continue;
                }
                CurrentSearchConditions.SentenceCond.Corpora.Add(c);
            }
            CollocationCondition collCond = UserSettings.GetInstance().DefaultCollCond;
            if (collCond != null)
            {
                CurrentSearchConditions.CollCond = collCond;
            }
        }
    }
}
