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

namespace Rokojori
{
  public class Convex2Group
  {
    public List<Convex2> items;
    public Box2 boundingBox;

    public static Convex2Group From( List<Convex2> items )
    {
      var group = new Convex2Group();
      
      group.items = items;

      group.boundingBox = items[ 0 ].boundingBox.Clone();

      items.ForEach( it => group.boundingBox.UnionWith( it.boundingBox ) );

      // RJLog.Log( group.boundingBox );

      return group;
      
    }

    public static Convex2Group FromPath( Path2 path )
    {
      return From( Convex2.PathToConvexList( path ) );
    }

    public bool ContainsPoint( Vector2 point )
    {
      if ( ! boundingBox.ContainsPoint( point ) )
      {
        return false;
      }

      for ( int i = 0; i < items.Count; i++ )
      {
        if ( items[ i ].ContainsPoint( point ) )
        {
          return true;
        }
      }

      return false;

    }
  }

  public class Convex2
  { 
    public List<Vector2> points;
    public List<Vector2> normals;
    public List<Vector2> directions;

    public Box2 boundingBox;
    public bool clockwise;

    public bool ContainsPoint( Vector2 point, bool checkBounds = true )
    {
      if ( checkBounds && ! boundingBox.ContainsPoint( point ) )
      {
        return false;
      }

      var positive = 0;
      var negative = 0;

      for ( int i = 0; i < points.Count; i++ )
      {
        var p = points[ i ];
        var d = directions[ i ].Cross( point - p );

        if ( d > 0 )
        {
          positive++;
        }

        if ( d < 0 )
        {
          negative++;
        }

        if ( positive > 0 && negative > 0 )
        {
          return false;
        }
      }

      
      return true;
    }

    public static List<Convex2> PathToConvexList( Path2 path )
    {
      var convexPolys = Geometry2D.DecomposePolygonInConvex( path.points.ToArray() );

      var list = new List<Convex2>();

      for ( int i = 0; i < convexPolys.Count; i++ )
      {
        var clockwise = Geometry2D.IsPolygonClockwise( convexPolys[ i ] );
        var cnv = FromConvexHull( convexPolys[ i ], clockwise );

        list.Add( cnv );
      }

      // RJLog.Log( "PathToConvexList:", list.Count );
      return list;
    }

    public static Convex2 FromConvexHull( Vector2[] points, bool isClockwise = true )
    {
      return FromConvexHull( new List<Vector2>( points ), isClockwise );
    }

    public static Convex2 FromConvexHull( List<Vector2> points, bool isClockwise = true )
    {
      var cnv = new Convex2();
      cnv.points = points;
      cnv.normals = new List<Vector2>();
      cnv.directions = new List<Vector2>();
      cnv.clockwise = isClockwise;

      cnv.boundingBox = new Box2( points[ 0 ], points[ 0 ] );

      for ( int i = 0; i < points.Count; i++ )
      {
        var next = ( i + 1 ) % points.Count;

        cnv.boundingBox.GrowByPoint( points[ i ] );

        var direction = points[ next ] - points[ i ];
        var normal = Math2D.Rotate90Degrees( direction.Normalized(), ! isClockwise );

        cnv.normals.Add( normal );
        cnv.directions.Add( direction );
      }

      return cnv;
    }
  }
}