using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using nft.ui.form;

namespace nft.ui
{
    internal class WinFormWrapper : IxForm
    {
        protected readonly Form entity;
        protected readonly Dictionary<string, IxControl> ctrCache = new Dictionary<string, IxControl>();

        public WinFormWrapper(Form f){
            entity = f;
            PrepareEventHandlers();
        }

        public WinFormWrapper(Type win_form_class) :this((Form) Activator.CreateInstance(win_form_class,true)){            
        }

        protected void PrepareEventHandlers() {
            entity.Load += new EventHandler(Entity_Load);
            entity.Disposed += new EventHandler(Entity_Closed);
            entity.VisibleChanged += new EventHandler(Entity_VisibleChanged);
            // TODO What todo for OnApply?
        }

        void Entity_VisibleChanged(object sender, EventArgs e) {
            if (VisibleChanged != null)
                VisibleChanged(this, Find(sender as Control)); 
        }

        void Entity_Closed(object sender, EventArgs e) {
            if (OnClose != null)
                OnClose(this, Find(sender as Control)); 
        }

        void Entity_Load(object sender, EventArgs e) {
            if (OnOpen != null)
                OnOpen(this, Find(sender as Control)); 
        }

        public string Name {
            get {
                return entity.Name;
            }
        }

        public IxControl this[string name] {
            get
            {
                IxControl c;
                if (!ctrCache.TryGetValue(name, out c))
                {
                    Control c0 = entity.Controls[name];
                    if (c0 != null)
                    {
                        c = CreateWrapperFor(c0);
                        ctrCache.Add(name, c);
                    }
                }
                return c;
            }
        }

        public IxInput<T> Get<T>(string name)
        {
            return this[name] as IxInput<T>;
        }

        protected IxControl Find(Control c) {
            return this[c.Name];
        }

        protected WinControlWrapper CreateWrapperFor(Control c) {
            WinControlWrapper w = new WinControlWrapper(c);
            // TODO for ControlValuesChanged
            return w;
        }

        public IEnumerator<IxControl> EnumChildren() {
            return new ControlEnumerator(this).GetEnumerator();
        }

        protected sealed class ControlEnumerator : IEnumerable<IxControl>
        {
            readonly WinFormWrapper wrapper;
            public ControlEnumerator(WinFormWrapper wfw) {
                wrapper = wfw;
            }

            public IEnumerator<IxControl> GetEnumerator() {
                IxControl ret;
                foreach (Control c in wrapper.entity.Controls) {
                    ret = wrapper.Find(c);
                    yield return ret;
                }
            }

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


        public bool Enabled
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public bool Visible {
            get {
                return entity.Visible;
            }
            set {
                entity.Visible = value;
            }
        }

        public event XFormEvent OnOpen;

        public event XFormEvent OnClose;

        public event XFormEvent VisibleChanged;

        public event XFormEvent ControlValuesChanged;

        public event XFormEvent OnApply;

    }
}
