using System.Collections;
using System.Collections.Generic;
using Godot;
using System;



namespace Rokojori
{
  [Tool]
  [GlobalClass]
  public partial class GenerateFence:GeneratorScatterer
  {
    [Export]
    public Spline spline;

    [Export]
    public bool xzOnly = true;

    [Export]
    public float sampleDensity = 1;   

    [Export]
    public GeneratorEntry segment;
    [Export]
    public float segmentLength;
    [Export]
    public Vector3 segmentRotation;
    [Export]
    public float segmentYOffset;
    [Export]
    public Vector3 scaleAxis = new Vector3( 1, 0, 0 );

    [Export]
    public GeneratorEntry pole;
    [Export]
    public float poleLength;

    [Export]
    public GeneratorEntry startPole;    
    [Export]
    public float startPoleLength;

    [Export]
    public GeneratorEntry endPole;
    [Export]
    public float endPoleLength;

    SplineCurve last;
    LerpCurve3 equalSpacedCurve;

    protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points, Scatterer root )
    {
      CreateWeights();
      var curve = spline.GetCurve();

      if ( last != curve )
      {
        last = curve;
        equalSpacedCurve = LerpCurve3.SampledEqually( curve, sampleDensity );
      }

      var curveLength = equalSpacedCurve.ComputeLength( 0 );
      var numPoints = Mathf.CeilToInt( curveLength * sampleDensity );


      var id = 0;

      var positions = new List<Vector3>();
      var rotations = new List<Quaternion>();

      for ( int i = 0; i < numPoints; i++ )
      {
        var t = i / (float) ( numPoints - 1 );

        var position = equalSpacedCurve.PositionAt( t );
        var rawDirection = equalSpacedCurve.TangentAt( t, 1f / 100f );
        var direction = rawDirection;
        var length = direction.Length();
        

        if ( length != 0 )
        {
          direction /= length;
        }

        /*RJLog.Log( "i:", i, "t:", t, 
          "P:", position, 
          "L:", length,
          "RD:", rawDirection,
          "D:", direction
        );*/

        var point = CreatePoint( points, id, position.X, position.Y, position.Z, pole );

        point.rotation = Math3D.LookRotation( direction, Vector3.Up );

        positions.Add( position );
        rotations.Add( point.rotation );
        id = point.creatorID + 1;

      } 

      for ( int i = 0; i < positions.Count - 1; i++ )
      {
        var position = positions[ i ].Lerp( positions[ i + 1 ], 0.5f );
        var direction = positions[ i + 1 ] - positions[ i ];
        var rotation = Math3D.LookRotation( direction, Vector3.Up );
        var length = direction.Length() / segmentLength - 1.0f;

        var point = CreatePoint( points, id, position.X, position.Y + segmentYOffset, position.Z, segment );
        point.rotation = rotation * Quaternion.FromEuler( segmentRotation / 180.0f * Mathf.Pi );
        point.scale = Vector3.One + length * scaleAxis;

        id = point.creatorID + 1;
      }


      return points;
    }

    ScatterPoint CreatePoint( List<ScatterPoint> points, int id, float x, float y, float z, GeneratorEntry entry )
    {
      var p = new ScatterPoint( this, id );

      p.position = new Vector3( x, y, z );
      p.visible = ! setDiscarded;
      p.seed = Noise.CreateSeed( p.position );

      p.scene = entry.GetPackedScene();
      p.parent = entry.container;
    
      points.Add( p );

      return p;
    } 
  }
}