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


namespace Rokojori
{
  public class Triangle2
  {   
    public Vector2 a;
    public Vector2 b;
    public Vector2 c;

    bool _needsUpdate = true;
    Vector2 _center;

    public Triangle2( Vector2 a, Vector2 b, Vector2 c )
    {
      this.a = a;
      this.b = b;
      this.c = c;
    }

    public static Triangle2 AsXZ( Triangle3 t )
    {
      return new Triangle2( Math2D.XZ( t.a ),  Math2D.XZ( t.b ), Math2D.XZ( t.c ) );
    }

    public void Update()
    {
      if ( ! _needsUpdate )
      {
        return;
      }

      _needsUpdate = false;
      _center = ( a + b +c ) /3f;
    }

    public Vector2 center 
    {
      get 
      {
        Update();
        return _center;
      }
    }

    public Line2 GetEdge( int index )
    {
      return index == 0 ? new Line2( a, b ) : index == 1 ? new Line2( b, c ) : new Line2( c, a) ;
    }

    public Vector2 GetEdgeDirection( int index )
    {
      return GetEdge( index ).direction;
    } 

    public Vector2 GetInnerNormal( int index )
    {
      var edge = GetEdge( index );

      var normal = Math2D.Rotate90DegreesRight( edge.direction.Normalized() );
      var flipNormal = - normal;
      var cnt = center;
      var edgeCenter = edge.center;
      var dist = ( cnt - edgeCenter ).Length() * 0.1f;

      if ( ContainsPoint( edgeCenter + normal ) )
      {
        return normal;
      }
      
      return -normal;
    }

    public bool ContainsPoint( Vector2 p )
    {
      var d1 = Sign( p, a, b );
      var d2 = Sign( p, b, c );
      var d3 = Sign( p, c, a );

      var hasNegative = ( d1 < 0 ) || ( d2 < 0 ) || ( d3 < 0 );
      var hasPositive = ( d1 > 0 ) || ( d2 > 0 ) || ( d3 > 0 );

      return ! ( hasNegative && hasPositive );
    }


    public Vector2 GetOuterNormal( int index )
    {
      return - GetInnerNormal( index );
    }

    public Triangle2 Shrink( float distance )
    {
      var edges = new List<Line2>();

      for ( int i = 0; i < 3; i++ )
      {
        edges.Add( GetEdge( i ) );
        edges[ i ].ScaleFromCenter( 10 );
        var t = GetInnerNormal( i ) * distance;
        edges[ i ].Translate( t );
        // RJLog.Log( i, ">", t );
      }

     
      var e0 = edges[ 0 ];
      var e1 = edges[ 1 ];
      var e2 = edges[ 2 ];

      var i01 = e0.IntersectionOf( e1 );

      if ( i01 == null || ! ContainsPoint( (Vector2) i01 ) )
      {
        // RJLog.Log( "i01", i01, i01 != null ? ContainsPoint( (Vector2) i01 ) : false );
        return null;
      }

      var i12 = e1.IntersectionOf( e2 );
      
      if ( i12 == null || ! ContainsPoint( (Vector2) i12 ) )
      {
        // RJLog.Log( "i12", i12, i12 != null ? ContainsPoint( (Vector2) i12 ) : false );
        return null;
      }

      var i20 = e2.IntersectionOf( e0 );

      if ( i20 == null || ! ContainsPoint( (Vector2) i20 ) )
      {
        // RJLog.Log( "i20", i20, i20 != null ? ContainsPoint( (Vector2) i20 ) : false );
        return null;
      }      

      return new Triangle2( (Vector2) i20, (Vector2) i01, (Vector2) i12 ); 
    }

    static float Sign( Vector2 p1, Vector2 p2, Vector2 p3)
    {
      return ( p1.X - p3.X ) * ( p2.Y - p3.Y ) - ( p2.X - p3.X ) * (p1.Y - p3.Y );
    }

    
    
  }
}