using System;
using System.Collections.Generic;
using nft.framework;
using System.Windows.Forms;
using nft.impl.view;
using nft.ui;

namespace nft.core.game {
    public class ViewCollection : IEnumerable<ViewController>{
        static protected IViewFactory ViewFactory {
            get {
                return GlobalModules.GetModule(typeof(IViewFactory)) as IViewFactory;
            }
        }


        protected List<ViewController> views;
        protected IGame game;
        protected ViewController current;
        protected IEnumerable<IPointerHandler> awakeTools;

        public ViewCollection(IGame _game) {
            game = _game;
            views = new List<ViewController>();
            awakeTools = new ToolEnumerator();
        }

        public IGame Game {
            get {
                return game;
            }
        }

        public virtual ViewController ActiveView {
            get {
                return current;
            }
            set {
                if (value != null) {
                    SetActive(value);
                }
            }
        }

        public virtual ViewController PrimaryView {
            get {
                return views.Count>0 ? views[0] : null;
            }
            /*
            set {
                throw new NotImplementedException();
            }
             */
        }

        public ViewController OpenNew() {
            ViewController v = CreateView();
            if (Add(v)) {
                SetActive(v);
                return v;
            }else{
                v.Dispose();
                return null;
            }
        }

        public void CloseAll() {
            foreach (ViewController v in views) {
                v.Dispose();
            }
            views.Clear();
        }

#region protected methods for override
        protected virtual bool Add(ViewController v) {            
            views.Add(v);
            return true;
        }

        protected virtual bool Remove(ViewController v) {
            return views.Remove(v);
        }

        protected virtual void SetActive(ViewController v) {
            if (views.Contains(v)) {
                current = v;
            } else {
                throw new InvalidOperationException("The view is not a member of collection.");
            }
        }

        protected virtual ViewController CreateView() {
            IView v = ViewFactory.Create();
            Main.mainFrame.AddView(Game.Name, v);
            v.MouseCursorMove += ViewMouseMove;
            v.MouseButtonDown += ViewMouseBtnDown;
            v.MouseButtonUp += ViewMouseBtnUp;
            v.Activated += ViewActivated;
            v.OnClose += OnViewClose;
            v.QueryClose += QueryViewClose;

            SceneBuilder builder = new SceneBuilder(game);
            ViewController controller = new ViewController(builder, v);

            return controller;
        }

        void ViewActivated(ViewEventArgs ea) {
            ViewController controller = FindController(ea.View);
            SetActive(controller);
        }

        protected ViewController FindController(IView view) {
            foreach (ViewController controller in this.views) {
                if (controller.View == view) return controller;
            }
            return null;
        }

        protected PointerEventArgs MakeArg(object sender, MouseEventArgs e) {
            IView view = sender as IView;
            return new PointerEventArgs(e, Game, view.Surface);
        }

        void ViewMouseBtnUp(object sender, MouseEventArgs e) {
            PointerEventArgs pe = MakeArg(sender, e);
            foreach (IPointerHandler h in awakeTools) {
                h.OnMouseButtonUp(pe);
            }
        }

        void ViewMouseBtnDown(object sender, MouseEventArgs e) {
            PointerEventArgs pe = MakeArg(sender, e);
            foreach (IPointerHandler h in awakeTools) {
                h.OnMouseButtonDown(pe);
            }
        }

        void ViewMouseMove(object sender, MouseEventArgs e) {
            PointerEventArgs pe = MakeArg(sender, e);
            bool dirty = false;
            foreach (IPointerHandler h in awakeTools) {
                h.OnMouseMove(pe);
                dirty = true;
            }
            if (dirty) {
                IView view = sender as IView;
                view.Refresh();
            }
        }

        protected virtual void OnViewClose(ViewEventArgs ea) {
            IView v = ea.View;
            v.MouseCursorMove -= ViewMouseMove;
            v.MouseButtonDown -= ViewMouseBtnDown;
            v.MouseButtonUp -= ViewMouseBtnUp;
            v.Activated -= ViewActivated;
            v.OnClose -= OnViewClose;
            v.QueryClose -= OnViewClose;

            if (PrimaryView.View == v && !game.Closed) {
                game.Close();
                ViewController controller = FindController(v);
                if (controller != null) {
                    Remove(controller);
                }
            }
        }

        protected virtual void QueryViewClose(ViewQueryEventArgs ea) {
            IView v = ea.View;
            if (PrimaryView.View == v) {
                ea.Cancel = !game.ConfirmClose();
            }
        }
#endregion

        #region IEnumerable implementation
        public IEnumerator<ViewController>  GetEnumerator()
        {
            return views.GetEnumerator();
        }

        System.Collections.IEnumerator  System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        #endregion

        class ToolEnumerator : IEnumerable<IPointerHandler> {

            public IEnumerator<IPointerHandler> GetEnumerator() {
                return GameManager.theInstance.Tools.EnumAwakeTools();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
                return GetEnumerator();
            }
        }
    }
}
