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

using System.Text;




namespace Rokojori
{
  public enum JSONDataType
  {
    BOOLEAN,
    NUMBER,
    STRING,
    OBJECT,
    ARRAY,
    NULL
  }

  public class StringifyOptions
  {
    public bool pretty = true;
    public string indentString = "  ";
    
    int _indentLevel = -1;
    string _indent = "";

    public void increaseIndent(){ _indentLevel++; UpdateIndent(); }
    public void decreaseIndent(){ _indentLevel--; UpdateIndent(); }

    public string indent{ get { return _indent; }}
    
    void UpdateIndent()
    { 
      _indent = "";

      for ( var i = 0; i < _indentLevel; i++ )
      {
        _indent += indentString;
      }      
    }
  }

  public abstract class JSONData
  {
    public abstract JSONDataType dataType { get; }
    public abstract string Stringify( StringifyOptions options );
    
    public string Stringify()
    {
      return Stringify( new StringifyOptions() );
    }

    public bool isArray
    {
      get { return dataType == JSONDataType.ARRAY; }
    }

    public bool isObject
    {
      get { return dataType == JSONDataType.OBJECT; }  
    }

    public bool isNull
    {
      get { return dataType == JSONDataType.NULL; }
    }

    public bool isNotNull
    {
      get { return dataType != JSONDataType.NULL; }
    }

    public bool isNumber
    {
      get { return dataType == JSONDataType.NUMBER; }
    }    

    public bool isBoolean
    {
      get { return dataType == JSONDataType.BOOLEAN; }
    }    

    public bool isString
    {
      get { return dataType == JSONDataType.STRING; }
    }
    
    public JSONArray AsArray()
    {
      if ( isArray )
      {
        return (JSONArray)this;
      }

      return null;
    }

    public JSONObject AsObject()
    {
      if ( isObject )
      {
        return (JSONObject)this;
      }
      
      return null;
    }
    
    
    public static int GetInt( JSONData data, int alternative = 0 )
    {
      if ( data == null || ! data.isNumber )
      { 
        return alternative; 
      }
      
      return data.intValue;
    }

    public static float GetFloat( JSONData data, float alternative = 0 )
    {
      if ( data == null || ! data.isNumber )
      { 
        return alternative;
      }
      
      return data.floatValue;
    }

    public static double GetNumber( JSONData data, double alternative = 0 )
    {
      if ( data == null || ! data.isNumber )
      { 
        return alternative; 
      }
      
      return data.numberValue;
    }

    public static bool GetBool( JSONData data, bool alternative = false )
    {
      if ( data == null || ! data.isBoolean )
      { 
        return alternative; 
      }
      
      return data.booleanValue;
    }

    public static string GetString( JSONData data, string alternative = "" )
    {
      if ( data == null || ! data.isString )
      { 
        return alternative;
      }
      
      return data.stringValue;
    }

    public double numberValue
    {
      get
      {
        var value = (JSONValue) this;
        return value.GetNumberValue();
      }
    }

    public float floatValue
    {
      get 
      {
        var value = (JSONValue) this;
        return value.GetFloatValue();
      }
    }


    public int intValue
    {
      get 
      {
        var value = (JSONValue) this;
        return value.GetIntValue();       
      }
    }

    public bool booleanValue
    {
      get
      {
       var value = (JSONValue) this;
       return value.GetBooleanValue();
      }
    }

    public string stringValue
    {
      get
      {
        var value = (JSONValue) this;
        return value.GetStringValue();
      }
    }
    
    
    public object enumValue( System.Type enumType )
    {
      var value = intValue;
      try
      {
        var enumValue = System.Enum.ToObject( enumType , intValue );
        return enumValue;
      }
      catch ( System.Exception e )
      {
        RJLog.Log(
          "Exception:", e, "\n",
          "Couldn't parse enum value", value ,
          "JSON Data Type", dataType,
          "Stringified Value:", JSON.Stringify( this )
        );
      }
      
      return null;
    }


    
  }
}