// 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.errors.CompilationError;
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.Iterator;
import java.util.List;
import java.util.function.Supplier;

public class DexProgramClass extends DexClass implements Supplier<DexProgramClass> {

  @FunctionalInterface
  public interface ChecksumSupplier {
    long getChecksum(DexProgramClass programClass);
  }

  public static final DexProgramClass[] EMPTY_ARRAY = {};

  private static final DexEncodedArray SENTINEL_NOT_YET_COMPUTED =
      new DexEncodedArray(DexValue.EMPTY_ARRAY);

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

  private final ChecksumSupplier checksumSupplier;

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

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

  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).
      sortMembers();
      synchronizedCollectAll(collector, directMethods);
      synchronizedCollectAll(collector, virtualMethods);
      synchronizedCollectAll(collector, staticFields);
      synchronizedCollectAll(collector, instanceFields);
    }
    if (annotations != null) {
      annotations.collectMixedSectionItems(collector);
    }
    if (interfaces != null) {
      interfaces.collectMixedSectionItems(collector);
    }
    annotations.collectMixedSectionItems(collector);
  }

  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 boolean isNotProgramClass() {
    return false;
  }

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

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

  public boolean hasFields() {
    return instanceFields.length + staticFields.length > 0;
  }

  public boolean hasMethods() {
    return directMethods.length + virtualMethods.length > 0;
  }

  public boolean hasMethodsOrFields() {
    return hasMethods() || hasFields();
  }

  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);
    }
  }

  public void addSynthesizedFrom(DexProgramClass clazz) {
    if (clazz.synthesizedFrom.isEmpty()) {
      synthesizedFrom.add(clazz);
    } else {
      clazz.synthesizedFrom.forEach(this::addSynthesizedFrom);
    }
  }

  public void computeStaticValues() {
    // 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(Arrays.asList(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;
          }
        }
        staticValues =
            length > 0
                ? new DexEncodedArray(values.subList(0, length).toArray(DexValue.EMPTY_ARRAY))
                : null;
      }
    }
  }

  public boolean isSorted() {
    return isSorted(virtualMethods)
        && isSorted(directMethods)
        && isSorted(staticFields)
        && isSorted(instanceFields);
  }

  private static <T extends KeyedDexItem<S>, S extends PresortedComparable<S>> boolean isSorted(
      T[] items) {
    synchronized (items) {
      T[] sorted = items.clone();
      Arrays.sort(sorted, Comparator.comparing(KeyedDexItem::getKey));
      return Arrays.equals(items, sorted);
    }
  }
  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();
    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();
    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 setInitialClassFileVersion(int initialClassFileVersion) {
    assert this.initialClassFileVersion == -1 && initialClassFileVersion > 0;
    this.initialClassFileVersion = initialClassFileVersion;
  }

  public boolean hasClassFileVersion() {
    return initialClassFileVersion > -1;
  }

  public int getInitialClassFileVersion() {
    assert initialClassFileVersion > -1;
    return initialClassFileVersion;
  }

  /**
   * Is the class reachability sensitive.
   *
   * <p>A class is reachability sensitive if the
   * dalvik.annotation.optimization.ReachabilitySensitive annotation is on any field or method. When
   * that is the case, dead reference elimination is disabled and locals are kept alive for their
   * entire scope.
   */
  public boolean hasReachabilitySensitiveAnnotation(DexItemFactory factory) {
    for (DexEncodedMethod directMethod : directMethods) {
      for (DexAnnotation annotation : directMethod.annotations.annotations) {
        if (annotation.annotation.type == factory.annotationReachabilitySensitive) {
          return true;
        }
      }
    }
    for (DexEncodedMethod virtualMethod : virtualMethods) {
      for (DexAnnotation annotation : virtualMethod.annotations.annotations) {
        if (annotation.annotation.type == factory.annotationReachabilitySensitive) {
          return true;
        }
      }
    }
    for (DexEncodedField staticField : staticFields) {
      for (DexAnnotation annotation : staticField.annotations.annotations) {
        if (annotation.annotation.type == factory.annotationReachabilitySensitive) {
          return true;
        }
      }
    }
    for (DexEncodedField instanceField : instanceFields) {
      for (DexAnnotation annotation : instanceField.annotations.annotations) {
        if (annotation.annotation.type == factory.annotationReachabilitySensitive) {
          return true;
        }
      }
    }
    return false;
  }

  public static Iterable<DexProgramClass> asProgramClasses(
      Iterable<DexType> types, DexDefinitionSupplier definitions) {
    return () ->
        new Iterator<DexProgramClass>() {

          private final Iterator<DexType> iterator = types.iterator();

          private DexProgramClass next = findNext();

          @Override
          public boolean hasNext() {
            return next != null;
          }

          @Override
          public DexProgramClass next() {
            DexProgramClass current = next;
            next = findNext();
            return current;
          }

          private DexProgramClass findNext() {
            while (iterator.hasNext()) {
              DexType next = iterator.next();
              DexClass clazz = definitions.definitionFor(next);
              if (clazz != null && clazz.isProgramClass()) {
                return clazz.asProgramClass();
              }
            }
            return null;
          }
        };
  }

  public static long invalidChecksumRequest(DexProgramClass clazz) {
    throw new CompilationError(
        clazz + " has no checksum information while checksum encoding is requested", clazz.origin);
  }

  public static long checksumFromType(DexProgramClass clazz) {
    return clazz.type.hashCode();
  }

  public long getChecksum() {
    return checksumSupplier.getChecksum(this);
  }
}
