using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Jitter.LinearMath;
using Jitter.Collision;

namespace KinPortal {
	public class Geometry {
		public List<Vector3> Vertices {get; private set;}
		public List<ushort> Indices {get; private set;}

		public BoundingBox Box {
			get {
				return BoundingBox.CreateFromPoints(Vertices);
			}
		}

		public BoundingSphere Sphere {
			get {
				return BoundingSphere.CreateFromPoints(Vertices);
			}
		}

		public List<JVector> JVertices {
			get {
				List<JVector> vertices = new List<JVector>();
				foreach(Vector3 vert in Vertices) {
					vertices.Add(GetJitterVector(vert));
				}
				return vertices;
			}
		}

		public List<TriangleVertexIndices> JTriangles {
			get {
				List<TriangleVertexIndices> triangles = new List<TriangleVertexIndices>();
				for(int i = 0; i < Indices.Count / 3; i++) {
					triangles.Add(new TriangleVertexIndices(
						Indices[i * 3 + 0],
						Indices[i * 3 + 1],
						Indices[i * 3 + 2]
					));
				}
				return triangles;
			}
		}

		public Geometry(Model model) {
			Vertices = new List<Vector3>();
			Indices = new List<ushort>();

			Matrix[] bones = new Matrix[model.Bones.Count];
			model.CopyAbsoluteBoneTransformsTo(bones);
			foreach (ModelMesh mm in model.Meshes) {
				Matrix bone = bones[mm.ParentBone.Index];
				foreach (ModelMeshPart mmp in mm.MeshParts) {
					int offset = Vertices.Count;
					Vector3[] verts = new Vector3[mmp.NumVertices];
					mmp.VertexBuffer.GetData<Vector3>(mmp.VertexOffset * mmp.VertexBuffer.VertexDeclaration.VertexStride,
					verts, 0, mmp.NumVertices, mmp.VertexBuffer.VertexDeclaration.VertexStride);
					Vector3.Transform(verts, ref bone, verts);
					Vertices.AddRange(verts);

					ushort[] indices = new ushort[mmp.PrimitiveCount * 3];
					mmp.IndexBuffer.GetData<ushort>(mmp.StartIndex * 2, indices, 0, mmp.PrimitiveCount * 3);
					TriangleVertexIndices[] tvi = new TriangleVertexIndices[mmp.PrimitiveCount];
					for (int i = 0; i != indices.Length; i++) {
						indices[i] += (ushort) offset;
					}
					Indices.AddRange(indices);
				}
			}
		}

		public static Matrix GetXnaMatrix(JMatrix jmat) {
			return new Matrix(
				jmat.M11, jmat.M12, jmat.M13, 0.0f,
				jmat.M21, jmat.M22, jmat.M23, 0.0f,
				jmat.M31, jmat.M32, jmat.M33, 0.0f,
				0.0f, 0.0f, 0.0f, 1.0f
			);
		}

		public static JMatrix GetJitterMatrix(Matrix xmat) {
			return new JMatrix(
				xmat.M11, xmat.M12, xmat.M13,
				xmat.M21, xmat.M22, xmat.M23,
				xmat.M31, xmat.M32, xmat.M33
			);
		}

		public static Vector3 GetXnaVector(JVector jvec) {
			return new Vector3(jvec.X, jvec.Y, jvec.Z);
		}

		public static JVector GetJitterVector(Vector3 xvec) {
			return new JVector(xvec.X, xvec.Y, xvec.Z);
		}

		public static Quaternion GetRelativeRotation(Vector3 u, Vector3 v) {
			Quaternion rot;
			if(u == v) {
				rot = Quaternion.Identity;
			} else if(u == (-v)) {
				rot = Quaternion.CreateFromAxisAngle(GetOrthogonalVector(u), (float) Math.PI);
			} else {
				rot = Quaternion.CreateFromAxisAngle(Vector3.Cross(u, v), (float) Math.Acos(Vector3.Dot(u, v)));
			}
			return rot;
		}

		public static Vector3 GetRotationAxis(Quaternion rot) {
			Vector3 axis = new Vector3(rot.X, rot.Y, rot.Z);
			Vector3 naxis = Vector3.Normalize(axis);
			return naxis;
		}

		public static Vector3 GetOrthogonalVector(Vector3 vec) {
			Vector3 v;
			if(vec.X != 0) {
				v = new Vector3((-(vec.Y)-(vec.Z))/vec.X, 1, 0);
			} else if(vec.Y != 0) {
				v = new Vector3(1, (-(vec.Z)-(vec.X))/vec.Y, 0);
			} else if(vec.Z != 0) {
				v = new Vector3(1, 0, (-(vec.X)-(vec.Y))/vec.Z);
			} else {
				v = Vector3.Zero;
			}
			return Vector3.Normalize(v);
		}
	}
}

/*public static void GetJitterModelTriangles(Model model, List<JVector> vertices, List<TriangleVertexIndices> triangles) {
			Matrix[] bones = new Matrix[model.Bones.Count];
			model.CopyAbsoluteBoneTransformsTo(bones);
			foreach (ModelMesh mm in model.Meshes) {
				Matrix bone = bones[mm.ParentBone.Index];
				foreach (ModelMeshPart mmp in mm.MeshParts) {
					int offset = vertices.Count;
					Vector3[] verts = new Vector3[mmp.NumVertices];
					mmp.VertexBuffer.GetData<Vector3>(mmp.VertexOffset * mmp.VertexBuffer.VertexDeclaration.VertexStride,
					verts, 0, mmp.NumVertices, mmp.VertexBuffer.VertexDeclaration.VertexStride);
					foreach(Vector3 vert in verts) {
						vertices.Add(GetJitterVector(Vector3.Transform(vert, bone)));
					}

					short[] indices = new short[mmp.PrimitiveCount * 3];
					mmp.IndexBuffer.GetData<short>(mmp.StartIndex * 2, indices, 0, mmp.PrimitiveCount * 3);
					TriangleVertexIndices[] tvi = new TriangleVertexIndices[mmp.PrimitiveCount];
					for (int i = 0; i != tvi.Length; ++i) {
						tvi[i].I0 = indices[i * 3 + 0] + offset;
						tvi[i].I1 = indices[i * 3 + 1] + offset;
						tvi[i].I2 = indices[i * 3 + 2] + offset;
					}
					triangles.AddRange(tvi);
				}
			}
		}
 */
