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

using System.Text;







namespace Rokojori
{
  public class JSONObject:JSONData
  {
    List<string> _keys = new List<string>();
    List<JSONData> _values = new List<JSONData>();

    public override JSONDataType dataType 
    {
      get { return JSONDataType.OBJECT; }
    }

    public List<string> keys { get { return _keys; }}
    public List<JSONData> values { get { return _values; }}

    public int size { get { return _keys.Count; } }

    public JSONData Get( string key )     
    {
      var index = _keys.IndexOf( key );
      return index == -1 ? null : _values[ index ];  
    }

    public bool HasKey( string key )
    {
      return keys.IndexOf( key ) != -1;
    }

    public string GetString( string key ){ return Get( key ).stringValue; }
    public double GetNumber( string key ){ return Get( key ).numberValue; }
    public int GetInt( string key ){ return Get( key ).intValue; }
    public float GetFloat( string key ){ return Get( key ).floatValue; }
    public bool GetBoolean( string key ){ return Get( key ).booleanValue; }

    public T ByPath<T>( params string[] path) where T:JSONData
    {
      JSONData it = this;

      for ( int  i = 0; i < path.Length; i++ )
      {
        var isLast = i == ( path.Length - 1 );

        if ( ! ( isLast || it.dataType == JSONDataType.OBJECT || it.dataType == JSONDataType.ARRAY ) )
        {
          return null;
        }

        if ( it.dataType == JSONDataType.OBJECT )
        {
          it = ( (JSONObject)it ).Get( path[ i ] );
        }
        else if ( it.dataType == JSONDataType.ARRAY )
        {
          var index = RegexUtility.ParseInt( path[ i ], -1 );
          it = ( (JSONArray) it ).Get( index );
        }

        if ( it == null )
        {
          return null;
        }
      }

      return it as T;
    }

    public JSONObject GetObject( string key )
    {
      var data = Get( key );  

      if ( data == null )
      {
        return null;
      }

      return data.AsObject();
    }

    public JSONArray GetArray( string key )
    {
      var data = Get( key );  

      if ( data == null )
      {
        return null;
      }

      return data.AsArray();
    }

    public T GetEnum<T>( string key )
    {
      var value = System.Enum.Parse( typeof( T ), GetString( key ) );
      return (T) value;
    }

    public double GetNumberOr( string key, double defaultFallback )
    {
      var index = _keys.IndexOf( key );

      if ( index != -1 )
      {
        var value = _values[ index ];
        return value.isNumber ? value.numberValue : defaultFallback;
      }

      return defaultFallback;
    }

    public bool Contains( string key )
    {
      return _keys.Contains( key );
    }

    public void Delete( string key )
    {
      var index = _keys.IndexOf( key );
      
      if ( index != -1 )
      {
        _keys.RemoveAt( index );
        _values.RemoveAt( index );
      }
    }

    public void Set( string key, JSONData value )
    {
      var index = _keys.IndexOf( key );
      
      if ( index == -1 ) 
      {
        _keys.Add( key );
        _values.Add( value );
      }
      else
      {
        _values[ index ] = value;
      }

    }

    public void Set( string key, double value ){ Set( key, new JSONValue( value ) ); } 
    public void Set( string key, string value ){ Set( key, new JSONValue( value ) ); } 
    public void Set( string key, bool value ){ Set( key, new JSONValue( value ) ); } 
    public void SetEnum<T>( string key, object value)
    {
      var stringValue = System.Enum.GetName( typeof( T ), value );
      Set( key, stringValue );
    }
   
    public override string Stringify( StringifyOptions options )
    {
      options.increaseIndent();
      var builder = new StringBuilder();

      if ( values.Count == 0 )
      {
        builder.Append( "{}" );
        options.decreaseIndent();
        return builder.ToString();
      }

      
      builder.Append( "{\n" );      

      if ( values.Count > 0 )
      {
        builder.Append( options.indent );
        JSONStringConverter.Write( builder, keys[ 0 ] );
        builder.Append( ": " );
        builder.Append( values[ 0 ].Stringify( options ) );
      }

      for ( var i = 1; i < values.Count; i++ )
      {
        builder.Append( ",\n" );
        builder.Append( options.indent );
        JSONStringConverter.Write( builder, keys[ i ] );
        builder.Append( ": " );
        builder.Append( values[ i ].Stringify( options ) );
      }

      options.decreaseIndent();
      builder.Append( "\n" );
      builder.Append( options.indent );
      builder.Append( "}" );
      
      

      return builder.ToString();
    }


  }
}