using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;
using Godot;

namespace Rokojori
{  
  public interface Animator
  {
    public void OnAnimatorStart();
    public void OnAnimatorEnd();
    public void OnAnimatorCancel();
  }

  /*
    public void OnAnimatorStart(){}
    public void OnAnimatorEnd(){}
    public void OnAnimatorCancel(){}
  */

  public class AnimationMember
  {
    public static readonly AnimationMember Position = new AnimationMember( "position" );
    public static readonly AnimationMember Rotation = new AnimationMember( "rotation" );
    public static readonly AnimationMember Scale    = new AnimationMember( "scale" );

    public static readonly AnimationMember VolumeDB    = new AnimationMember( "volumeDB" );

    public static readonly AnimationMember[] Transform = new AnimationMember[]
    {
      AnimationMember.Position,  AnimationMember.Rotation,  AnimationMember.Scale
    };

    string _name;
    public string name => _name;

    public AnimationMember( string name )
    {
      _name = name;
    }
  }
  
  public class AnimationManager
  {     
    static MultiMap<GodotObject,string,Animator> _animatingObjects = new MultiMap<GodotObject,string,Animator>();

    public static Animator GetAnimator( GodotObject go, string memberName )
    {
      return _animatingObjects.Get( go, memberName );
    }

    public static Animator GetAnimator( Material material, ShaderPropertyName propertyName  )
    {
      return GetAnimator( material, propertyName.propertyName );
    }

    public static bool IsAnimating( Animator animator, GodotObject go, string memberName )
    { 
      return GetAnimator( go, memberName ) == animator;
    }    

    public static bool IsAnimating( Animator animator, Material material, ShaderPropertyName propertyName  )
    { 
      return IsAnimating( animator, material, propertyName.propertyName );
    } 

    public static bool IsAnimating( Animator animator, Node node, params AnimationMember[] members )
    { 
      for ( int i = 0; i < members.Length; i++ )
      {
        if ( ! IsAnimating( animator, node, members[ i ].name ) )
        {
          return false;
        }
      }

      return members.Length > 0;
    }

    public static bool IsAnimating( Animator animator, Node[] nodes, params AnimationMember[] members )
    { 
      for ( int i = 0; i < nodes.Length; i++ )
      {
        if ( ! IsAnimating( animator, nodes[ i ], members ) )
        {
          return false;
        }
      }

      return nodes.Length > 0;
    }

    public static void StartAnimation( Animator animator, GodotObject go, string member )
    {
      var activeAnimator = GetAnimator( go, member );
      
      if ( activeAnimator != null )
      {
        activeAnimator.OnAnimatorCancel();
      }

      _animatingObjects.Set( go, member, animator );
    }

    public static void StartAnimation( Animator animator, Node node, AnimationMember member )
    {
      var activeAnimator = GetAnimator( node, member.name );
      
      if ( activeAnimator != null )
      {
        activeAnimator.OnAnimatorCancel();
      }

      _animatingObjects.Set( node, member.name, animator );

    }

    public static void StartAnimation( Animator animator, Material material, ShaderPropertyName shaderPropertyName )
    {
      var activeAnimator = GetAnimator( material, shaderPropertyName );
      
      if ( activeAnimator != null )
      {
        activeAnimator.OnAnimatorCancel();
      }

      _animatingObjects.Set( material, shaderPropertyName.propertyName, animator );
    }

    public static void StartAnimation( Animator animator, Node node, params AnimationMember[] members )
    {
      for ( int i = 0; i < members.Length; i++ )
      {
        StartAnimation( animator, node, members[ i ].name );
      }
    }

    public static void StartAnimation( Animator animator, Node[] nodes, params AnimationMember[] members )
    {
      for ( int i = 0; i < nodes.Length; i++ )
      {
        StartAnimation( animator, nodes[ i ], members );
      }
    }

     public static void EndAnimation( Animator animator, GodotObject go, string member )
    {
      var activeAnimator = GetAnimator( go, member );
      
      if ( activeAnimator != null )
      {
        activeAnimator.OnAnimatorCancel();
      }
    } 


    public static void EndAnimation( Animator animator, Node node, AnimationMember member )
    {
      var activeAnimator = GetAnimator( node, member.name );
      
      if ( activeAnimator != null )
      {
        activeAnimator.OnAnimatorCancel();
      }
    } 

    public static void EndAnimation( Animator animator, Material material, ShaderPropertyName propertyName )
    {
      var activeAnimator = GetAnimator( material, propertyName );
      
      if ( activeAnimator != null )
      {
        activeAnimator.OnAnimatorCancel();
      }
    } 

    public static void EndAnimation( Animator animator, Node node, params AnimationMember[] members )
    {
      for ( int i = 0; i < members.Length; i++ )
      {
        EndAnimation( animator, node, members[ i ].name );
      }
    }

    public static void EndAnimation( Animator animator, Node[] nodes, params AnimationMember[] members )
    {
      for ( int i = 0; i < nodes.Length; i++ )
      {
        EndAnimation( animator, nodes[ i ], members );
      }
    }
  }
}