// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;

import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.kotlin.KotlinInfo;
import com.android.tools.r8.origin.Origin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

public class DexProgramClass extends DexClass implements Supplier<DexProgramClass> {

  private static final DexEncodedArray SENTINEL_NOT_YET_COMPUTED =
      new DexEncodedArray(new DexValue[0]);

  private final ProgramResource.Kind originKind;
  private DexEncodedArray staticValues = SENTINEL_NOT_YET_COMPUTED;
  private final Collection<DexProgramClass> synthesizedFrom;
  private int classFileVersion = -1;
  private KotlinInfo kotlinInfo = null;

  public DexProgramClass(
      DexType type,
      ProgramResource.Kind originKind,
      Origin origin,
      ClassAccessFlags accessFlags,
      DexType superType,
      DexTypeList interfaces,
      DexString sourceFile,
      EnclosingMethodAttribute enclosingMember,
      List<InnerClassAttribute> innerClasses,
      DexAnnotationSet classAnnotations,
      DexEncodedField[] staticFields,
      DexEncodedField[] instanceFields,
      DexEncodedMethod[] directMethods,
      DexEncodedMethod[] virtualMethods,
      boolean skipNameValidationForTesting) {
    this(
        type,
        originKind,
        origin,
        accessFlags,
        superType,
        interfaces,
        sourceFile,
        enclosingMember,
        innerClasses,
        classAnnotations,
        staticFields,
        instanceFields,
        directMethods,
        virtualMethods,
        skipNameValidationForTesting,
        Collections.emptyList());
  }

  public DexProgramClass(
      DexType type,
      ProgramResource.Kind originKind,
      Origin origin,
      ClassAccessFlags accessFlags,
      DexType superType,
      DexTypeList interfaces,
      DexString sourceFile,
      EnclosingMethodAttribute enclosingMember,
      List<InnerClassAttribute> innerClasses,
      DexAnnotationSet classAnnotations,
      DexEncodedField[] staticFields,
      DexEncodedField[] instanceFields,
      DexEncodedMethod[] directMethods,
      DexEncodedMethod[] virtualMethods,
      boolean skipNameValidationForTesting,
      Collection<DexProgramClass> synthesizedDirectlyFrom) {
    super(
        sourceFile,
        interfaces,
        accessFlags,
        superType,
        type,
        staticFields,
        instanceFields,
        directMethods,
        virtualMethods,
        enclosingMember,
        innerClasses,
        classAnnotations,
        origin,
        skipNameValidationForTesting);
    assert classAnnotations != null;
    this.originKind = originKind;
    this.synthesizedFrom = accumulateSynthesizedFrom(new HashSet<>(), synthesizedDirectlyFrom);
  }

  public boolean originatesFromDexResource() {
    return originKind == Kind.DEX;
  }

  public boolean originatesFromClassResource() {
    return originKind == Kind.CF;
  }

  @Override
  public void collectIndexedItems(IndexedItemCollection indexedItems,
      DexMethod method, int instructionOffset) {
    if (indexedItems.addClass(this)) {
      type.collectIndexedItems(indexedItems, method, instructionOffset);
      if (superType != null) {
        superType.collectIndexedItems(indexedItems, method, instructionOffset);
      } else {
        assert type.toDescriptorString().equals("Ljava/lang/Object;");
      }
      if (sourceFile != null) {
        sourceFile.collectIndexedItems(indexedItems, method, instructionOffset);
      }
      if (annotations != null) {
        annotations.collectIndexedItems(indexedItems, method, instructionOffset);
      }
      if (interfaces != null) {
        interfaces.collectIndexedItems(indexedItems, method, instructionOffset);
      }
      if (getEnclosingMethod() != null) {
        getEnclosingMethod().collectIndexedItems(indexedItems);
      }
      for (InnerClassAttribute attribute : getInnerClasses()) {
        attribute.collectIndexedItems(indexedItems);
      }
      synchronizedCollectAll(indexedItems, staticFields);
      synchronizedCollectAll(indexedItems, instanceFields);
      synchronizedCollectAll(indexedItems, directMethods);
      synchronizedCollectAll(indexedItems, virtualMethods);
    }
  }

  private static <T extends DexItem> void synchronizedCollectAll(IndexedItemCollection collection,
      T[] items) {
    synchronized (items) {
      collectAll(collection, items);
    }
  }

  public Collection<DexProgramClass> getSynthesizedFrom() {
    return synthesizedFrom;
  }

  @Override
  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
    assert getEnclosingMethod() == null;
    assert getInnerClasses().isEmpty();
    if (hasAnnotations()) {
      mixedItems.setAnnotationsDirectoryForClass(this, new DexAnnotationDirectory(this));
    }
  }

  @Override
  public void addDependencies(MixedSectionCollection collector) {
    assert getEnclosingMethod() == null;
    assert getInnerClasses().isEmpty();
    // We only have a class data item if there are methods or fields.
    if (hasMethodsOrFields()) {
      collector.add(this);

      // The ordering of methods and fields may not be deterministic due to concurrency
      // (see b/116027780).
      synchronizedCollectAll(collector, sortedCopyIfPotentiallyNotSorted(directMethods));
      synchronizedCollectAll(collector, sortedCopyIfPotentiallyNotSorted(virtualMethods));
      synchronizedCollectAll(collector, sortedCopyIfPotentiallyNotSorted(staticFields));
      synchronizedCollectAll(collector, sortedCopyIfPotentiallyNotSorted(instanceFields));
    }
    if (annotations != null) {
      annotations.collectMixedSectionItems(collector);
    }
    if (interfaces != null) {
      interfaces.collectMixedSectionItems(collector);
    }
    annotations.collectMixedSectionItems(collector);
  }

  private static <T extends KeyedDexItem<S>, S extends PresortedComparable<S>>
      T[] sortedCopyIfPotentiallyNotSorted(T[] items) {
    if (items.length > 1) {
      T[] sorted = items.clone();
      Arrays.sort(sorted, Comparator.comparing(KeyedDexItem::getKey));
      return sorted;
    }
    return items;
  }

  private static <T extends DexItem> void synchronizedCollectAll(MixedSectionCollection collection,
      T[] items) {
    synchronized (items) {
      collectAll(collection, items);
    }
  }

  @Override
  public String toString() {
    return type.toString();
  }

  @Override
  public String toSourceString() {
    return type.toSourceString();
  }

  @Override
  public boolean isProgramClass() {
    return true;
  }

  @Override
  public DexProgramClass asProgramClass() {
    return this;
  }

  @Override
  public KotlinInfo getKotlinInfo() {
    return kotlinInfo;
  }

  public void setKotlinInfo(KotlinInfo kotlinInfo) {
    assert this.kotlinInfo == null || kotlinInfo == null;
    this.kotlinInfo = kotlinInfo;
  }

  public boolean hasMethodsOrFields() {
    int numberOfFields = staticFields().length + instanceFields().length;
    int numberOfMethods = directMethods().length + virtualMethods().length;
    return numberOfFields + numberOfMethods > 0;
  }

  public boolean hasAnnotations() {
    return !annotations.isEmpty()
        || hasAnnotations(virtualMethods)
        || hasAnnotations(directMethods)
        || hasAnnotations(staticFields)
        || hasAnnotations(instanceFields);
  }

  boolean hasOnlyInternalizableAnnotations() {
    return !hasAnnotations(virtualMethods)
        && !hasAnnotations(directMethods)
        && !hasAnnotations(staticFields)
        && !hasAnnotations(instanceFields);
  }

  private boolean hasAnnotations(DexEncodedField[] fields) {
    synchronized (fields) {
      return Arrays.stream(fields).anyMatch(DexEncodedField::hasAnnotation);
    }
  }

  private boolean hasAnnotations(DexEncodedMethod[] methods) {
    synchronized (methods) {
      return Arrays.stream(methods).anyMatch(DexEncodedMethod::hasAnnotation);
    }
  }

  private static Collection<DexProgramClass> accumulateSynthesizedFrom(
      Set<DexProgramClass> accumulated,
      Collection<DexProgramClass> toAccumulate) {
    for (DexProgramClass dexProgramClass : toAccumulate) {
      if (dexProgramClass.synthesizedFrom.isEmpty()) {
        accumulated.add(dexProgramClass);
      } else {
        accumulateSynthesizedFrom(accumulated, dexProgramClass.synthesizedFrom);
      }
    }
    return accumulated;
  }

  public void computeStaticValues(DexItemFactory factory) {
    // It does not actually hurt to compute this multiple times. So racing on staticValues is OK.
    if (staticValues == SENTINEL_NOT_YET_COMPUTED) {
      synchronized (staticFields) {
        assert PresortedComparable.isSorted(staticFields);
        DexEncodedField[] fields = staticFields;
        int length = 0;
        List<DexValue> values = new ArrayList<>(fields.length);
        for (int i = 0; i < fields.length; i++) {
          DexEncodedField field = fields[i];
          DexValue staticValue = field.getStaticValue();
          assert staticValue != null;
          values.add(staticValue);
          if (!staticValue.isDefault(field.field.type)) {
            length = i + 1;
          }
        }
        if (length > 0) {
          staticValues = new DexEncodedArray(
              values.subList(0, length).toArray(new DexValue[length]));
        } else {
          staticValues = null;
        }
      }
    }
  }

  public DexEncodedArray getStaticValues() {
    // The sentinel value is left over for classes that actually have no fields.
    if (staticValues == SENTINEL_NOT_YET_COMPUTED) {
      assert !hasMethodsOrFields();
      return null;
    }
    return staticValues;
  }

  public void addMethod(DexEncodedMethod method) {
    if (method.accessFlags.isStatic()
        || method.accessFlags.isPrivate()
        || method.accessFlags.isConstructor()) {
      addDirectMethod(method);
    } else {
      addVirtualMethod(method);
    }
  }

  public void addVirtualMethod(DexEncodedMethod virtualMethod) {
    assert !virtualMethod.accessFlags.isStatic();
    assert !virtualMethod.accessFlags.isPrivate();
    assert !virtualMethod.accessFlags.isConstructor();
    synchronized (virtualMethods) {
      virtualMethods = Arrays.copyOf(virtualMethods, virtualMethods.length + 1);
      virtualMethods[virtualMethods.length - 1] = virtualMethod;
    }
  }

  public void addDirectMethod(DexEncodedMethod staticMethod) {
    assert staticMethod.accessFlags.isStatic() || staticMethod.accessFlags.isPrivate()
        || staticMethod.accessFlags.isConstructor();
    synchronized (directMethods) {
      directMethods = Arrays.copyOf(directMethods, directMethods.length + 1);
      directMethods[directMethods.length - 1] = staticMethod;
    }
  }

  public void sortMembers() {
    sortEncodedFields(staticFields);
    sortEncodedFields(instanceFields);
    sortEncodedMethods(directMethods);
    sortEncodedMethods(virtualMethods);
  }

  private void sortEncodedFields(DexEncodedField[] fields) {
    synchronized (fields) {
      Arrays.sort(fields, Comparator.comparing(a -> a.field));
    }
  }

  private void sortEncodedMethods(DexEncodedMethod[] methods) {
    synchronized (methods) {
      Arrays.sort(methods, Comparator.comparing(a -> a.method));
    }
  }

  @Override
  public DexProgramClass get() {
    return this;
  }

  public void setClassFileVersion(int classFileVersion) {
    assert classFileVersion >= 0;
    this.classFileVersion = classFileVersion;
  }

  public boolean hasClassFileVersion() {
    return classFileVersion >= 0;
  }

  public int getClassFileVersion() {
    assert classFileVersion != -1;
    return classFileVersion;
  }
}
