using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using Crownwood.DotNetMagic.Docking;
using Crownwood.DotNetMagic.Common;
using Crownwood.DotNetMagic.Forms;

using ChaKi.Common;
using ChaKi.GUICommon;
using ChaKi.Panels;
using ChaKi.UICommands;
using DependencyEditSLA;
using ChaKi.Entity.Settings;
using ChaKi.Entity.Corpora;
using ChaKi.Entity.Kwic;
using ChaKi.Entity.Search;
using ChaKi.Common.Settings;
using ChaKi.Views.KwicView;
using ChaKi.Views;

namespace ChaKi
{
    public delegate void BeginSearchDelegate();

    public partial class MainForm : DotNetMagicForm
    {
        #region private members
        private static MainForm instance;
        private DockingManager dockingManager;
        private Content condPanelContainer;
        private Content commandPanelContainer;
        private Content contextPanelContainer;
        private Content scriptingPanelContainer;
        private Content LexemePanelContainer;
        private Content historyGuidePanelContainer;
        private Content dependencyEditContainer;
        private Content AttributePanelContainer;
        private ConditionsPanel condPanel;
        private CommandPanel commandPanel;
        private ContextPanel contextPanel;
        private ScriptingPanel scriptingPanel;
        private WordAttributeListPanel wordAttributeListPanel;
        private HistoryGuidePanel historyGuidePanel;
        private DepEditControl dependencyEditPanel;
        private AttributeListPanel attributePanel;

        // このFormに対応する唯一のModelオブジェクト
        // Formの所有する各子ウィンドウは、このModelの一部を割り当てられ、そのUpdateを通知される。
        private ChaKiModel m_Model;

        private string m_DockStateFile;

        #endregion

        public static Rectangle SBounds
        {
            get
            {
                return (instance == null) ? Rectangle.Empty : instance.Bounds;
            }
        }

        static public MainForm Instance
        {
            get { return instance; }
        }

        public KwicView KwicView
        {
            get { return this.kwicView; }
        }

        public MainForm()
        {
            instance = this;

            InitializeComponent();

            Program.MainForm = this;
            m_Model = ChaKiModel.Instance;
            m_Model.Initialize();

            #region create views
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));

            // Create Views
            this.kwicView.Dock = DockStyle.Fill;
            this.wordListView.Dock = DockStyle.Fill;
            this.collocationView.Dock = DockStyle.Fill;

            // 初期状態で表示するView
            this.ChangeView(SearchType.SentenceSearch);

            this.ResumeLayout();
            #endregion

            #region create docking panels
            // Create Docking Panels
            condPanel = new ConditionsPanel(m_Model.CurrentSearchConditions);
            contextPanel = new ContextPanel();
            scriptingPanel = new ScriptingPanel();
            wordAttributeListPanel = new WordAttributeListPanel();
            commandPanel = new CommandPanel(condPanel.GetFilterButton());
            historyGuidePanel = new HistoryGuidePanel(m_Model.History);
            dependencyEditPanel = new DepEditControl();
            attributePanel = new AttributeListPanel();

            try
            {
                this.Style = GUISetting.Instance.Visual;
                GUISetting.Instance.VisualStyleChanged += new EventHandler(delegate { ChangeStyle(GUISetting.Instance.Visual); });
            }
            catch
            {
                this.Style = VisualStyle.Office2007Silver;  // Default
            }
            this.dockingManager = new DockingManager(toolStripContainer1.ContentPanel, this.Style);
            condPanel.Style = this.Style;

            dockingManager.CaptionFont = new Font("Arial", 7.5F);
            dockingManager.TabControlFont = new Font("Lucida Sans Unicode", 8F);
            dockingManager.AllowSideCaptions = true;

            // Hook into the events generated by the docking manager
            //            dockingManager.ContextMenu += new DockingManager.ContextMenuHandler(OnContextMenu);

            // Ensure correct inner and outer values for correct window positioning
            dockingManager.InnerControl = this.kwicView;

            // Setup custom config handling
            dockingManager.SaveCustomConfig += new DockingManager.SaveCustomConfigHandler(OnSaveConfig);
            dockingManager.LoadCustomConfig += new DockingManager.LoadCustomConfigHandler(OnLoadConfig);

            // Create the initial starting docking windows
            // Create a new docking Content instance with our new ExampleForm
            WindowContent wc;
            // Upper (default) Docking Panels
            condPanelContainer = dockingManager.Contents.Add(condPanel, "Search Conditions");
            condPanelContainer.FloatingSize = new Size(800, 150);
            wc = dockingManager.AddContentWithState(condPanelContainer, State.DockTop) as WindowContent;

            commandPanelContainer = dockingManager.Contents.Add(commandPanel, "Command");
            commandPanelContainer.FloatingSize = new Size(200, 150);
            dockingManager.AddContentToZone(commandPanelContainer, wc.ParentZone, 1);

            historyGuidePanelContainer = dockingManager.Contents.Add(historyGuidePanel, "History");
            historyGuidePanelContainer.FloatingSize = new Size(200, 150);
            dockingManager.AddContentToZone(historyGuidePanelContainer, wc.ParentZone, 2);

            // Lower (default) Docking Panels
            dependencyEditContainer = dockingManager.Contents.Add(dependencyEditPanel, "Dependency");
            dependencyEditContainer.FloatingSize = new Size(640, 480);
            wc = dockingManager.AddContentWithState(dependencyEditContainer, State.DockBottom) as WindowContent;

            contextPanelContainer = dockingManager.Contents.Add(contextPanel, "Context");
            contextPanelContainer.FloatingSize = new Size(800, 150);
            dockingManager.AddContentToZone(contextPanelContainer, wc.ParentZone, 1);

            scriptingPanelContainer = dockingManager.Contents.Add(scriptingPanel, "Scripting");
            scriptingPanelContainer.FloatingSize = new Size(640, 480);
            dockingManager.AddContentToZone(scriptingPanelContainer, wc.ParentZone, 2);

            AttributePanelContainer = dockingManager.Contents.Add(attributePanel, "Attributes");
            AttributePanelContainer.FloatingSize = new Size(200, 150);
            dockingManager.AddContentToZone(AttributePanelContainer, wc.ParentZone, 1);

            LexemePanelContainer = dockingManager.Contents.Add(wordAttributeListPanel, "Lexeme");
            LexemePanelContainer.FloatingSize = new Size(200, 150);
            dockingManager.AddContentToZone(LexemePanelContainer, wc.ParentZone, 2);

            m_DockStateFile = Program.SettingDir + @"\DockState.xml";
            try
            {
                dockingManager.LoadConfigFromFile(m_DockStateFile);
            }
            catch (FileNotFoundException)
            {
            }
            catch
            {
                MessageBox.Show("Could not restore docking positions.  Resetting.");
            }

            // Floating PanelがVisibleに戻らないので、強制的にVisibleにセットする.
            // Visibleにするのは、Controlの親を辿った最上位のFloatingForm Controlである.
            foreach (Content c in this.dockingManager.Contents)
            {
                if (c.Visible)
                {
                    Control p = c.Control;
                    while (p != null)
                    {
                        if (p is FloatingForm)
                        {
                            p.Visible = true;
                        }
                        p = p.Parent;
                    }
                }
            }
            #endregion

            #region UICommand登録
            //
            // アプリケーションのコマンド管理メカニズムは、
            // ChaKi.UICommandsサブフォルダに存在するUICommandクラスが行っている
            // cf. http://geekswithblogs.net/willemf/archive/2007/06/05/113005.aspx
            //
            UICommand uc;
            UICommand.Commands.Add((uc = new UICommand(this, "FileOpen")));
            UICommand.Commands.Add((uc = new UICommand(this, "FileSave")));
            UICommand.Commands.Add((uc = new UICommand(this, "FileSaveAs")));
            UICommand.Commands.Add((uc = new UICommand(this, "FileSendToExcelCSV")));
            UICommand.Commands.Add((uc = new UICommand(this, "FileExit")));

            UICommand.Commands.Add((uc = new UICommand(this, "EditCopy")));
            uc.UpdateEventHandler += this.OnEditCutCopyPasteUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "EditCut")));
            UICommand.Commands.Add((uc = new UICommand(this, "EditPaste")));
            UICommand.Commands.Add((uc = new UICommand(this, "EditDeleteAll")));
            UICommand.Commands.Add((uc = new UICommand(this, "EditCheckAll")));
            UICommand.Commands.Add((uc = new UICommand(this, "EditCheckSelected")));
            UICommand.Commands.Add((uc = new UICommand(this, "EditUncheckAll")));
            UICommand.Commands.Add((uc = new UICommand(this, "EditSelectAll")));
            UICommand.Commands.Add((uc = new UICommand(this, "EditUnselectAll")));
            UICommand.Commands.Add((uc = new UICommand(this, "EditSelectChecked")));

            UICommand.Commands.Add((uc = new UICommand(this, "ViewToolbar")));
            uc.UpdateEventHandler += this.OnViewToolbarUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewStatusBar")));
            uc.UpdateEventHandler += this.OnViewStatusBarUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewSearchPanel")));
            uc.UpdateEventHandler += this.OnViewSearchPanelUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewHistoryPanel")));
            uc.UpdateEventHandler += this.OnViewHistoryPanelUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewCommandPanel")));
            uc.UpdateEventHandler += this.OnViewCommandPanelUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewContextPanel")));
            uc.UpdateEventHandler += this.OnViewContextPanelUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewDependencyEditPanel")));
            uc.UpdateEventHandler += this.OnViewDependencyEditPanelUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewScriptingPanel")));
            uc.UpdateEventHandler += this.OnViewScriptingPanelUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewKwicMode")));
            uc.UpdateEventHandler += this.OnViewKwicModeUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewTextMode")));
            uc.UpdateEventHandler += this.OnViewTextModeUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewAttributePanel")));
            uc.UpdateEventHandler += this.OnViewAttributePanelUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewLexemePanel")));
            uc.UpdateEventHandler += this.OnViewLexemePanelUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewViewAttributes")));
            uc.UpdateEventHandler += this.OnViewViewAttributesUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "ViewReloadKwicView")));
            UICommand.Commands.Add((uc = new UICommand(this, "ViewLoadAnnotations")));
            UICommand.Commands.Add((uc = new UICommand(this, "ViewAutoAdjustRowWidth")));
            UICommand.Commands.Add((uc = new UICommand(this, "ViewAdjustRowWidthToTheLeft")));
            UICommand.Commands.Add((uc = new UICommand(this, "ViewGotoSentence")));

            UICommand.Commands.Add((uc = new UICommand(this, "SearchSelectCorpus")));
            uc.UpdateEventHandler += this.OnSearchSelectCorpusUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "SearchSetSearchFilters")));
            uc.UpdateEventHandler += this.OnSearchSetSearchFiltersUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "SearchStringSearchSettings")));
            uc.UpdateEventHandler += this.OnSearchStringSearchSettingsUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "SearchTagSearchSettings")));
            uc.UpdateEventHandler += this.OnSearchTagSearchSettingsUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "SearchDependencySearchSettings")));
            uc.UpdateEventHandler += this.OnSearchDependencySearchSettingsUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "SearchCollocationSettings")));
            uc.UpdateEventHandler += this.OnSearchCollocationSettingsUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "SearchBeginSearch")));
            uc.UpdateEventHandler += this.OnSearchBeginSearchUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "SearchBeginSearchNarrow")));
            UICommand.Commands.Add((uc = new UICommand(this, "SearchBeginSearchAppend")));
            UICommand.Commands.Add((uc = new UICommand(this, "SearchLoadSearchConditions")));
            UICommand.Commands.Add((uc = new UICommand(this, "SearchSaveCurrentSearchConditions")));
            UICommand.Commands.Add((uc = new UICommand(this, "SearchResetAllSearchSettings")));
            UICommand.Commands.Add((uc = new UICommand(this, "SearchExamineLastSearch")));
            UICommand.Commands.Add((uc = new UICommand(this, "SearchExamineLastEdit")));
            UICommand.Commands.Add((uc = new UICommand(this, "SearchSearchInView")));

            UICommand.Commands.Add((uc = new UICommand(this, "FormatShiftPivotLeft")));
            uc.UpdateEventHandler += this.OnFormatShiftUpdate;
            UICommand.Commands.Add((uc = new UICommand(this, "FormatShiftPivotRight")));
            UICommand.Commands.Add((uc = new UICommand(this, "FormatHilightPreviousWord")));
            UICommand.Commands.Add((uc = new UICommand(this, "FormatHilightNextWord")));

            UICommand.Commands.Add((uc = new UICommand(this, "ToolsCreateSQLiteCorpus")));
            UICommand.Commands.Add((uc = new UICommand(this, "ToolsCreateMySQLCorpus")));
            UICommand.Commands.Add((uc = new UICommand(this, "ToolsEditTagSetDefinitions")));
            UICommand.Commands.Add((uc = new UICommand(this, "ToolsCreateDictionary")));
            UICommand.Commands.Add((uc = new UICommand(this, "ToolsTextFormatter")));

            UICommand.Commands.Add((uc = new UICommand(this, "OptionsSettings")));
            UICommand.Commands.Add((uc = new UICommand(this, "OptionsPropertyBoxSettings")));
            UICommand.Commands.Add((uc = new UICommand(this, "OptionsWordColorSettings")));
            UICommand.Commands.Add((uc = new UICommand(this, "OptionsTagAppearance")));
            UICommand.Commands.Add((uc = new UICommand(this, "OptionsDictionarySettings")));

            UICommand.Commands.Add((uc = new UICommand(this, "HelpHelp")));
            UICommand.Commands.Add((uc = new UICommand(this, "HelpAbout")));
            #endregion

            // CommandPanelからのCallback
            commandPanel.BeginSearch = this.OnBeginSearch;
            commandPanel.NarrowSearch = this.OnBeginSearchNarrow;
            commandPanel.AppendSearch = this.OnBeginSearchAppend;
            commandPanel.BeginWordList = this.OnBeginWordList;
            commandPanel.BeginCollocation = this.OnBeginCollocation;

            // ConditionsPanelからのCallback
            condPanel.TabChanged += new EventHandler(OnConditionTabChanged);

            // KwicViewからのCallback
            this.kwicView.UpdateGuidePanel += new UpdateGuidePanelDelegate(this.OnUpdateGuidePanel);
            this.kwicView.CurrentChanged += new CurrentChangedDelegate(this.OnCurrentChanged);
            this.kwicView.DepEditRequested += new RequestDepEditDelegate(this.OnRequestDepEdit);
            this.kwicView.ContextRequested += new RequestContextDelegate(this.OnRequestContext);
            this.kwicView.ContextRequested += new RequestContextDelegate(this.OnRequestSentenceTagList);

            // WordListViewからのCallback
            this.wordListView.OccurrenceRequested += new EventHandler(this.OnWordOccurenceRequested);

            // CollocationViewからのcallback
            this.collocationView.OccurrenceRequested += new EventHandler<SentenceIdsOccurrenceEventArgs>(HandleCollocationOccurrenceRequested);

            // HistoryGuidePanelからのCallback
            this.historyGuidePanel.HistoryNavigating +=new NavigateHistoryDelegate(this.OnHistoryNavigating);
            this.historyGuidePanel.HistorySaveRequested += new EventHandler(this.OnHistorySaveRequested);
            this.historyGuidePanel.DeleteHistoryRequested += new EventHandler(this.OnDeleteHistoryRequested);

            // DepEditからのCallback
            this.dependencyEditPanel.UpdateGuidePanel += new UpdateGuidePanelDelegate(this.OnUpdateGuidePanel);
            this.dependencyEditPanel.UpdateAttributePanel += new UpdateAttributePanelDelegate(this.OnUpdateAttributePanel);
            this.dependencyEditPanel.ChangeSenenceRequested += new ChangeSentenceDelegate(this.OnChangeSenenceRequested);
        }

        public void ChangeStyle(VisualStyle st)
        {
            this.Style = st;
            this.dockingManager.Style = st;
        }

        /// <summary>
        /// Docking Panelの表示・非表示を切り替える
        /// </summary>
        /// <param name="c"></param>
        private void SwitchVisible(Content c)
        {
            if (c.Visible)
            {
                this.dockingManager.HideContent(c);
            }
            else
            {
                this.dockingManager.ShowContent(c);
            }
        }

        public void IdleUpdate()
        {
            UICommand.UpdateCommands();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            // DependencyEditの終了前セーブを確認
            if (!this.dependencyEditPanel.EndEditing())
            {
                e.Cancel = true;
                return;
            }
            // 終了時にDepEditのコントロールをすべてクリアすることで、ちらつきを軽減する。
            this.dependencyEditPanel.Terminate();

            // AttributeEditの終了前セーブ確認
            if (!this.attributePanel.EndEditing())
            {
                e.Cancel = true;
                return;
            }

            // SentenceEditの終了前セーブ確認
            if (!this.contextPanel.EndEditing())
            {
                e.Cancel = true;
                return;
            }

            // WordAttributeEditの終了前セーブ確認
            if (!this.wordAttributeListPanel.EndEditing())
            {
                e.Cancel = true;
                return;
            }

            // CommandPanelにスレッド中断を指示する
            this.commandPanel.Abort(false);

            // Docking状態を保存する
            dockingManager.SaveConfigToFile(m_DockStateFile);

            // ユーザ設定を保存する
            UserSettings.GetInstance().LastCorpus = m_Model.CurrentSearchConditions.SentenceCond.Corpora;
            UserSettings.GetInstance().DefaultCollCond = m_Model.CurrentSearchConditions.CollCond;
        }

        delegate void BeginSentenceEditDele(Corpus c, int i, int j);

        public void OnCurrentChanged(Corpus cps, int senid)
        {
            if (cps != null && senid >= 0) {
                // StatusBarを更新する
                this.statusStrip1.SetCorpusName(cps.Name);
                this.statusStrip1.SetSentenceNo(senid);
            }
        }

        public void OnRequestDepEdit(KwicItem ki)
        {
            if (!this.dependencyEditContainer.Visible || ki == null)
            {
                return;
            }
            BeginSentenceEdit(ki.Crps, ki.SenID, ki.CenterWordID);
        }

        /// <summary>
        /// DepEditから編集する文の移動を要求されたときの処理
        /// </summary>
        /// <param name="direction"></param>
        public void OnChangeSenenceRequested(Corpus crps, int currentSenid, int direction, bool moveInKwicList)
        {
            // 最初にセーブ確認
            if (!this.dependencyEditPanel.EndEditing())
            {
                return;
            }

            if (!this.dependencyEditContainer.Visible)
            {
                return;
            }
            Corpus c;
            int newSenId = 0;
            int center = -1;
            if (moveInKwicList)
            {
                // KwicList中の前後の文に移動
                KwicItem ki = this.kwicView.ShiftCurrent(direction);
                if (ki == null)
                {
                    c = null;
                }
                else
                {
                    c = ki.Crps;
                    newSenId = ki.SenID;
                    center = ki.CenterWordID;
                }
            }
            else
            {
                // 単純にCorpsu内の文を移動
                if (currentSenid >= 0)
                {
                    newSenId = currentSenid + direction;
                }
                else
                {
                    newSenId = direction;
                }
                c = crps;
            }
            if (c == null)
            {
                MessageBox.Show("No more sentence found.");
                return;
            }
            if (!BeginSentenceEdit(c, newSenId, center))
            {
                BeginSentenceEdit(crps, currentSenid, -1);
            }
        }

        /// <summary>
        /// タグ編集を開始する.
        /// </summary>
        /// <param name="crps">コーパス</param>
        /// <param name="senid">文番号</param>
        /// <param name="cwid">中心語（赤色表示する）不要なら-1</param>
        /// <returns></returns>
        private bool BeginSentenceEdit(Corpus crps, int senid, int cwid)
        {
            // 最初にセーブ確認
            if (!this.dependencyEditPanel.EndEditing())
            {
                return true;
            }
            Cursor oldCur = this.Cursor;
            this.Cursor = Cursors.WaitCursor;

            // DependencyEditを開始する
            bool res = (bool)this.dependencyEditPanel.Invoke(
                new Func<Corpus, int, int, bool>(this.dependencyEditPanel.BeginSentenceEdit),
                crps, senid, cwid);

            this.Cursor = oldCur;
            return res;
        }

        public void OnUpdateGuidePanel(Corpus corpus, Lexeme lex)
        {
            if (lex != null)
            {
                this.wordAttributeListPanel.SetSource(corpus, lex);
            }
        }

        public void OnUpdateAttributePanel(Corpus corpus, object source)
        {
            if (source != null)
            {
                this.attributePanel.SetSource(corpus, source);
            }
        }

        private void OnConditionTabChanged(object sender, EventArgs args)
        {
            ConditionsPanelType tab = this.condPanel.SelectedTab;
            bool[] commandEnableStates = null;
            switch (tab)
            {
                case ConditionsPanelType.CP_CORPUS:
                    commandEnableStates = new bool[5] { true, true, false, false, true };
                    break;
                case ConditionsPanelType.CP_FILTER:
                    commandEnableStates = new bool[5] { true, false, false, false, true };
                    break;
                case ConditionsPanelType.CP_STRING:
                    commandEnableStates = new bool[5] { true, true, false, false, true };
                    break;
                case ConditionsPanelType.CP_TAG:
                case ConditionsPanelType.CP_DEP:
                    commandEnableStates = new bool[5] { true, true, true, false, true };
                    break;
                case ConditionsPanelType.CP_COLLOCATION:
                    commandEnableStates = new bool[5] { false, false, false, true, true };
                    break;
            }
            if (commandEnableStates != null)
            {
                this.commandPanel.CommandEnableStates = commandEnableStates;
            }
        }

        /// <summary>
        /// 指定された検索の種類によってViewを切り替える
        /// </summary>
        /// <param name="st"></param>
        public IChaKiView ChangeView(SearchType st)
        {
            IChaKiView activeView = null;

            this.kwicView.SetVisible(false);
            this.wordListView.SetVisible(false);
            this.collocationView.SetVisible(false);

            if (st == SearchType.TagWordList || st == SearchType.DepWordList)
            {
                activeView = this.wordListView;
            }
            else if (st == SearchType.Collocation)
            {
                activeView = this.collocationView;
            }
            else 
            {
                activeView = this.kwicView;
                this.kwicView.KwicMode = (st != SearchType.SentenceSearch);
                this.kwicView.TwoLineMode = (st != SearchType.StringSearch);
            }

            if (activeView != null)
            {
                activeView.SetVisible(true);
            }
            return activeView;
        }

        public IChaKiView GetActiveView()
        {
            if (this.attributePanel.ContainsFocus)
            {
                return this.attributePanel;
            }
            if (this.contextPanel.ContainsFocus)
            {
                return this.contextPanel;
            }
            if (this.kwicView.Visible)
            {
                return this.kwicView;
            }
            if (this.wordListView.Visible)
            {
                return this.wordListView;
            }
            if (this.collocationView.Visible)
            {
                return this.collocationView;
            }
            return null;
        }

        private void MainForm_KeyUp(object sender, KeyEventArgs e)
        {
            bool f = this.kwicView.Focused;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
        }
    }
}