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

using System.Text;
using System.Globalization;
using System;
using Godot;


namespace Rokojori
{ 
  public enum ReferenceType
  {
    MEMBER_REFERENCE,
    ARRAY_LIST_REFERENCE,
    MAP_DICTIONARY_REFERENCE
  }

  public class Reference
  {
    public ReferenceType type;
    public object target;
    public int index;
    public string name;    

    public string GetInfo()
    {
      var accessorInfo = "";
      
      if ( ReferenceType.ARRAY_LIST_REFERENCE == type )
      {
        if ( target is JSONArray )
        {
          accessorInfo += "JSONArray[ " + index + " ]"; 
        }
        else if ( target is IList )
        {
          accessorInfo += "List[ " + index + " ]"; 
        }
        else
        {
          accessorInfo += "List/Array[ " + index + " ]"; 
        }
        
      }
      else if ( ReferenceType.MEMBER_REFERENCE == type )
      {
        accessorInfo += "Member[ " + name + " ]"; 
      }
      else if ( ReferenceType.MAP_DICTIONARY_REFERENCE == type )
      {
        if (  JSONSerializationSettings.IsSerializableDictionary( target ) )
        {
          var keyType = target.GetType().GetGenericArguments()[ 0 ];

          if ( typeof( int ) == keyType )
          {
            accessorInfo += "Dictionary[ " + index + " ]"; 
          }
          else if ( typeof( string ) == keyType )
          {
            accessorInfo += "Dictionary[ " + name + " ]"; 
          }
        }
        else if ( target is JSONObject )
        {
          accessorInfo += "JSONObject[ " + name + " ]";  
        }
        else
        {
          accessorInfo += "Map/Dictionary[ " + index + " ]";
        }
        
      }

      return accessorInfo + "@" + target;
    }

    public void AssignValue( object value )
    {
      if ( ReferenceType.ARRAY_LIST_REFERENCE == type )
      {
        if ( target is IList )
        {
          var list = ( (IList) target );
          var missing = Mathf.Max( 0, index - ( list.Count - 1 ) );
          
          for ( int i = 0; i < missing; i++ )
          {
            list.Add( null );
          }
          
          list[ index ] = value;
        }
        else if ( target is JSONArray )
        {
          ( (JSONArray) target ).Set( index, (JSONData) value );
        }
      }
      else if ( ReferenceType.MEMBER_REFERENCE == type )
      {
        if ( target is JSONObject )
        { 
          ( (JSONObject) target ).Set( name, (JSONData) value );
        } 
        else
        {
          ReflectionHelper.SetDataMemberValue( target, name, value );
        }
        
      }
      else if ( ReferenceType.MAP_DICTIONARY_REFERENCE == type )
      {
        if ( target is JSONObject )
        { 
          ( (JSONObject) target ).Set( name, (JSONData) value );
        } 
        else if ( JSONSerializationSettings.IsSerializableDictionary( target ) )
        {
          if ( typeof( string ) == target.GetType().GetGenericArguments()[ 0 ] )
          {
            ( (IDictionary) target )[ name ] = value;
          }
          else
          {
            ( (IDictionary) target )[ index ] = value;
          }
          
        }
      }
    }

    public Reference( object target, int index )
    {
      this.target = target;
      this.index  = index;

      if ( target is JSONObject || JSONSerializationSettings.IsSerializableDictionary( target ) )
      { 
        type = ReferenceType.MAP_DICTIONARY_REFERENCE; 
      }
      else
      {
        type = ReferenceType.ARRAY_LIST_REFERENCE;
      }  
    }

    public Reference( object target, string name )
    {      
      this.target = target;
      this.name  = name;

      if ( target is JSONObject || JSONSerializationSettings.IsSerializableDictionary( target ) )
      { 
        type = ReferenceType.MAP_DICTIONARY_REFERENCE; 
      }
      else
      {
        type = ReferenceType.MEMBER_REFERENCE;
      }  

    }


    

  }
}