using System.Globalization;
using System.Text;

namespace MajacloudSdk.Internal
{
    /// <summary>Compact, culture-invariant JSON writer.</summary>
    internal static class JsonWriter
    {
        public static void Write(JsonNode node, StringBuilder sb)
        {
            if (node == null)
            {
                sb.Append("null");
                return;
            }
            switch (node.Type)
            {
                case JsonType.Null: sb.Append("null"); break;
                case JsonType.Bool: sb.Append(node.BoolValue ? "true" : "false"); break;
                case JsonType.Number:
                    if (node.IsInteger) sb.Append(node.LongValue.ToString(CultureInfo.InvariantCulture));
                    else if (double.IsNaN(node.NumberValue) || double.IsInfinity(node.NumberValue)) sb.Append("null");
                    else sb.Append(node.NumberValue.ToString("R", CultureInfo.InvariantCulture));
                    break;
                case JsonType.String: WriteString(node.StringValue, sb); break;
                case JsonType.Array:
                    sb.Append('[');
                    for (int i = 0; i < node.Items.Count; i++)
                    {
                        if (i > 0) sb.Append(',');
                        Write(node.Items[i], sb);
                    }
                    sb.Append(']');
                    break;
                case JsonType.Object:
                    sb.Append('{');
                    for (int i = 0; i < node.Fields.Count; i++)
                    {
                        if (i > 0) sb.Append(',');
                        WriteString(node.Fields[i].Key, sb);
                        sb.Append(':');
                        Write(node.Fields[i].Value, sb);
                    }
                    sb.Append('}');
                    break;
            }
        }

        public static void WriteString(string value, StringBuilder sb)
        {
            sb.Append('"');
            if (value != null)
            {
                foreach (char c in value)
                {
                    switch (c)
                    {
                        case '"': sb.Append("\\\""); break;
                        case '\\': sb.Append("\\\\"); break;
                        case '\b': sb.Append("\\b"); break;
                        case '\f': sb.Append("\\f"); break;
                        case '\n': sb.Append("\\n"); break;
                        case '\r': sb.Append("\\r"); break;
                        case '\t': sb.Append("\\t"); break;
                        default:
                            if (c < 0x20)
                            {
                                sb.Append("\\u");
                                sb.Append(((int)c).ToString("x4", CultureInfo.InvariantCulture));
                            }
                            else sb.Append(c);
                            break;
                    }
                }
            }
            sb.Append('"');
        }
    }
}
