using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;

namespace CSGBuilder {
    [Serializable()]
    public class Solid : ISerializable {
        public static int pcounter = 1;

        protected BRep mesh;    // a poligonháló

        // a lokális koordináta-rendszer egységvektorai
        protected Point3D e1;
        protected Point3D e2;
        protected Point3D e3;

        // A befoglaló téglatest két sarka
        protected Point3D lowerCorner, upperCorner;

        // A test középpontja
        protected Point3D center;
                
        #region Public properties

        public BRep Mesh {
            get { return mesh; }
            set { mesh = value; }
        }

        public Point3D E1 {
            get { return e1; }
            set { e1 = value; }
        }

        public Point3D E2 {
            get { return e2; }
            set { e2 = value; }
        }

        public Point3D E3 {
            get { return e3; }
            set { e3 = value; }
        }

        public Point3D Center {
            get { return center; }
            set { center = value; }
        }

        public Point3D UpperCorner {
            get { return upperCorner; }
            set { upperCorner = value; }
        }

        public Point3D LowerCorner {
            get { return lowerCorner; }
            set { lowerCorner = value; }
        }
        #endregion

        public Solid() {
        }

        #region ISerializable Members

        public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
            info.AddValue("Mesh", mesh);
            info.AddValue("E1", e1);
            info.AddValue("E2", e2);
            info.AddValue("E3", e3);
            info.AddValue("LowerCorner", lowerCorner);
            info.AddValue("UpperCorner", upperCorner);
            info.AddValue("Center", center);
        }

        protected Solid(SerializationInfo info, StreamingContext context) {
            mesh = (BRep)info.GetValue("Mesh", typeof(BRep));
            e1 = (Point3D)info.GetValue("E1", typeof(Point3D));
            e2 = (Point3D)info.GetValue("E2", typeof(Point3D));
            e3 = (Point3D)info.GetValue("E3", typeof(Point3D));
            lowerCorner = (Point3D)info.GetValue("LowerCorner", typeof(Point3D));
            upperCorner = (Point3D)info.GetValue("UpperCorner", typeof(Point3D));
            center = (Point3D)info.GetValue("Center", typeof(Point3D));
        }        

        #endregion

        public virtual string SolidType() {
            return "Solid";
        }

        public virtual void MeshTesselation() {
        }

        public virtual void ChangeParams() {
            System.Drawing.Color vc = mesh.Vertices[0].Color;
            System.Drawing.Color ec = mesh.Edges[0].Color;
            System.Drawing.Color fc = mesh.Faces[0].Color;
            MeshTesselation();
            foreach (Point3D p in mesh.Vertices) p.Color = vc;
            foreach (Edge e in mesh.Edges) e.Color = ec;
            foreach (Face f in mesh.Faces) f.Color = fc;
            MainForm.Saved = false;
        }
      
        // Két pont távolsága
        protected double Dist(Point3D p1, Point3D p2) {
            return Math.Sqrt(
                (p1.X - p2.X) * (p1.X - p2.X) +
                (p1.Y - p2.Y) * (p1.Y - p2.Y) +
                (p1.Z - p2.Z) * (p1.Z - p2.Z));
        }

        protected Face DivNeed() {
            foreach (Face f in mesh.Faces) {
                if (Dist(mesh.Vertices[f[0]], mesh.Vertices[f[1]]) > 50) return f;
                if (Dist(mesh.Vertices[f[1]], mesh.Vertices[f[2]]) > 50) return f;
                if (Dist(mesh.Vertices[f[0]], mesh.Vertices[f[2]]) > 50) return f;
            }
            return null;
        }

        public void ProcessLongFaces() {
            Face f;
            int max;
            double maxDist, n;
            while ((f = DivNeed()) != null) {
                maxDist = 0.0; max = 0;
                if ((n = Dist(mesh.Vertices[f[0]], mesh.Vertices[f[1]])) > maxDist) { maxDist = n; max = 0; }
                if ((n = Dist(mesh.Vertices[f[1]], mesh.Vertices[f[2]])) > maxDist) { maxDist = n; max = 1; }
                if ((n = Dist(mesh.Vertices[f[0]], mesh.Vertices[f[2]])) > maxDist) { maxDist = n; max = 2; }
                switch (max) {
                    case 0:
                        mesh.Vertices.Add((mesh.Vertices[f[0]] + mesh.Vertices[f[1]]) / 2);
                        mesh.Faces.Add(new Face(f[0], mesh.Vertices.Count - 1, f[2]));
                        mesh.Faces.Add(new Face(mesh.Vertices.Count - 1, f[1], f[2]));
                        mesh.Faces.Remove(f);
                        mesh.Edges.Add(new Edge(f[0], mesh.Vertices.Count - 1));
                        mesh.Edges.Add(new Edge(mesh.Vertices.Count - 1, f[1]));
                        mesh.Edges.Add(new Edge(mesh.Vertices.Count - 1, f[2]));
                        mesh.Edges.Remove(new Edge(f[0], f[1]));
                        break;
                    case 1:
                        mesh.Vertices.Add((mesh.Vertices[f[1]] + mesh.Vertices[f[2]]) / 2);
                        mesh.Faces.Add(new Face(f[0], f[1], mesh.Vertices.Count - 1));
                        mesh.Faces.Add(new Face(f[0], mesh.Vertices.Count - 1, f[2]));
                        mesh.Faces.Remove(f);
                        mesh.Edges.Add(new Edge(f[1], mesh.Vertices.Count - 1));
                        mesh.Edges.Add(new Edge(mesh.Vertices.Count - 1, f[2]));
                        mesh.Edges.Add(new Edge(mesh.Vertices.Count - 1, f[0]));
                        mesh.Edges.Remove(new Edge(f[1], f[2]));
                        break;
                    case 2:
                        mesh.Vertices.Add((mesh.Vertices[f[2]] + mesh.Vertices[f[0]]) / 2);
                        mesh.Faces.Add(new Face(f[0], f[1], mesh.Vertices.Count - 1));
                        mesh.Faces.Add(new Face(f[1], f[2], mesh.Vertices.Count - 1));
                        mesh.Faces.Remove(f);
                        mesh.Edges.Add(new Edge(f[2], mesh.Vertices.Count - 1));
                        mesh.Edges.Add(new Edge(mesh.Vertices.Count - 1, f[0]));
                        mesh.Edges.Add(new Edge(mesh.Vertices.Count - 1, f[1]));
                        mesh.Edges.Remove(new Edge(f[2], f[0]));
                        break;
                }
            }
        }

    }
}
