using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace nft.framework.drawing
{
    public struct Point3D
    {
        public int X, Y, Z;
        public Point3D(int x, int y, int z) {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }

        /// <summary>
        /// Convert array of Location objects into 2D projected Point array.
        /// </summary>
        /// <param name="locs"></param>
        /// <param name="bounds"></param>
        /// <returns></returns>
        public static Point[] ConvertToQuarterViewPos(Point3D[] locs, ref Rectangle bounds) {
            int n = locs.Length;
            Point[] pt = new Point[n];
            Point minP = new Point(int.MaxValue, int.MaxValue);
            Point maxP = new Point(int.MinValue, int.MinValue);
            for (int i = 0; i < n; i++) {
                int x = locs[i].X - locs[i].Y;
                int y = -locs[i].Z - (locs[i].X + locs[i].Y) / 2;
                minP.X = Math.Min(minP.X, x);
                maxP.X = Math.Max(maxP.X, x);
                minP.Y = Math.Min(minP.Y, y);
                maxP.Y = Math.Max(maxP.Y, y);
                pt[i].X = x;
                pt[i].Y = y;
            }
            bounds.Location = minP;
            bounds.Width = maxP.X - minP.X;
            bounds.Height = maxP.Y - minP.Y;
            return pt;
        }

        public override string ToString() {
            return "Point3D(" + X + "," + Y + "," + Z + ")";
        }
    }

    public struct PointF3D
    {
        public float X, Y, Z;
        public PointF3D(float x, float y, float z) {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }
        public PointF3D(Point3D p) {
            this.X = p.X;
            this.Y = p.Y;
            this.Z = p.Z;
        }

        public override string ToString() {
            return "PointF3D("+X+","+Y+","+Z+")";
        }

        Point3D Ceiling() {
            return new Point3D((int)Math.Ceiling(X), (int)Math.Ceiling(Y), (int)Math.Ceiling(Z));
        }

        Point3D Floor() {
            return new Point3D((int)Math.Floor(X), (int)Math.Floor(Y), (int)Math.Floor(Z));
        }
    }

    /// <summary>
    /// Instance Recycle(Reuse) is recommended for Memory saving purpos.
    /// </summary>
    public interface I3DObject //: IDisposable
    {
        UInt32 ID { get; set; }
        //object Tag { get; set; }
        IEffectFilter Effect { get; set; }
        float DepthBias { get; set; }
    }

    public interface IEffectFilter{
    }

    public interface ITerrainPlateTemplate : IDisposable
    {
    }

    public interface ITerrainPlate : I3DObject
    {
        PointF3D Location { get; set; }
        /// <summary>
        /// Must be the same one as given when this instance has created.
        /// </summary>
        ITerrainPlateTemplate Template { get; }
    }

    public interface ICubicStructure : I3DObject
    {
        PointF3D Location { get; set; }
    }

    public interface IBillboard : I3DObject
    {
        ICubicStructure Anchor { get; set; }
        PointF3D Offset { get; set; }
    }

    public interface IOverlay : I3DObject
    {
        Point Offset { get; set; }
    }
}
