using System;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using System.Windows;
using SurfacePlot3D.Enumerations;

namespace SurfacePlot3D.MeshGenerators
{
    public abstract class MeshGeneratorBase : CustomBindableBase // Animatable
    {
        public static readonly DependencyProperty SupportLegacyPositioningProperty = DependencyProperty.Register("SupportLegacyPositioning", typeof(Boolean), typeof(MeshGeneratorBase), new PropertyMetadata(true)); //, PropertyChanged
        public Boolean SupportLegacyPositioning { set { SetValue(SupportLegacyPositioningProperty, value); } get { return (Boolean)GetValue(SupportLegacyPositioningProperty); } }

        public static readonly DependencyProperty ScaleXProperty = DependencyProperty.Register("ScaleX", typeof(Double), typeof(MeshGeneratorBase), new PropertyMetadata(1.0D, PropertyChanged));
        public static readonly DependencyProperty ScaleYProperty = DependencyProperty.Register("ScaleY", typeof(Double), typeof(MeshGeneratorBase), new PropertyMetadata(1.0D, PropertyChanged));
        public static readonly DependencyProperty ScaleZProperty = DependencyProperty.Register("ScaleZ", typeof(Double), typeof(MeshGeneratorBase), new PropertyMetadata(1.0D, PropertyChanged));

        public Double ScaleX { set { SetValue(ScaleXProperty, value); } get { return (Double)GetValue(ScaleXProperty); } }
        public Double ScaleY { set { SetValue(ScaleYProperty, value); } get { return (Double)GetValue(ScaleYProperty); } }
        public Double ScaleZ { set { SetValue(ScaleZProperty, value); } get { return (Double)GetValue(ScaleZProperty); } }


        public static readonly DependencyProperty AxisProperty = DependencyProperty.Register("AxisProperty", typeof(TargetAxis), typeof(MeshGeneratorBase), new PropertyMetadata(TargetAxis.X, PropertyChanged));
        public TargetAxis Axis { set { SetValue(AxisProperty, value); } get { return (TargetAxis)GetValue(AxisProperty); } }

        public event EventHandler<MeshEventArgs> MeshChanged;

        protected virtual void OnMeshChanged(MeshEventArgs e)
        {
            EventHandler<MeshEventArgs> handler = MeshChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        //public event EventHandler<LastActionEventArgs> LastActionChanged;

        //protected virtual void OnLastActionChanged(LastActionEventArgs e)
        //{
        //    EventHandler<LastActionEventArgs> handler = LastActionChanged;
        //    if (handler != null)
        //    {
        //        handler(this, e);
        //    }
        //}

        public static readonly DependencyProperty MovementValueProperty = DependencyProperty.Register("MovementValue", typeof(Double), typeof(MeshGeneratorBase), new PropertyMetadata(1.0D));

        public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(MeshGeneratorBase));
        public string Name
        {
            set { SetValue(NameProperty, value); }
            get { return (string)GetValue(NameProperty); }
        }

        static DependencyPropertyKey GeometryKey = DependencyProperty.RegisterReadOnly("Geometry", typeof(MeshGeometry3D), typeof(MeshGeneratorBase), new PropertyMetadata(new MeshGeometry3D()));

        public static readonly DependencyProperty GeometryProperty = GeometryKey.DependencyProperty;

        public MeshGeometry3D Geometry { set { SetValue(GeometryKey, value); } get { return (MeshGeometry3D)GetValue(GeometryProperty); } }
        public Double MovementValue { set { SetValue(MovementValueProperty, value); } get { return (Double)GetValue(MovementValueProperty); } }

        public MeshGeneratorBase()
        {
            Geometry = new MeshGeometry3D();
        }

        protected static void PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            (obj as MeshGeneratorBase).PropertyChanged(args);
        }

        protected virtual void PropertyChanged(DependencyPropertyChangedEventArgs args)
        {
            // Get the MeshGeometry3D for local convenience.
            MeshGeometry3D mesh = Geometry;

            // Obtain the four collection of the MeshGeometry3D.
            Point3DCollection vertices = mesh.Positions;
            Vector3DCollection normals = mesh.Normals;
            Int32Collection indices = mesh.TriangleIndices;
            PointCollection textures = mesh.TextureCoordinates;

            // Set the MeshGeometry3D collections to null while updating.
            mesh.Positions = null;
            mesh.Normals = null;
            mesh.TriangleIndices = null;
            mesh.TextureCoordinates = null;

            // Call the abstract method to fill the collections.
            Triangulate(args, vertices, normals, indices, textures);

            // Set the updated collections to the MeshGeometry3D.
            mesh.TextureCoordinates = textures;
            mesh.TriangleIndices = indices;
            mesh.Normals = normals;
            mesh.Positions = vertices;
        }

        protected abstract void Triangulate(DependencyPropertyChangedEventArgs args, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures);
    }

}
