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

namespace Rokojori
{  
  public class RDPushConstants
  {
    protected List<float> _floats = new List<float>();
    protected int _floatIndex = 0;

    protected List<int> _ints = new List<int>();
    protected int _intIndex = 0;

    protected byte[] _bytes;

    public void Reset()
    {
      _floatIndex = 0;
      _intIndex = 0;
    }

    public void Set( params object[] objects )
    { 
      Reset();

      for ( int i = 0; i < objects.Length; i++ )
      {
        if ( objects[ i ] is int )
        {
          _AddInt( (int) objects[ i ] );
        }

        else if ( objects[ i ] is float )
        {
          _AddFloat( (float) objects[ i ] );
        }

        else if ( objects[ i ] is Vector2 )
        {
          _AddVector2( (Vector2) objects[ i ] );
        }

        else if ( objects[ i ] is Vector2I )
        {
          _AddVector2( (Vector2I) objects[ i ] );
        }

        else if ( objects[ i ] is Vector3 )
        {
          _AddVector3( (Vector3) objects[ i ] );
        }

        else if ( objects[ i ] is Vector3I )
        {
          _AddVector3( (Vector3I) objects[ i ] );
        }

        else if ( objects[ i ] is Vector4 )
        {
          _AddVector4( (Vector4) objects[ i ] );
        }
      }
    }

    protected void _AddFloat( float value )
    {
      if ( _floatIndex >= _floats.Count )
      {
        _floats.Add( value );
        _floatIndex = _floats.Count;
      }
      else
      {
        _floats[ _floatIndex ] = value;
        _floatIndex ++;
      }
    }

    protected void _AddInt( int value )
    {
      if ( _intIndex >= _ints.Count )
      {
        _ints.Add( value );
        _intIndex = _floats.Count;
      }
      else
      {
        _ints[ _intIndex ] = value;
        _intIndex ++;
      }
    }

    public void Add( params float[] values )
    {
      for ( int i = 0; i < values.Length; i++ )
      {
        _AddFloat( values[ i ] );
      }
    }

    protected void _AddVector2( Vector2 value )
    {
      _AddFloat( value.X );
      _AddFloat( value.Y ); 
    }

    protected void _AddVector2I( Vector2I value )
    {
      _AddInt( value.X );
      _AddInt( value.Y ); 
    }

    public void Add( params Vector2[] values )
    {
      for ( int i = 0; i < values.Length; i++ )
      {
        _AddVector2( values[ i ] );
      }
    }

    public void Add( params Vector2I[] values )
    {
      for ( int i = 0; i < values.Length; i++ )
      {
        _AddVector2I( values[ i ] );
      }
    }

    protected void _AddVector3( Vector3 value )
    {
      _AddFloat( value.X );
      _AddFloat( value.Y ); 
      _AddFloat( value.Z ); 
    }

    protected void _AddVector3I( Vector3I value )
    {
      _AddInt( value.X );
      _AddInt( value.Y ); 
      _AddInt( value.Z ); 
    }

    public void Add( params Vector3[] values )
    {
      for ( int i = 0; i < values.Length; i++ )
      {
        _AddVector3( values[ i ] );
      }
    }
    
    public void Add( params Vector3I[] values )
    {
      for ( int i = 0; i < values.Length; i++ )
      {
        _AddVector3I( values[ i ] );
      }
    }

    protected void _AddVector4( Vector4 value )
    {
      _AddFloat( value.X );
      _AddFloat( value.Y ); 
      _AddFloat( value.Z ); 
      _AddFloat( value.W ); 
    } 

    public void Add( params Vector4[] values )
    {
      for ( int i = 0; i < values.Length; i++ )
      {
        _AddVector4( values[ i ] );
      }
    }
 

    

    public void Add( params int[] values )
    {
      for ( int i = 0; i < values.Length; i++ )
      {
        _AddInt( values[ i ] );
      }
    }

    public byte[] bytes
    {
      get 
      {
        var numBytes = ( _intIndex + _floatIndex ) * 4;

        while ( numBytes % 16 != 0 )
        {
          numBytes ++;
        }

        if ( _bytes == null || _bytes.Length != numBytes )
        {
          _bytes = new byte[ numBytes ];
        }

        for ( int i = 0; i < _floats.Count; i++ )
        {
          var floatBytes = BitConverter.GetBytes( _floats[ i ] );
          Array.Copy( floatBytes, 0, _bytes, i * 4, 4 );
        }

        var floatsOffset = _floats.Count * 4;

        for ( int i = 0; i < _ints.Count; i++ )
        {
          var intBytes = BitConverter.GetBytes( _ints[ i ] );
          Array.Copy( intBytes, 0, _bytes, i * 4 + floatsOffset, 4 );
        }

        var intsOffset = _ints.Count * 4;

        for ( int i = intsOffset + floatsOffset; i < _bytes.Length; i++ )
        {
          _bytes[ i ] = 0;
        }

        return _bytes;
      }
    }
    
  }   
}