
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using nft.framework.drawing;
using nft.core.game;
using nft.impl.game;
using nft.core.geometry;
using Geocon = nft.core.geometry.GeometricConstants;
using TPolygonSet = nft.impl.game.TerrainPieceTemplate.TerrainPolygonSet;
using nft.framework;
using nft.core;
using System.Diagnostics;
using System.Windows.Forms;

namespace nft.impl.view_old {
    public class MapViewDrawer : ViewDrawerBase, IQuarterView {
        static readonly long FrameCount = 64L * 27L * 25L * 7L * 11L * 13L * 17L * 19L * 23L * 29L * 31L * 37L;
        TerrainMapImpl map;
        Margin margin;
        ViewFactor factor;
        private ViewFactor prevFactor;
        SceneBuilder builder;
        ViewObjectList oblist;
        ISurfaceOld sfWork;
        List<Rectangle> dirtyRects;

        public MapViewDrawer(ITerrainMap srcmap) {
            if (!(srcmap is TerrainMapImpl)) {
                map = new TerrainMapImpl(srcmap);
            } else {
                map = srcmap as TerrainMapImpl;
            }
            oblist = new ViewObjectList();
            factor = new ViewFactor(InterCardinalDirection.SOUTHWEST,ZoomScale.x1);
            factor.ViewDirectionChanged += new EventHandler(OnViewFactorChanged);
            factor.ScaleChanged += new EventHandler(OnScaleChanged);
            margin = new Margin(Geocon.CellWidthPixel * 2, Geocon.CellHeightPixel * 32); 
            builder = new SceneBuilder(this, Screen.PrimaryScreen.Bounds.Size);
            IGraphicManagerOld gm = GlobalModules.GraphicManagerOld;
            sfWork = gm.CreateOffscreenSurface(Screen.PrimaryScreen.Bounds.Size);
            
            prevFactor = factor.Clone();
        }

        void OnScaleChanged(object sender, EventArgs e) {
            builder.SetViewFactor(ViewFactor);
            NotifyContentSizeChanged();
            prevFactor = ViewFactor.Clone();
        }

        void OnViewFactorChanged(object sender, EventArgs e) {
            builder.SetViewFactor(ViewFactor);
            NotifyAllUpdated(false);
        }

        #region IQuarterView implementation
        /// <summary>
        /// You can change actual view through the ViewFactor aquired by this getter.
        /// (ie. ViewFactor.Scale = ZoomScale.x1)
        /// </summary>
        public ViewFactor ViewFactor {
            get {
                return factor;
            }
        }

        public Control TargetControl {
            // this drawer should be assiosiated with single view only.
            get { 
                DrawablePanel dp = views[0] as DrawablePanel;
                if (dp != null) {
                    return dp.Canvas;
                } else {
                    return null;
                }
            }
        }

        internal protected CoordinationUtil CdUtil {
            get { return builder.CoordinationUtil; }
        }

        public Location GetHitSprite(IView v, Point pt, out object tag) {
            return builder.GetHitSprite(v, pt, out tag);
        }
        /*
        public Location ConvertMousePos(IView v, Point pt) {
            Point pv = v.ViewPosition;
            pv.Offset(pt);
            Location l = builder.GetVisibleGroundAtView(pv);
            return l;            
        }

        public Location ConvertMousePos(IView v, Point pt, int unitHeight) {
            Point pv = v.ViewPosition;
            pv.Offset(pt);
            Location l = CdUtil.QuarterXYToLocation(pv, unitHeight);
            return l;
        }

        public LocationF ConvertMousePosF(IView v, Point pt) {
            Point pv = v.ViewPosition;
            pv.Offset(pt);
            throw new NotImplementedException();
        }

        public LocationF ConvertMousePosF(IView v, Point pt, int pixelHeight) {
            Point pv = v.ViewPosition;
            pv.Offset(pt);
            LocationF l = CdUtil.QuarterXYToLocationF(pv, pixelHeight);
            return l;
        }
         */
        #endregion

        public override void Attach(IView view) {
            if(views.Count>0)
                throw new InvalidOperationException("Multi view not supported!");
            base.Attach(view);
            DrawablePanel c = view as DrawablePanel;
            c.Canvas.MouseMove += new MouseEventHandler(OnMouseMove);
        }

        void OnMouseMove(object sender, MouseEventArgs e) {
            /*
            Point pt = e.Location;
            Control c = sender as Control;
            Location l = ConvertMousePos(c.Parent as IView, pt);
             */
            Control c = (Control)sender;
            IView v = (IView)c.Parent;
            Point pv = e.Location;
            pv = c.PointToScreen(pv);
            pv = c.Parent.PointToClient(pv);
            object tag;
            Location l = GetHitSprite(v, pv, out tag);

            if (l != Location.UNPLACED) {
                string s;
                if (tag is ViewObject) {
                    s = ((ViewObject)tag).Bounds.ToString() ;
                } else {
                    s = l.ToString();
                }
                Main.mainFrame.SetStatusText(s);
            } else {
                Main.mainFrame.SetStatusText("");
            }
        }

        /// <summary>
        /// Extra margin of visible area.
        /// validate corresponding map area including this margin.
        /// </summary>
        public Margin VarlidationMargin {
            get { return margin; }
            set { margin = value; }
        }

        protected virtual void NotifyContentSizeChanged() {
            double v = ViewFactor.Scaler.Value / prevFactor.Scaler.Value;
            Size sz = ContentSize;
            // TODO: consider rotation
            foreach (IView vw in views) {
                Rectangle rectPrv = vw.VisibleSourceRect;
                int wo = rectPrv.Width >> 1;
                int ho = rectPrv.Height >> 1;
                Point pos = vw.ViewPosition;
                pos.Offset(wo , ho);
                pos.X = (int)(pos.X * v);
                pos.Y = (int)(pos.Y * v);
                pos.Offset(-wo, -ho);
                vw.NotifyContentSizeChanged(pos);
            }
        }

        #region IViewDrawer implementation
        protected override void DrawCore(ISurfaceOld surfDest, Graphics g, IView owner, Rectangle rctDest, Region requestSrc) {
            int t1 = System.Environment.TickCount;
            int t2;
            surfDest.Clear(rctDest, Color.Navy);
            Rectangle rectReq = Rectangle.Round(requestSrc.GetBounds(g));
            int n;
            builder.Prepare(rectReq, oblist);
            t2 = System.Environment.TickCount;
            t1 = t2 - t1;
            builder.Draw(owner, surfDest, rctDest);
            n = builder.drawCells;
            t2 = System.Environment.TickCount - t2;
#if DEBUG
            Debug.WriteLine("Draw ticks=" + t1 + "," + t2 + ": dest=" + rctDest + ", cells="+ n);
#else
            Console.WriteLine("Draw ticks=" + t1 + "," + t2 + ": dest=" + rctDest+ ", cells="+ n);
#endif
        }

        internal protected TerrainMapImpl TerrainMap { get { return map; } }

        public Size3D WorldSize {
            get { return map.Size; }
        }

        public override Size ContentSize {
            get {
                return builder.ContentSize;
            }
        }

        public ViewObjectList ViewObjects {
            get { return oblist; }
        }

        public override Size ScrollUnit {
            get {
                int u = Geocon.CellWidthPixel;
                Size sz = new Size(u, u >> 1);
                factor.Scaler.Scale(ref sz);
                return sz;
            }
        }

        protected override void Dispose(bool disposing) {
            base.Dispose(disposing);
            if (disposing) {
                map = null;
                if (builder != null) {
                    builder.Dispose();
                }
            }
        }
        #endregion

    }
}
