using Earthblend.Tts.Common.Core.MeshGenerators.Base;
using Earthblend.Tts.Common.Core.CustomEventArgs;
using HelixToolkit.Wpf;
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;

namespace Earthblend.Tts.Common.Core.MeshGenerators
{
    public class ConeMeshGenerator : CylindricalMeshBase
    {
        public ConeMeshGenerator()
        {
            Slices = 16;
            PropertyChanged(new DependencyPropertyChangedEventArgs());
        }

        public static IList<String> Properties = new List<String>() 
        { 
            "BaseCap", "TopCap", "BaseRadius", "TopRadius", "Height", "Stacks","Slices" 
            ,"Point1X","Point1Y","Point1Z","Point2X","Point2Y","Point2Z",
        };

        public ConeMeshGenerator Duplicate()
        {
            ConeMeshGenerator coneMeshGenerator = new ConeMeshGenerator();

            coneMeshGenerator.BaseCap = BaseCap;
            coneMeshGenerator.TopCap = TopCap;
            coneMeshGenerator.BaseRadius = BaseRadius;
            coneMeshGenerator.TopRadius = TopRadius;
            coneMeshGenerator.Height = Height;
            coneMeshGenerator.Stacks = Stacks;
            coneMeshGenerator.Slices = Slices;
            coneMeshGenerator.Point1X = Point1X;
            coneMeshGenerator.Point1Y = Point1Y;
            coneMeshGenerator.Point1Z = Point1Z;
            coneMeshGenerator.Point2X = Point2X;
            coneMeshGenerator.Point2Y = Point2Y;
            coneMeshGenerator.Point2Z = Point2Z;

            return coneMeshGenerator;      
        }

        private ICommand _decreaseBaseRadiusCommandIc;[XmlIgnore] public ICommand DecreaseBaseRadiusCommandIc => _decreaseBaseRadiusCommandIc ?? (_decreaseBaseRadiusCommandIc = new RelayCommand<Object>(DecreaseBaseRadiusCommandIcExecuted));
        public void DecreaseBaseRadiusCommandIcExecuted(Object sender) { BaseRadius -= MovementValue; }
        private ICommand _decreaseTopRadiusCommandIc;[XmlIgnore] public ICommand DecreaseTopRadiusCommandIc => _decreaseTopRadiusCommandIc ?? (_decreaseTopRadiusCommandIc = new RelayCommand<Object>(DecreaseTopRadiusCommandIcExecuted));
        public void DecreaseTopRadiusCommandIcExecuted(Object sender) { TopRadius -= MovementValue; }


        private ICommand _increaseBaseRadiusCommandIc;[XmlIgnore] public ICommand IncreaseBaseRadiusCommandIc => _increaseBaseRadiusCommandIc ?? (_increaseBaseRadiusCommandIc = new RelayCommand<Object>(IncreaseBaseRadiusCommandIcExecuted));
        public void IncreaseBaseRadiusCommandIcExecuted(Object sender) { BaseRadius += MovementValue; }
        private ICommand _increaseTopRadiusCommandIc;[XmlIgnore] public ICommand IncreaseTopRadiusCommandIc => _increaseTopRadiusCommandIc ?? (_increaseTopRadiusCommandIc = new RelayCommand<Object>(IncreaseTopRadiusCommandIcExecuted));
        public void IncreaseTopRadiusCommandIcExecuted(Object sender) { TopRadius += MovementValue; }

        public static readonly DependencyProperty BaseCapProperty = DependencyProperty.Register("BaseCap", typeof(Boolean), typeof(ConeMeshGenerator), new PropertyMetadata(true, Point2PropertyChanged));
        public static readonly DependencyProperty TopCapProperty = DependencyProperty.Register("TopCap", typeof(Boolean), typeof(ConeMeshGenerator), new PropertyMetadata(true, Point2PropertyChanged));

        public static readonly DependencyProperty BaseRadiusProperty = DependencyProperty.Register("BaseRadius", typeof(Double), typeof(ConeMeshGenerator), new PropertyMetadata(1.0D, Point2PropertyChanged));
        public static readonly DependencyProperty TopRadiusProperty = DependencyProperty.Register("TopRadius", typeof(Double), typeof(ConeMeshGenerator), new PropertyMetadata(1.0D, Point2PropertyChanged));
        public static readonly DependencyProperty HeightProperty = DependencyProperty.Register("Height", typeof(Double), typeof(ConeMeshGenerator), new PropertyMetadata(1.0D, Point2PropertyChanged));

        public Boolean BaseCap { set { SetValue(BaseCapProperty, value); } get { return (Boolean)GetValue(BaseCapProperty); } }
        public Boolean TopCap { set { SetValue(TopCapProperty, value); } get { return (Boolean)GetValue(TopCapProperty); } }
        public Double BaseRadius { set { SetValue(BaseRadiusProperty, value); } get { return (Double)GetValue(BaseRadiusProperty); } }
        public Double TopRadius { set { SetValue(TopRadiusProperty, value); } get { return (Double)GetValue(TopRadiusProperty); } }
        public Double Height { set { SetValue(HeightProperty, value); } get { return (Double)GetValue(HeightProperty); } }

        //protected override Freezable CreateInstanceCore()
        //{
        //    return new ConeMeshGenerator();
        //}

        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();

            //                  Point3D origin, Point3D apex,        double baseRadius, bool baseCap,     int thetaDiv
            //                  Point3D origin, Vector3D direction,  double baseRadius, double topRadius, double height, bool baseCap, bool topCap, int thetaDiv
            //meshBuilder.AddCone(Point1, Point2, BaseRadius, BaseCap, Slices);   
            meshBuilder.AddCone(Point1, Point2.ToVector3D(), BaseRadius, TopRadius, Height, BaseCap, TopCap, Slices,ThetaStart,ThetaStop);
            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));
        }
    }
}