using Earthblend.Tts.Shell.Members;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace Earthblend.Tts.Common.Core.MeshGenerators
{
    public class TravelingTorusMeshGeneratorService
    {
        public TravelingTorusMeshGeneratorService(Dictionary<int, HoseConfigurationDataItem> skewPaths)
        {
            _skewPaths = skewPaths;
        }

        private Dictionary<int, HoseConfigurationDataItem> _skewPaths = null;

        public int ThetaStart = 0;
        public int ThetaStop = 36;
        public Double Radius = 1.0D;
        public Double TubeRadius = 0.25D;
        public int Slices = 18;
        public int Stacks = 36;

        public MeshGeometry3D GenerateMesh()
        {
            Point3DCollection vertices = new Point3DCollection();
            Int32Collection indices = new Int32Collection();
            PointCollection textures = new PointCollection();
            Vector3DCollection normals = new Vector3DCollection();

            // Fill the vertices, normals, and textures collections.
            for (int stack = ThetaStart; stack <= ThetaStop; stack++)
            {
                double phi = stack * 2 * Math.PI / Stacks;

                double xCenter = Radius * Math.Sin(phi);
                double yCenter = Radius * Math.Cos(phi);
                Point3D pointCenter = new Point3D(xCenter, yCenter, 0);

                Point3D lastPoint = new Point3D();
                for (int slice = 0; slice <= Slices; slice++)
                {
                    double theta = slice * 2 * Math.PI / Slices + Math.PI;
                    double x = (Radius + TubeRadius * Math.Cos(theta)) * Math.Sin(phi);
                    double y = (Radius + TubeRadius * Math.Cos(theta)) * Math.Cos(phi);
                    double z = -TubeRadius * Math.Sin(theta);

                    Point3D point = new Point3D();

                    if (_skewPaths != null)
                    {
                        if (_skewPaths.ContainsKey(stack))
                        {
                            point = new Point3D(x + _skewPaths[stack].DirectionX, y + _skewPaths[stack].DirectionY, z + _skewPaths[stack].DirectionZ);
                        }
                        else
                        {
                            point = new Point3D(x, y, z);
                        }
                    }
                    else
                    {
                        point = new Point3D(x, y, z);
                    }

                    vertices.Add(point);
                    normals.Add(point - pointCenter);
                    textures.Add(new Point((double)slice / Slices, (double)stack / Stacks));
                    lastPoint = point;
                }
            }

            // Fill the indices collection.
            for (int stack = ThetaStart; stack < ThetaStop; stack++)
            {
                for (int slice = 0; slice < Slices; slice++)
                {
                    indices.Add((stack + 0) * (Slices + 1) + slice);
                    indices.Add((stack + 1) * (Slices + 1) + slice);
                    indices.Add((stack + 0) * (Slices + 1) + slice + 1);

                    indices.Add((stack + 0) * (Slices + 1) + slice + 1);
                    indices.Add((stack + 1) * (Slices + 1) + slice);
                    indices.Add((stack + 1) * (Slices + 1) + slice + 1);
                }
            }

            return new MeshGeometry3D() { Positions = vertices, TriangleIndices = indices, TextureCoordinates = textures, Normals = normals };
        }
    }
}