package com.airbnb.lottie.parser;

import android.graphics.Color;
import android.graphics.PointF;
import androidx.annotation.ColorInt;
import android.util.JsonToken;

import com.airbnb.lottie.parser.moshi.JsonReader;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

class JsonUtils {
  private JsonUtils() {
  }

  /**
   * [r,g,b]
   */
  @ColorInt static int jsonToColor(JsonReader reader) throws IOException {
    reader.beginArray();
    int r = (int) (reader.nextDouble() * 255);
    int g = (int) (reader.nextDouble() * 255);
    int b = (int) (reader.nextDouble() * 255);
    while (reader.hasNext()) {
      reader.skipValue();
    }
    reader.endArray();
    return Color.argb(255, r, g, b);
  }

  static List<PointF> jsonToPoints(JsonReader reader, float scale) throws IOException {
    List<PointF> points = new ArrayList<>();

    reader.beginArray();
    while (reader.peek() == JsonReader.Token.BEGIN_ARRAY) {
      reader.beginArray();
      points.add(jsonToPoint(reader, scale));
      reader.endArray();
    }
    reader.endArray();
    return points;
  }

  static PointF jsonToPoint(JsonReader reader, float scale) throws IOException {
    switch (reader.peek()) {
      case NUMBER: return jsonNumbersToPoint(reader, scale);
      case BEGIN_ARRAY: return jsonArrayToPoint(reader, scale);
      case BEGIN_OBJECT: return jsonObjectToPoint(reader, scale);
      default: throw new IllegalArgumentException("Unknown point starts with " + reader.peek());
    }
  }

  private static PointF jsonNumbersToPoint(JsonReader reader, float scale) throws IOException {
    float x = (float) reader.nextDouble();
    float y = (float) reader.nextDouble();
    while (reader.hasNext()) {
      reader.skipValue();
    }
    return new PointF(x * scale, y * scale);
  }

  private static PointF jsonArrayToPoint(JsonReader reader, float scale) throws IOException {
    float x;
    float y;
    reader.beginArray();
    x = (float) reader.nextDouble();
    y = (float) reader.nextDouble();
    while (reader.peek() != JsonReader.Token.END_ARRAY) {
      reader.skipValue();
    }
    reader.endArray();
    return new PointF(x * scale, y * scale);
  }

  private static final JsonReader.Options POINT_NAMES = JsonReader.Options.of("x", "y");

  private static PointF jsonObjectToPoint(JsonReader reader, float scale) throws IOException {
    float x = 0f;
    float y = 0f;
    reader.beginObject();
    while (reader.hasNext()) {
      switch (reader.selectName(POINT_NAMES)) {
        case 0:
          x = valueFromObject(reader);
          break;
        case 1:
          y = valueFromObject(reader);
          break;
        default:
          reader.skipName();
          reader.skipValue();
      }
    }
    reader.endObject();
    return new PointF(x * scale, y * scale);
  }

  static float valueFromObject(JsonReader reader) throws IOException {
    JsonReader.Token token = reader.peek();
    switch (token) {
      case NUMBER:
        return (float) reader.nextDouble();
      case BEGIN_ARRAY:
        reader.beginArray();
        float val = (float) reader.nextDouble();
        while (reader.hasNext()) {
          reader.skipValue();
        }
        reader.endArray();
        return val;
      default:
        throw new IllegalArgumentException("Unknown value for token of type " + token);
    }
  }
}
