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

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

        private double irad, mrad;
        private int hdiv, vdiv;

        #region Properties
        public double InnerRadius {
            get { return irad; }
            set { irad = value; }
        }

        public double MarginRadius {
            get { return mrad; }
            set { mrad = value; }
        }

        public int Hdiv {
            get { return hdiv; }
            set { hdiv = value; }
        }

        public int Vdiv {
            get { return vdiv; }
            set { vdiv = value; }
        }
        #endregion

        public Torus(double irad, double mrad, int hdiv, int vdiv, Point3D ct) {
            this.irad = irad;
            this.mrad = mrad;
            this.hdiv = hdiv;
            this.vdiv = vdiv;
            if (ct == null) this.center = new Point3D(0.0, 0.0, 0.0); else this.center = ct;
            this.e1 = new Point3D(irad, 0.0, 0.0);
            this.e2 = new Point3D(0.0, irad, 0.0);
            this.e3 = new Point3D(0.0, 0.0, mrad);
            this.UpperCorner = new Point3D(irad + 2 * mrad, irad + 2 * mrad, mrad);
            this.LowerCorner = new Point3D(-irad - 2 * mrad, -irad - 2 * mrad, -mrad);
            MeshTesselation();
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext context) {
            base.GetObjectData(info, context);
            info.AddValue("IRadius", irad);
            info.AddValue("MRadius", mrad);
            info.AddValue("HDiv", hdiv);
            info.AddValue("VDiv", vdiv);
        }

        public Torus(SerializationInfo info, StreamingContext context) : base(info, context) {
            irad = info.GetDouble("IRadius");
            mrad = info.GetDouble("MRadius");            
            hdiv = info.GetInt32("HDiv");
            vdiv = info.GetInt32("VDiv");            
        }

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

        public override void MeshTesselation() {
            mesh = new BRep();
            double hstep = 360.0 / (double)hdiv;
            double vstep = 360.0 / (double)vdiv;
            double a = hstep * Math.PI / 180.0;
            double b = vstep * Math.PI / 180.0;

            // A tórusz pontjainak kiszámítása
            for (double u1 = 0; u1 < hdiv; u1 += 1) {
                for (double u2 = 0; u2 < vdiv; u2 += 1) {
                    mesh.Vertices.Add(new Point3D(
                        (irad + mrad * Math.Cos(u2 * b)) * Math.Cos(u1 * a),
                        (irad + mrad * Math.Cos(u2 * b)) * Math.Sin(u1 * a),
                        mrad * Math.Sin(u2 * b)));
                }
            }

            // Az élek meghatározása
            for (int i = 0; i < hdiv; ++i) {
                for (int j = 0; j < vdiv; ++j) {
                    mesh.Edges.Add(new Edge(i * vdiv + j, ((i + 1) % hdiv) * vdiv + j));
                    mesh.Edges.Add(new Edge(i * vdiv + j, i * vdiv + ((j + 1) % vdiv)));
                }
            }

            // A lapok meghatározása
            for (int i = 0; i < hdiv; ++i) {
                for (int j = 0; j < vdiv; ++j) {
                    mesh.Faces.Add(new Face(((i + 1) % hdiv) * vdiv + ((j + 1) % vdiv), 
                        i * vdiv + j, ((i + 1) % hdiv) * vdiv + j));
                    mesh.Faces.Add(new Face(i * vdiv + ((j + 1) % vdiv), i * vdiv + j, 
                        ((i + 1) % hdiv) * vdiv + ((j + 1) % vdiv)));
                }
            }
        }

        public override void ChangeParams() {
            NewTorus ns = new NewTorus();
            ns.Text = "Modify Torus";
            ns.tbInnerRad.Text = this.InnerRadius.ToString();
            ns.tbMarginRad.Text = this.MarginRadius.ToString();
            ns.tbHdiv.Text = this.Hdiv.ToString();
            ns.tbVdiv.Text = this.Vdiv.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.irad = ns.irad;
            this.mrad = ns.mrad;
            this.hdiv = ns.hdiv;
            this.vdiv = ns.vdiv;
            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);
            this.e1 = new Point3D(irad, 0.0, 0.0);
            this.e2 = new Point3D(0.0, irad, 0.0);
            this.e3 = new Point3D(0.0, 0.0, mrad);
            this.UpperCorner = new Point3D(irad + 2 * mrad, irad + 2 * mrad, mrad);
            this.LowerCorner = new Point3D(-irad - 2 * mrad, -irad - 2 * mrad, -mrad);
            base.ChangeParams();
        }
    }
}
