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

using Spark3D.Algebra3D;
using Spark3D.Objects3D;

namespace Spark3D.Projector3D
{
    public abstract class ProjectorCommon : IProjector3D
    {
        protected Matrix3D Rotation;
        protected Vector3D CameraPosition;
        protected double ScaleX;
        protected double ScaleY;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="FieldOfViewX">In degrees</param>
        /// <param name="FieldOfViewY">In degrees</param>
        public ProjectorCommon()
        {
            FieldOfView = 0.1;
        }

        public double FieldOfView
        {
            set
            {
                ScaleX = 1.0 / Math.Tan(value * Math.PI / 180.0);
                ScaleY = 1.0 / Math.Tan(value * Math.PI / 180.0);

            }
        }

        public abstract void MoveView(Vector3D angles);

        public void MoveView(double distance)
        {
            CameraPosition = new Vector3D(0, 0, distance);
        }

        public abstract ProjectedPoint Project(Vector3D p3);

        public Polygon2D Project(Polygon3D p3d)
        {
            int N = p3d.NumVerticies;
            Point[] verticies2D = new Point[N];
            int i = 0;
            double avgZ = 0.0;
            foreach (Vector3D v in p3d.itsVerticies)
            {
                ProjectedPoint pp = Project(v);
                verticies2D[i++] = pp.itsPoint;
                avgZ += pp.its3DPoint[2];
            }
            avgZ /= (double)N;
            return new Polygon2D(verticies2D, p3d.Colour(CameraPosition, Rotation), avgZ);
        }

        public IList<Polygon2D> Project(IList<Polygon3D> p3s)
        {
            List<Polygon2D> ret = new List<Polygon2D>();
            foreach (Polygon3D p3 in p3s)
                ret.Add(Project(p3));

            // Fancy syntax to sort by Z value.
            // We want to draw the ones at the back first, so they get overlayed by the ones in front.
            ret.Sort(delegate(Polygon2D p1, Polygon2D p2)
           {
               return Comparer<double>.Default.Compare(p1.itsZ, p2.itsZ);
           });
            return ret;
        }

    }
}
