// Copyright 2016 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.packages;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FunctionSignature;
import com.google.devtools.build.lib.syntax.SkylarkType;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;

/**
 * Declared provider defined in Skylark.
 *
 * <p>This is a result of calling {@code provider()} function from Skylark ({@link
 * com.google.devtools.build.lib.analysis.skylark.SkylarkRuleClassFunctions#provider}).
 */
public class SkylarkProvider extends Provider implements SkylarkExportable {

  private static final FunctionSignature.WithValues<Object, SkylarkType> SIGNATURE =
      FunctionSignature.WithValues.create(FunctionSignature.KWARGS);

  @Nullable private SkylarkKey key;
  @Nullable private String errorMessageFormatForInstances;

  private static final String DEFAULT_ERROR_MESSAFE = "Object has no '%s' attribute.";

  /**
   * Creates a Skylark-defined Declared Provider ({@link Info} constructor).
   *
   * <p>Needs to be exported later.
   */
  public SkylarkProvider(String name,
      @Nullable Iterable<String> fields,
      Location location) {
    this(name, buildSignature(fields), location);
  }

  private SkylarkProvider(
      String name,
      FunctionSignature.WithValues<Object, SkylarkType> signature, Location location) {
    super(name, signature, location);
    this.errorMessageFormatForInstances = DEFAULT_ERROR_MESSAFE;
  }

  private static FunctionSignature.WithValues<Object, SkylarkType> buildSignature(
      @Nullable  Iterable<String> fields) {
    if (fields == null) {
      return SIGNATURE;
    }
    return
        FunctionSignature.WithValues.create(
        FunctionSignature.namedOnly(0, ImmutableList.copyOf(fields).toArray(new String[0]))
    );
  }

  @Override
  protected Info createInstanceFromSkylark(Object[] args, Location loc) throws EvalException {
    if (signature.getSignature().getShape().hasKwArg()) {
      @SuppressWarnings("unchecked")
      Map<String, Object> kwargs = (Map<String, Object>) args[0];
      return new SkylarkInfo(this, kwargs, loc);
    } else {
      // todo(dslomov): implement shape sharing.
      ImmutableList<String> names = signature.getSignature().getNames();
      Preconditions.checkState(names.size() == args.length);
      ImmutableMap.Builder<String, Object> fields = ImmutableMap.builder();
      for (int i = 0; i < args.length; i++) {
        if (args[i] != null) {
          fields.put(names.get(i), args[i]);
        }
      }
      return new SkylarkInfo(this, fields.build(), loc);
    }
  }

  @Override
  public boolean isExported() {
    return key != null;
  }

  @Override
  public SkylarkKey getKey() {
    Preconditions.checkState(isExported());
    return key;
  }

  @Override
  public String getName() {
    return key != null ? key.getExportedName() : "<no name>";
  }

  @Override
  public String getPrintableName() {
    return getName();
  }

  @Override
  public String getErrorMessageFormatForInstances() {
    return errorMessageFormatForInstances;
  }

  @Override
  public void export(Label extensionLabel, String exportedName) {
    Preconditions.checkState(!isExported());
    this.key = new SkylarkKey(extensionLabel, exportedName);
    this.errorMessageFormatForInstances =
        String.format("'%s' object has no attribute '%%s'", exportedName);
  }

  @Override
  public int hashCode() {
    if (isExported()) {
      return getKey().hashCode();
    }
    return System.identityHashCode(this);
  }

  @Override
  public boolean equals(@Nullable Object otherObject) {
    if (!(otherObject instanceof SkylarkProvider)) {
      return false;
    }
    SkylarkProvider other = (SkylarkProvider) otherObject;

    if (this.isExported() && other.isExported()) {
      return this.getKey().equals(other.getKey());
    } else {
      return this == other;
    }
  }

  @Override
  public boolean isImmutable() {
    // Hash code for non exported constructors may be changed
    return isExported();
  }

  @Override
  public void repr(SkylarkPrinter printer) {
    printer.append("<provider>");
  }

  /**
   * A serializable representation of Skylark-defined {@link SkylarkProvider} that uniquely
   * identifies all {@link SkylarkProvider}s that are exposed to SkyFrame.
   */
  public static class SkylarkKey extends Key {
    private final Label extensionLabel;
    private final String exportedName;

    public SkylarkKey(Label extensionLabel, String exportedName) {
      this.extensionLabel = Preconditions.checkNotNull(extensionLabel);
      this.exportedName = Preconditions.checkNotNull(exportedName);
    }

    public Label getExtensionLabel() {
      return extensionLabel;
    }

    public String getExportedName() {
      return exportedName;
    }

    @Override
    public String toString() {
      return exportedName;
    }

    @Override
    public int hashCode() {
      return Objects.hash(extensionLabel, exportedName);
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      }

      if (!(obj instanceof SkylarkKey)) {
        return false;
      }
      SkylarkKey other = (SkylarkKey) obj;
      return Objects.equals(this.extensionLabel, other.extensionLabel)
          && Objects.equals(this.exportedName, other.exportedName);
    }
  }
}
