package com.airbnb.lottie.parser;

import com.airbnb.lottie.LottieComposition;
import com.airbnb.lottie.animation.keyframe.PathKeyframe;
import com.airbnb.lottie.parser.moshi.JsonReader;
import com.airbnb.lottie.value.Keyframe;

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

class KeyframesParser {

  static JsonReader.Options NAMES = JsonReader.Options.of("k");

  private KeyframesParser() {
  }

  static <T> List<Keyframe<T>> parse(JsonReader reader,
                                     LottieComposition composition, float scale, ValueParser<T> valueParser)
      throws IOException {
    List<Keyframe<T>> keyframes = new ArrayList<>();

    if (reader.peek() == JsonReader.Token.STRING) {
      composition.addWarning("Lottie doesn't support expressions.");
      return keyframes;
    }

    reader.beginObject();
    while (reader.hasNext()) {
      switch (reader.selectName(NAMES)) {
        case 0:
          if (reader.peek() == JsonReader.Token.BEGIN_ARRAY) {
            reader.beginArray();

            if (reader.peek() == JsonReader.Token.NUMBER) {
              // For properties in which the static value is an array of numbers.
              keyframes.add(KeyframeParser.parse(reader, composition, scale, valueParser, false));
            } else {
              while (reader.hasNext()) {
                keyframes.add(KeyframeParser.parse(reader, composition, scale, valueParser, true));
              }
            }
            reader.endArray();
          } else {
            keyframes.add(KeyframeParser.parse(reader, composition, scale, valueParser, false));
          }
          break;
        default:
          reader.skipValue();
      }
    }
    reader.endObject();

    setEndFrames(keyframes);
    return keyframes;
  }

  /**
   * The json doesn't include end frames. The data can be taken from the start frame of the next
   * keyframe though.
   */
  public static <T> void setEndFrames(List<? extends Keyframe<T>> keyframes) {
    int size = keyframes.size();
    for (int i = 0; i < size - 1; i++) {
      // In the json, the keyframes only contain their starting frame.
      Keyframe<T> keyframe = keyframes.get(i);
      Keyframe<T> nextKeyframe = keyframes.get(i + 1);
      keyframe.endFrame = nextKeyframe.startFrame;
      if (keyframe.endValue == null && nextKeyframe.startValue != null) {
        keyframe.endValue = nextKeyframe.startValue;
        if (keyframe instanceof PathKeyframe) {
          ((PathKeyframe) keyframe).createPath();
        }
      }
    }
    Keyframe<?> lastKeyframe = keyframes.get(size - 1);
    if ((lastKeyframe.startValue == null || lastKeyframe.endValue == null) && keyframes.size() > 1) {
      // The only purpose the last keyframe has is to provide the end frame of the previous
      // keyframe.
      //noinspection SuspiciousMethodCalls
      keyframes.remove(lastKeyframe);
    }
  }
}
