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

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

        private double edgelen;

        public double EdgeLength {
            get { return edgelen; }
            set { edgelen = value; }
        }

        public Icosahedron(double edgelen, Point3D ct) {
            this.edgelen = edgelen;
            if (ct == null) this.center = new Point3D(0.0, 0.0, 0.0); else this.center = ct;
            // A tengelyek irányvektorai
            double l = (0.5 + Math.Sqrt(5.0 / 4.0)) * edgelen;
            this.e1 = new Point3D(l / 2, 0.0, 0.0);
            this.e2 = new Point3D(0.0, l / 2, 0.0);
            this.e3 = new Point3D(0.0, 0.0, l / 2);
            // A befoglaló téglatest
            this.UpperCorner = new Point3D(l / 2, l / 2, l / 2);
            this.LowerCorner = new Point3D(-l / 2, -l / 2, -l / 2);
            // A primitív tesszellációja
            MeshTesselation();
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext context) {
            base.GetObjectData(info, context);
            info.AddValue("EdgeLength", edgelen);
        }

        public Icosahedron(SerializationInfo info, StreamingContext context) : base(info, context) {
            edgelen = info.GetDouble("EdgeLength");
        }

        public override string SolidType() {
            return "Icosahedron";
        }

        public override void MeshTesselation() {
            mesh = new BRep();

            double l = (0.5 + Math.Sqrt(5.0 / 4.0)) * edgelen;

            // Csúcsok
            #region Vertices
            mesh.Vertices.Add(new Point3D(-edgelen / 2, 0, l / 2));  // 0
            mesh.Vertices.Add(new Point3D(edgelen / 2, 0, l / 2));   // 1
            mesh.Vertices.Add(new Point3D(-edgelen / 2, 0, -l / 2)); // 2
            mesh.Vertices.Add(new Point3D(edgelen / 2, 0, -l / 2));  // 3
            mesh.Vertices.Add(new Point3D(0, l / 2, -edgelen / 2));  // 4 
            mesh.Vertices.Add(new Point3D(0, l / 2, edgelen / 2));   // 5
            mesh.Vertices.Add(new Point3D(0, -l / 2, edgelen / 2));  // 6
            mesh.Vertices.Add(new Point3D(0, -l / 2, -edgelen / 2)); // 7
            mesh.Vertices.Add(new Point3D(-l / 2, -edgelen / 2, 0)); // 8
            mesh.Vertices.Add(new Point3D(-l / 2, edgelen / 2, 0));  // 9
            mesh.Vertices.Add(new Point3D(l / 2, -edgelen / 2, 0));  // 10
            mesh.Vertices.Add(new Point3D(l / 2, edgelen / 2, 0));   // 11
            #endregion

            // Élek
            #region Edges
            mesh.Edges.Add(new Edge(0, 1));
            mesh.Edges.Add(new Edge(0, 5));
            mesh.Edges.Add(new Edge(0, 9));
            mesh.Edges.Add(new Edge(0, 8));
            mesh.Edges.Add(new Edge(0, 6));

            mesh.Edges.Add(new Edge(1, 6));
            mesh.Edges.Add(new Edge(1, 10));
            mesh.Edges.Add(new Edge(1, 11));
            mesh.Edges.Add(new Edge(1, 5));

            mesh.Edges.Add(new Edge(2, 3));
            mesh.Edges.Add(new Edge(2, 4));
            mesh.Edges.Add(new Edge(2, 7));
            mesh.Edges.Add(new Edge(2, 8));
            mesh.Edges.Add(new Edge(2, 9));

            mesh.Edges.Add(new Edge(3, 4));
            mesh.Edges.Add(new Edge(3, 7));
            mesh.Edges.Add(new Edge(3, 10));
            mesh.Edges.Add(new Edge(3, 11));

            mesh.Edges.Add(new Edge(4, 5));
            mesh.Edges.Add(new Edge(6, 7));
            mesh.Edges.Add(new Edge(8, 9));
            mesh.Edges.Add(new Edge(10, 11));

            mesh.Edges.Add(new Edge(5, 9));
            mesh.Edges.Add(new Edge(5, 11));
            mesh.Edges.Add(new Edge(4, 9));
            mesh.Edges.Add(new Edge(4, 11));

            mesh.Edges.Add(new Edge(6, 8));
            mesh.Edges.Add(new Edge(6, 10));
            mesh.Edges.Add(new Edge(7, 8));
            mesh.Edges.Add(new Edge(7, 10));

            #endregion

            // Lapok
            #region Faces
            mesh.Faces.Add(new Face(0, 8, 6));
            mesh.Faces.Add(new Face(0, 9, 8));
            mesh.Faces.Add(new Face(0, 5, 9));
            mesh.Faces.Add(new Face(0, 1, 5));

            mesh.Faces.Add(new Face(1, 10, 11));
            mesh.Faces.Add(new Face(1, 6, 10));
            mesh.Faces.Add(new Face(1, 0, 6));

            mesh.Faces.Add(new Face(9, 2, 8));
            mesh.Faces.Add(new Face(9, 4, 2));
            mesh.Faces.Add(new Face(9, 5, 4));

            mesh.Faces.Add(new Face(5, 11, 4));
            mesh.Faces.Add(new Face(4, 3, 2));
            mesh.Faces.Add(new Face(3, 11, 10));
            mesh.Faces.Add(new Face(6, 8, 7));
            mesh.Faces.Add(new Face(7, 10, 6));

            mesh.Faces.Add(new Face(7, 2, 3));
            mesh.Faces.Add(new Face(11, 5, 1));
            mesh.Faces.Add(new Face(11, 3, 4));
            mesh.Faces.Add(new Face(2, 7, 8));
            mesh.Faces.Add(new Face(3, 10, 7));

            #endregion

            // a lapok további felosztása
            //ProcessLongFaces();
        }

        public override void ChangeParams() {
            NewIcosahedron ns = new NewIcosahedron();
            ns.Text = "Modify Icosahedron";
            ns.tbEdgeLength.Text = this.EdgeLength.ToString();
            if (this.center.X != 0.0 || this.center.Y != 0.0 || this.center.Z != 0.0) {
                ns.cbCenter.Checked = false;
                ns.tbCX.Text = this.center.X.ToString();
                ns.tbCY.Text = this.center.Y.ToString();
                ns.tbCZ.Text = this.center.Z.ToString();
            } else ns.cbCenter.Checked = true;
            if (ns.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) return;
            this.edgelen = ns.edgelen;
            if (ns.cbCenter.Checked)
                this.center = new Point3D(0.0, 0.0, 0.0);
            else
                this.center = new Point3D(ns.cx, ns.cy, ns.cz);
            double l = (0.5 + Math.Sqrt(5.0 / 4.0)) * edgelen;
            this.e1 = new Point3D(l, 0.0, 0.0);
            this.e2 = new Point3D(0.0, l, 0.0);
            this.e3 = new Point3D(0.0, 0.0, l);
            // A befoglaló téglatest
            this.UpperCorner = new Point3D(l / 2, l / 2, l / 2);
            this.LowerCorner = new Point3D(-l / 2, -l / 2, -l / 2);
            // A primitív tesszellációja
            base.ChangeParams();
        }

    }
}
