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

namespace CSGBuilder {
    [Serializable()]
    class Rotation : Transformation, ISerializable {
        // A forgatási tengely kezdő- és végpontja
        private Point3D sp, ep;
        // A forgatás szöge
        private double angle;

        #region Properties
        public Point3D Sp {
            get { return sp; }
            set { sp = value; }
        }

        public Point3D Ep {
            get { return ep; }
            set { ep = value; }
        }

        public double Angle {
            get { return angle; }
            set { angle = value; }
        }
        #endregion

        public Rotation(Point3D sp, Point3D ep, double angle) {
            this.sp = sp;
            this.ep = ep;
            this.angle = angle;
            SetMatrix();
        }

        public override string Type() {
            return "Rotation";
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext context) {
            base.GetObjectData(info, context);
            info.AddValue("Sp", sp);
            info.AddValue("Ep", ep);
            info.AddValue("Angle", angle);
        }

        public Rotation(SerializationInfo info, StreamingContext context) : base(info, context) {
            sp = (Point3D)info.GetValue("Sp", typeof(Point3D));
            ep = (Point3D)info.GetValue("Ep", typeof(Point3D));
            angle = info.GetDouble("Angle");
        }
        
        // Elkészíti a transzformációs mátrixot
        public override void SetMatrix() {
            double delta = angle * Math.PI / 180;

            double h = Math.Sqrt((ep.X - sp.X) * (ep.X - sp.X) + 
                (ep.Y - sp.Y) * (ep.Y - sp.Y) + (ep.Z - sp.Z) * (ep.Z - sp.Z));
            double cx = (ep.X - sp.X) / h;
            double cy = (ep.Y - sp.Y) / h;
            double cz = (ep.Z - sp.Z) / h;
            double d = Math.Sqrt(cz * cz + cy * cy);

            double cx2 = cx * cx;
            double cy2 = cy * cy;
            double cz2 = cz * cz;
            double d2 = d * d;

            Matrix t = new Matrix(4, 4);
            t.LoadIdentity();
            t[0, 3] = -sp.X;
            t[1, 3] = -sp.Y;
            t[2, 3] = -sp.Z;

            Matrix rx = new Matrix(4, 4);
            rx.LoadIdentity();
            if (d != 0) {
                rx[1, 1] = cz / d;
                rx[1, 2] = -cy / d;
                rx[2, 1] = cy / d;
                rx[2, 2] = cz / d;
            }

            Matrix ry = new Matrix(4, 4);
            ry.LoadIdentity();
            ry[0, 0] = d;
            ry[0, 2] = -cx;
            ry[2, 0] = cx;
            ry[2, 2] = d;

            Matrix rz = new Matrix(4, 4);
            rz.LoadIdentity();
            rz[0, 0] = Math.Cos(delta);
            rz[0, 1] = -Math.Sin(delta);
            rz[1, 0] = Math.Sin(delta);
            rz[1, 1] = Math.Cos(delta);

            TrMatrix = t.Trans() * rx.Trans() * ry.Trans() * rz * ry * rx * t;

        }

        public override string ToString() {
            return "Rotation: Axis points: " + sp.ToString() + " - " + ep.ToString() + "  Angle: " + angle.ToString("F2");
        }
    }
}
