using Earthblend.Tts.Common.Core.MeshGenerators.Base;
using Earthblend.Tts.Common.Core.CustomEventArgs;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Xml.Serialization;
using Earthblend.DynamicCompile;
using Earthblend.Tts.Common.Core.Members;
using Earthblend.Nts.Common.MeshGenerators.Base;

namespace Earthblend.Tts.Common.Core.MeshGenerators
{
    public class PipeMeshGenerator : MeshGeneratorBase
    {
        public PipeMeshGenerator()
        {
            PropertyChanged(new DependencyPropertyChangedEventArgs());
        }

        private ICommand _decreasePoint1XCommandIc; [XmlIgnore] public ICommand DecreasePoint1XCommandIc => _decreasePoint1XCommandIc ?? (_decreasePoint1XCommandIc = new RelayCommand<Object>(DecreasePoint1XCommandIcExecuted));
        public void DecreasePoint1XCommandIcExecuted(Object sender) { Point1X -= MovementValue; }

        private ICommand _increasePoint1XCommandIc; [XmlIgnore] public ICommand IncreasePoint1XCommandIc => _increasePoint1XCommandIc ?? (_increasePoint1XCommandIc = new RelayCommand<Object>(IncreasePoint1XCommandIcExecuted));
        public void IncreasePoint1XCommandIcExecuted(Object sender) { Point1X += MovementValue; }

        private ICommand _decreasePoint1YCommandIc; [XmlIgnore] public ICommand DecreasePoint1YCommandIc => _decreasePoint1YCommandIc ?? (_decreasePoint1YCommandIc = new RelayCommand<Object>(DecreasePoint1YCommandIcExecuted));
        public void DecreasePoint1YCommandIcExecuted(Object sender) { Point1Y -= MovementValue; }

        private ICommand _increasePoint1YCommandIc; [XmlIgnore] public ICommand IncreasePoint1YCommandIc => _increasePoint1YCommandIc ?? (_increasePoint1YCommandIc = new RelayCommand<Object>(IncreasePoint1YCommandIcExecuted));
        public void IncreasePoint1YCommandIcExecuted(Object sender) { Point1Y += MovementValue; }
        private ICommand _decreasePoint1ZCommandIc; [XmlIgnore] public ICommand DecreasePoint1ZCommandIc => _decreasePoint1ZCommandIc ?? (_decreasePoint1ZCommandIc = new RelayCommand<Object>(DecreasePoint1ZCommandIcExecuted));
        public void DecreasePoint1ZCommandIcExecuted(Object sender) { Point1Z -= MovementValue; }
        private ICommand _increasePoint1ZCommandIc; [XmlIgnore] public ICommand IncreasePoint1ZCommandIc => _increasePoint1ZCommandIc ?? (_increasePoint1ZCommandIc = new RelayCommand<Object>(IncreasePoint1ZCommandIcExecuted));
        public void IncreasePoint1ZCommandIcExecuted(Object sender) { Point1Z += MovementValue; }




        private ICommand _decreasePoint2XCommandIc; [XmlIgnore] public ICommand DecreasePoint2XCommandIc => _decreasePoint2XCommandIc ?? (_decreasePoint2XCommandIc = new RelayCommand<Object>(DecreasePoint2XCommandIcExecuted));
        public void DecreasePoint2XCommandIcExecuted(Object sender) { Point2X -= MovementValue; }

        private ICommand _increasePoint2XCommandIc; [XmlIgnore] public ICommand IncreasePoint2XCommandIc => _increasePoint2XCommandIc ?? (_increasePoint2XCommandIc = new RelayCommand<Object>(IncreasePoint2XCommandIcExecuted));
        public void IncreasePoint2XCommandIcExecuted(Object sender) { Point2X += MovementValue; }

        private ICommand _decreasePoint2YCommandIc; [XmlIgnore] public ICommand DecreasePoint2YCommandIc => _decreasePoint2YCommandIc ?? (_decreasePoint2YCommandIc = new RelayCommand<Object>(DecreasePoint2YCommandIcExecuted));
        public void DecreasePoint2YCommandIcExecuted(Object sender) { Point2Y -= MovementValue; }

        private ICommand _increasePoint2YCommandIc; [XmlIgnore] public ICommand IncreasePoint2YCommandIc => _increasePoint2YCommandIc ?? (_increasePoint2YCommandIc = new RelayCommand<Object>(IncreasePoint2YCommandIcExecuted));
        public void IncreasePoint2YCommandIcExecuted(Object sender) { Point2Y += MovementValue; }
        private ICommand _decreasePoint2ZCommandIc; [XmlIgnore] public ICommand DecreasePoint2ZCommandIc => _decreasePoint2ZCommandIc ?? (_decreasePoint2ZCommandIc = new RelayCommand<Object>(DecreasePoint2ZCommandIcExecuted));
        public void DecreasePoint2ZCommandIcExecuted(Object sender) { Point2Z -= MovementValue; }
        private ICommand _increasePoint2ZCommandIc; [XmlIgnore] public ICommand IncreasePoint2ZCommandIc => _increasePoint2ZCommandIc ?? (_increasePoint2ZCommandIc = new RelayCommand<Object>(IncreasePoint2ZCommandIcExecuted));
        public void IncreasePoint2ZCommandIcExecuted(Object sender) { Point2Z += MovementValue; }







        private ICommand _decreaseSlicesCommandIc; [XmlIgnore] public ICommand DecreaseSlicesCommandIc => _decreaseSlicesCommandIc ?? (_decreaseSlicesCommandIc = new RelayCommand<Object>(DecreaseSlicesCommandIcExecuted));
        public void DecreaseSlicesCommandIcExecuted(Object sender) { Slices -= 1; }

        private ICommand _increaseSlicesCommandIc; [XmlIgnore] public ICommand IncreaseSlicesCommandIc => _increaseSlicesCommandIc ?? (_increaseSlicesCommandIc = new RelayCommand<Object>(IncreaseSlicesCommandIcExecuted));
        public void IncreaseSlicesCommandIcExecuted(Object sender) { Slices += 1; }


        private ICommand _decreaseInnerRadiusCommandIc; [XmlIgnore] public ICommand DecreaseInnerRadiusCommandIc => _decreaseInnerRadiusCommandIc ?? (_decreaseInnerRadiusCommandIc = new RelayCommand<Object>(DecreaseInnerRadiusCommandIcExecuted));
        public void DecreaseInnerRadiusCommandIcExecuted(Object sender) { InnerRadius -= MovementValue; }

        private ICommand _increaseInnerRadiusCommandIc; [XmlIgnore] public ICommand IncreaseInnerRadiusCommandIc => _increaseInnerRadiusCommandIc ?? (_increaseInnerRadiusCommandIc = new RelayCommand<Object>(IncreaseInnerRadiusCommandIcExecuted));
        public void IncreaseInnerRadiusCommandIcExecuted(Object sender) { InnerRadius += MovementValue; }

        private ICommand _decreaseRadiusCommandIc; [XmlIgnore] public ICommand DecreaseRadiusCommandIc => _decreaseRadiusCommandIc ?? (_decreaseRadiusCommandIc = new RelayCommand<Object>(DecreaseRadiusCommandIcExecuted));
        public void DecreaseRadiusCommandIcExecuted(Object sender) { Radius -= MovementValue; }
        private ICommand _increaseRadiusCommandIc; [XmlIgnore] public ICommand IncreaseRadiusCommandIc => _increaseRadiusCommandIc ?? (_increaseRadiusCommandIc = new RelayCommand<Object>(IncreaseRadiusCommandIcExecuted));
        public void IncreaseRadiusCommandIcExecuted(Object sender) { Radius += MovementValue; }




        private ICommand _decreaseHeadLengthCommandIc; [XmlIgnore] public ICommand DecreaseHeadLengthCommandIc => _decreaseHeadLengthCommandIc ?? (_decreaseHeadLengthCommandIc = new RelayCommand<Object>(DecreaseHeadLengthCommandIcExecuted));
        public void DecreaseHeadLengthCommandIcExecuted(Object sender) { HeadLength -= MovementValue; }
        private ICommand _increaseHeadLengthCommandIc; [XmlIgnore] public ICommand IncreaseHeadLengthCommandIc => _increaseHeadLengthCommandIc ?? (_increaseHeadLengthCommandIc = new RelayCommand<Object>(IncreaseHeadLengthCommandIcExecuted));
        public void IncreaseHeadLengthCommandIcExecuted(Object sender) { HeadLength += MovementValue; }

        public static IList<String> Properties = new List<String>() { "HeadLength", "Point1X", "Point1Y", "Point1Z", "Point2X", "Point2Y", "Point2Z", "Radius", "Slices" }; //, "Stacks" };

        public static readonly DependencyProperty HeadLengthProperty = DependencyProperty.Register("HeadLength", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(1.0D, PropertyChanged));
        public Double HeadLength { set { SetValue(HeadLengthProperty, value); } get { return (Double)GetValue(HeadLengthProperty); } }

        public PipeMeshGenerator Duplicate()
        {
            PipeMeshGenerator meshGenerator = new PipeMeshGenerator();
            meshGenerator.HeadLength = HeadLength;
            meshGenerator.Radius = Radius;
            meshGenerator.Slices = Slices;

            meshGenerator.Point1X = Point1X;
            meshGenerator.Point1Y = Point1Y;
            meshGenerator.Point1Z = Point1Z;
            meshGenerator.Point2X = Point2X;
            meshGenerator.Point2Y = Point2Y;
            meshGenerator.Point2Z = Point2Z;

            return meshGenerator;
        }

        public static readonly DependencyProperty SlicesProperty = DependencyProperty.Register("Slices", typeof(int), typeof(PipeMeshGenerator), new PropertyMetadata(36, PropertyChanged));
        public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(1D, PropertyChanged));
        public static readonly DependencyProperty ThetaStartProperty = DependencyProperty.Register("ThetaStart", typeof(int), typeof(PipeMeshGenerator), new PropertyMetadata(default(int), PropertyChanged));
        public static readonly DependencyProperty ThetaStopProperty = DependencyProperty.Register("ThetaStop", typeof(int), typeof(PipeMeshGenerator), new PropertyMetadata(36, PropertyChanged));

        public static readonly DependencyProperty Point1XProperty = DependencyProperty.Register("Point1X", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(0D, PropertyChanged));
        public static readonly DependencyProperty Point1YProperty = DependencyProperty.Register("Point1Y", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(-1D, PropertyChanged));
        public static readonly DependencyProperty Point1ZProperty = DependencyProperty.Register("Point1Z", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(0D, PropertyChanged));
        public static readonly DependencyProperty Point2XProperty = DependencyProperty.Register("Point2X", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(1D, PropertyChanged));
        public static readonly DependencyProperty Point2YProperty = DependencyProperty.Register("Point2Y", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(0D, PropertyChanged));
        public static readonly DependencyProperty Point2ZProperty = DependencyProperty.Register("Point2Z", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(0D, PropertyChanged));
        public static readonly DependencyProperty InnerRadiusProperty = DependencyProperty.Register("InnerRadius", typeof(Double), typeof(PipeMeshGenerator), new PropertyMetadata(1D, PropertyChanged));

        public Double InnerRadius { set { SetValue(InnerRadiusProperty, value); } get { return (Double)GetValue(InnerRadiusProperty); } }

        public Double Radius { set { SetValue(RadiusProperty, value); } get { return (Double)GetValue(RadiusProperty); } }
        public int Slices { set { SetValue(SlicesProperty, value); } get { return (int)GetValue(SlicesProperty); } }
        public int ThetaStart { set { SetValue(ThetaStartProperty, value); } get { return (int)GetValue(ThetaStartProperty); } }
        public int ThetaStop { set { SetValue(ThetaStopProperty, value); } get { return (int)GetValue(ThetaStopProperty); } }

        public Double Point1X { set { SetValue(Point1XProperty, value); } get { return (Double)GetValue(Point1XProperty); } }
        public Double Point1Y { set { SetValue(Point1YProperty, value); } get { return (Double)GetValue(Point1YProperty); } }
        public Double Point1Z { set { SetValue(Point1ZProperty, value); } get { return (Double)GetValue(Point1ZProperty); } }
        public Double Point2X { set { SetValue(Point2XProperty, value); } get { return (Double)GetValue(Point2XProperty); } }
        public Double Point2Y { set { SetValue(Point2YProperty, value); } get { return (Double)GetValue(Point2YProperty); } }
        public Double Point2Z { set { SetValue(Point2ZProperty, value); } get { return (Double)GetValue(Point2ZProperty); } }


        protected override void Triangulate(DependencyPropertyChangedEventArgs args, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures)
        {
            vertices.Clear(); normals.Clear(); indices.Clear(); textures.Clear();

            CustomMeshBuilder meshBuilder = new CustomMeshBuilder();
             meshBuilder.AddPipe(new Point3D(Point1X, Point1Y, Point1Z), new Point3D(Point2X, Point2Y, Point2Z), Radius,InnerRadius, Slices, ThetaStart, ThetaStop);

            //var pipeVectors = new List<Vector3D>() { new Vector3D(0, 0, 0), new Vector3D(1, 2, 0), new Vector3D(1, 2, 0), new Vector3D(1.1, 2, 3), new Vector3D(2, 4, 2) };
            //var edges = new List<int>() { 0,1,2,3 };
            //meshBuilder.AddPipes(pipeVectors,edges,1,36,0,36);

            vertices = meshBuilder.Positions;
            normals = meshBuilder.Normals;
            indices = meshBuilder.TriangleIndices;
            textures = meshBuilder.TextureCoordinates;

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

            meshBuilder = null;

            OnMeshChanged(new MeshEventArgs(Geometry as MeshGeometry3D));
        }
    }
}