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



namespace Rokojori
{
  [Tool]
  [GlobalClass]
  public partial class GeneratorScatterer:Scatterer
  {
    [Export]
    public bool setDiscarded = true;

    [Export]
    public PackedScene packedScene;

    [Export]
    public Node3D container;

    [Export]
    public bool useGeneratorEntryFromChildren = true;

    [Export]
    public float childGeneratorNoiseScale = 1;

    [Export]
    public Vector3 childGeneratorNoiseOffset = Vector3.Zero;

    protected List<GeneratorEntry> childGenerators = new List<GeneratorEntry>();
    protected List<float> childGeneratorWeights = new List<float>();

    public void CreateWeights()
    {
      if ( ! useGeneratorEntryFromChildren )
      {
        return;
      }

      childGenerators = Nodes.GetDirectChildren<GeneratorEntry>( this );
      childGeneratorWeights = Lists.Map( childGenerators, c => c.probability );
      
      var sum = 0f;
      childGeneratorWeights.ForEach( w => sum += w );      
      childGeneratorWeights = Lists.Map( childGeneratorWeights, c => c /= sum );
    }

    public void AssginSceneAndContainer( ScatterPoint p )
    {
      if ( ! useGeneratorEntryFromChildren )
      {
        p.scene  = packedScene;
        p.parent = container; 
      }
      else
      {
        var value = Noise.Perlin( ( p.position + childGeneratorNoiseOffset ) * childGeneratorNoiseScale );
        var index = _FindElementIndexWithWeights( childGeneratorWeights, value );
        var gs = childGenerators[ index ];

        p.scene = gs.GetPackedScene() != null ? gs.GetPackedScene() : packedScene;
        p.parent = gs.container != null ? gs.container : container;
        p.instanced = gs.useInstancing;
        p.instanceSplitSize = gs.instancingSplitSize;
        p.instancingSplitScatterNoiseAmount = gs.instancingSplitScatterNoiseAmount;
        p.instancingSplitScatterNoiseFrequency = gs.instancingSplitScatterNoiseFrequency;
        p.instanceCullDistance = gs.instancingCullDistance;
        p.instanceCullRange = gs.instancingCullRange;

        if ( gs.node3D != null && gs.node3D is MeshInstance3D mi )
        {
          p.shadowCasting = mi.CastShadow;
        }
       

      }

    }

    int _FindElementIndexWithWeights( List<float> weights, float value )
    {
      var limit = 0f;

      for ( int i = 0; i < weights.Count; i++ )
      {
        var before = limit;
        limit += weights[ i ];

        if ( before <= value && value < limit )
        {
          return i;
        }
      }

      return weights.Count - 1;
    }

  }
}