using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using nft.framework.drawing;

namespace nft.ui.view
{
    public class GameViewPanel : UserControl, IView
    {
        private Size contentSize;
        
        public GameViewPanel() {
            InitializeComponent();
            //renderPanel.SurfaceUsage = SurfaceUsage.Normal;
            touchPanel.Scroll2 += new ScrollEventHandler(OnTouchPanelScroll);
        }

        public event EventHandler SurfacePrepared {
            add {
                renderPanel.OnSurfacePrepared += new EventHandler(value); 
                if (Surface != null) {
                    value(renderPanel, new EventArgs());
                }
            }
            remove {
                renderPanel.OnSurfacePrepared -= new EventHandler(value); 
            }
        }

        #region Internal event handlers
        void EventTarget_MouseMove(object sender, MouseEventArgs e) {
            if (MouseCursorMove != null) MouseCursorMove(this, e);
        }
        void EventTarget_MouseDown(object sender, MouseEventArgs e) {
            if (MouseButtonDown != null) MouseButtonDown(this, e);
        }
        void EventTarget_MouseUp(object sender, MouseEventArgs e) {
            if (MouseButtonUp != null) MouseButtonUp(this, e);
        }
        void Parent_LostFocus(object sender, EventArgs e) {
            if (Activated != null) Activated(new ViewEventArgs(this));
        }

        void Parent_GotFocus(object sender, EventArgs e) {
            // Do nothing
        }
        #endregion

        #region IView implementations
        public void SetScrollParams(Size contentSize) {
            this.contentSize = contentSize;
            InitScroll();
        }

        public ISurface Surface {
            get { return renderPanel.Surface; }
        }

        public void Close() {
            if (OnClose != null) OnClose(new ViewEventArgs(this));
            this.Dispose();
        }

        public event ViewEventHandler OnClose;
        public event ViewQueryEventHandler QueryClose;
        public event ViewEventHandler Activated;
        public event ViewPointEventHandler ViewPointChanged;
        public event MouseEventHandler MouseCursorMove;
        public event MouseEventHandler MouseButtonDown;
        public event MouseEventHandler MouseButtonUp;
        #endregion

        void OnTouchPanelScroll(object sender, ScrollEventArgs e) {
            UpdateScrollParams(false);
        }


        protected override void OnLoad(EventArgs e) {
            base.OnLoad(e);
            this.SuspendLayout();
            renderPanel.EventTarget.MouseMove += EventTarget_MouseMove;
            renderPanel.EventTarget.MouseDown += EventTarget_MouseDown;
            renderPanel.EventTarget.MouseUp += EventTarget_MouseUp;
            Parent.GotFocus += Parent_GotFocus;
            Parent.LostFocus += Parent_LostFocus;
            SetupCloseConfirmation();
            this.ResumeLayout(false);
        }

        protected virtual void SetupCloseConfirmation() {
            Control c = this;
            Form f = null;
            while (null == (f = c as Form)) {
                c = c.Parent;
                if (c == null) return; // 予期せぬ状況
            }
            f.FormClosing += new FormClosingEventHandler(OnClosing);
        }

        protected void OnClosing(object sender, FormClosingEventArgs e) {
            if (QueryClose != null) {
                ViewQueryEventArgs arg = new ViewQueryEventArgs(this);
                QueryClose(arg);
                e.Cancel = arg.Cancel;
            }
        }

        protected override void Dispose(bool disposing) {
            base.Dispose(disposing);
            if (OnClose != null) OnClose(new ViewEventArgs(this));
        }

        #region Designer generated
        private TouchPanel touchPanel;
        private RenderViewPanel renderPanel;
        private Panel panelDummy;
        private void InitializeComponent() {
            this.renderPanel = new nft.framework.drawing.RenderViewPanel();
            this.touchPanel = new nft.ui.view.TouchPanel();
            this.panelDummy = new System.Windows.Forms.Panel();
            this.touchPanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // renderPanel
            // 
            this.renderPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.renderPanel.Location = new System.Drawing.Point(0, 0);
            this.renderPanel.Name = "renderPanel";
            this.renderPanel.Size = new System.Drawing.Size(150, 150);
            this.renderPanel.SurfaceUsage = nft.framework.drawing.SurfaceUsage.GameView;
            this.renderPanel.TabIndex = 1;
            // 
            // touchPanel
            // 
            this.touchPanel.AutoScroll = true;
            this.touchPanel.BackColor = System.Drawing.Color.Transparent;
            this.touchPanel.Controls.Add(this.panelDummy);
            this.touchPanel.Dock = System.Windows.Forms.DockStyle.Fill;
            this.touchPanel.Location = new System.Drawing.Point(0, 0);
            this.touchPanel.Name = "touchPanel";
            this.touchPanel.Size = new System.Drawing.Size(150, 150);
            this.touchPanel.TabIndex = 0;
            // 
            // panelDummy
            // 
            this.panelDummy.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.panelDummy.Location = new System.Drawing.Point(0, 0);
            this.panelDummy.Name = "panelDummy";
            this.panelDummy.Size = new System.Drawing.Size(150, 150);
            this.panelDummy.TabIndex = 0;
            // 
            // GameViewPanel
            // 
            this.Controls.Add(this.renderPanel);
            this.Controls.Add(this.touchPanel);
            this.Name = "GameViewPanel";
            this.touchPanel.ResumeLayout(false);
            this.ResumeLayout(false);

        }
        #endregion

        #region Scroll management
        Point offset = new Point();
        protected virtual void InitScroll() {
            touchPanel.AutoScrollMinSize = this.contentSize;
            UpdateScrollParams(true);
            Rectangle r = VisibleBounce;
            int w = Math.Max(0, (this.contentSize.Width - r.Width) / 2);
            int h = Math.Max(0, (this.contentSize.Height - r.Height) / 2);
            touchPanel.AutoScrollPosition = new Point(w,h);
        }

        public Rectangle VisibleBounce {
            get {
                if (panelDummy != null) {
                    Control c = panelDummy;
                    Rectangle rect = c.RectangleToScreen(c.ClientRectangle);
                    Control c2 = c.Parent;
                    rect = Rectangle.Intersect(rect, c2.RectangleToScreen(c2.ClientRectangle));
                    rect = c.RectangleToClient(rect);
                    return rect;
                } else {
                    return touchPanel.ClientRectangle;
                }
            }
        }

        public void UpdateScrollParams(bool resized) {
            SuspendLayout();
            Rectangle rvw = VisibleBounce;
            if (resized) {
                Size szcl = ClientSize;
                Size szmap = this.contentSize;
                Debug.WriteLine("map="+szmap+", cln="+szcl);
                int w2 = szcl.Width / 2;
                int h2 = szcl.Height / 2;
                offset.X = Math.Max(0, (szmap.Width - rvw.Width) / 2);
                offset.Y = Math.Max(0, szmap.Height - rvw.Height / 2);
                Debug.Write(", ofst=" + offset);
                renderPanel.Size = rvw.Size;
            }
            Point pt = touchPanel.AutoScrollPosition;
            Debug.Write(", scrl=" + pt);
            pt.Offset(offset);
            if (ViewPointChanged != null) {
                ViewPointChanged(new ViewPointEventArgs(this,pt.X,pt.Y));
            }
            ResumeLayout(true);
            renderPanel.Refresh();
        }

        protected Point ControlToContentPosition(int x, int y) {
            Point p = touchPanel.AutoScrollPosition;
            return new Point(x-p.X,y-p.Y);
        }

        protected override void OnSizeChanged(EventArgs e) {
            base.OnSizeChanged(e);
            Rectangle r = VisibleBounce;
            UpdateScrollParams(true);
        }

        protected override void OnPaintBackground(PaintEventArgs e) {
        }
        #endregion


    }

    /// <summary>
    /// For scroll bar management
    /// </summary>
    class TouchPanel : Panel
    {
        public event ScrollEventHandler Scroll2;
        
        protected override void OnScroll(ScrollEventArgs se) {
            if (Scroll2 != null) {
                // Because of unknown reason, we should draw both before and after OnScroll.
                // otherwize the view does not redrawed by the latest scroll position.
                Scroll2(this, se);
                base.OnScroll(se);
                Scroll2(this, se);
            } else {
                base.OnScroll(se);
            }
        }

        protected override void OnPaint(PaintEventArgs e) {
        }

        protected override void OnPaintBackground(PaintEventArgs e) {
        }
    }
}
