using SurfacePlot3D.Common;
using SurfacePlot3D.Members;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using System.Windows;
using System.Xml.Serialization;

namespace SurfacePlot3D.MeshGenerators
{
    public class ArrowMeshGenerator : CylindricalMeshBase
    {
        public static IList<String> Properties = new List<String>() { "HeadLength", "Point1X", "Point1Y", "Point1Z", "Point2X", "Point2Y", "Point2Z", "Radius", "Slices" }; //, "Stacks" };

        #region Constructor(s)

        public ArrowMeshGenerator()
        {
            PropertyChanged(new DependencyPropertyChangedEventArgs());
            Radius = .5D;
        }

        #endregion

        #region Private Commands

        private ICommand _cycleCommandIc;
        private ICommand _decreaseHeadLengthCommandIc;
        private ICommand _increaseHeadLengthCommandIc;

        #endregion

        #region Public Commands

        [XmlIgnore] public ICommand CycleCommandIc => _cycleCommandIc ?? (_cycleCommandIc = new RelayCommand<Object>(CycleCommandIcExecuted));
        [XmlIgnore] public ICommand DecreaseHeadLengthCommandIc => _decreaseHeadLengthCommandIc ?? (_decreaseHeadLengthCommandIc = new RelayCommand<Object>(DecreaseHeadLengthCommandIcExecuted));
        [XmlIgnore] public ICommand IncreaseHeadLengthCommandIc => _increaseHeadLengthCommandIc ?? (_increaseHeadLengthCommandIc = new RelayCommand<Object>(IncreaseHeadLengthCommandIcExecuted));

        #endregion

        #region ICommand Executed

        public void CycleCommandIcExecuted(Object sender)
        {
            var point1TempZ = Point1Z;
            Point1Z = Point1Y;
            Point1Y = Point1X;
            Point1X = point1TempZ;

            var point2TempZ = Point2Z;
            Point2Z = Point2Y;
            Point2Y = Point2X;
            Point2X = point2TempZ;

            //OnLastActionChanged(new LastActionEventArgs(ActionType.Cycle));
        }
        private void DecreaseHeadLengthCommandIcExecuted(Object sender) { HeadLength -= MovementValue; }
        private void IncreaseHeadLengthCommandIcExecuted(Object sender) { HeadLength += MovementValue; }

        #endregion

        #region Dependency Properties

        private static readonly DependencyProperty HeadLengthProperty = DependencyProperty.Register("HeadLength", typeof(Double), typeof(ArrowMeshGenerator), new PropertyMetadata(1.0D, PropertyChanged));

        #endregion

        #region Public Clr Access Properties

        public Double HeadLength { set { SetValue(HeadLengthProperty, value); } get { return (Double)GetValue(HeadLengthProperty); } }

        #endregion

        public ArrowMeshGenerator Duplicate()
        {
            ArrowMeshGenerator arrowMeshGenerator = new ArrowMeshGenerator();
            arrowMeshGenerator.HeadLength = HeadLength;
            arrowMeshGenerator.Radius = Radius;
            arrowMeshGenerator.Slices = Slices;

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

            return arrowMeshGenerator;
        }

        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.AddArrow(Point1, Point2, Radius * 2, HeadLength, 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));
        }
    }
}