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

using Geocon = nft.core.geometry.GeometricConstants;
using nft.framework.drawing;
namespace nft.core.geometry {
    /// <summary>
    /// Hexagonal bounds of cube on QuarterView serface
    /// </summary>
    public class QVCubeSilhouette {
        static private int[][] matrix;
        static QVCubeSilhouette() {
            matrix = new int[4][];
            matrix[Direction.ToZeroBaseIndex(InterCardinalDirection.NORTHEAST)] 
                = new int[]{0,0,0,0};
        }

        public enum Vertex : int { Bottom, LowerLeft, UpperLeft, Top, UpperRight, LowerRight };
        private Point[] vertices;

        public static QVCubeSilhouette FromRect(Rect3D rect, Size3D worldSize, ViewFactor vf ) {
            Point pt = CoordinationUtil.Create(worldSize,vf).LocationToQuarterXY(rect.Location);
            return FromPosAndSize(pt, rect.Size, vf);
        }

        public static QVCubeSilhouette FromPosAndSize(Point org, Size3D sz, ViewFactor vf) {
            Point[] vertices = new Point[6];
            int x = org.X;
            int y = org.Y;
            // argument of Create needs world size. 
            // but this method does not effected by it. So give dummy one.
            Size3DV szv = CoordinationUtil.Create(sz,vf).RotatedForViewAxis(sz);
            int uh = vf.Scaler.Scale(Geocon.UnitHeightPixel);
            int uw = vf.Scaler.Scale(Geocon.UnitWidthPixel);
            int vx = szv.VX * uw;
            int vy = szv.VY * uw;
            int vz = szv.VZ * uh;
            Point top = new Point(x + vx - vy, y + vx + vy + vz);
            vertices[(int)Vertex.Bottom] = new Point(x, y);
            vertices[(int)Vertex.Top] = top;
            vertices[(int)Vertex.LowerLeft] = new Point(x - vy, y - (vy>>1));
            vertices[(int)Vertex.LowerRight] = new Point(x + vx, y - (vx >> 1));
            vertices[(int)Vertex.UpperLeft] = new Point(top.X - vx, top.Y + (vx >> 1));
            vertices[(int)Vertex.UpperRight] = new Point(top.X + vy, top.Y + (vy >> 1));
            return new QVCubeSilhouette(vertices);
        }

        private QVCubeSilhouette(Point[] ps) {
            this.vertices = ps;
        }

        public Point this[Vertex v] {
            get {
                return vertices[(int)v];
            }
        }

        public Rectangle RectBounds {
            get {
                int x1 = this[Vertex.LowerLeft].X;
                int y1 = this[Vertex.Top].Y;
                int x2 = this[Vertex.LowerRight].X;
                int y2 = this[Vertex.Bottom].Y;
                return new Rectangle(x1,y1,x2-x1,y2-y1);
            }
        }

        public bool IntersectWith(Rectangle rect) {
            return RectBounds.IntersectsWith(rect);
        }
        // memo y=y_0-r(x_0-x_)
        public bool IntersectWith(QVCubeSilhouette other) {
            int x1 = this[Vertex.LowerLeft].X;
            int x2 = this[Vertex.LowerRight].X;
            if (x1 <= other[Vertex.UpperRight].X && x2 >= other[Vertex.LowerLeft].X) {
                int y1 = this[Vertex.Top].Y;
                int y2 = this[Vertex.Bottom].Y;
                if (y1 <= other[Vertex.Bottom].Y && y2 >= other[Vertex.Top].Y) {
                    int h1 = other[Vertex.Bottom].Y - ((other[Vertex.Bottom].X - x1) >> 1);
                    int h2 = other[Vertex.Top].Y - ((other[Vertex.Top].X - x2) >> 1);
                    if (h1 >= this[Vertex.UpperLeft].Y && h2 <= this[Vertex.LowerRight].Y) {
                        h1 = other[Vertex.Bottom].Y + ((other[Vertex.Bottom].X - x2) >> 1);
                        h2 = other[Vertex.Top].Y + ((other[Vertex.Top].X-x1) >> 1);
                        if (h1 >= this[Vertex.UpperLeft].Y && h2 <= this[Vertex.LowerRight].Y) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public bool HitTest(Point p) {
            return HitTest(p.X, p.Y);
        }

        public bool HitTest(int x, int y) {
            int x1 = this[Vertex.LowerLeft].X;
            int y1 = this[Vertex.Top].Y;
            int x2 = this[Vertex.LowerRight].X;
            int y2 = this[Vertex.Bottom].Y;
            if (x >= x1 && x <= x2 && y >= y1 && y <= y2) {
                int h = y - ((x - x1) >> 1);
                if (h >= this[Vertex.UpperLeft].Y && h <= (y2 << 1) - this[Vertex.LowerLeft].Y) {
                    h = y + ((x - x2) >> 1);
                    if (h >= this[Vertex.UpperRight].Y && h <= (y2 << 1) - this[Vertex.LowerRight].Y) {
                        return true;
                    }
                }
            }
            return false;
        }

    }
}
