// Copyright (C) 2015 The Android Open Source Project
//
// 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.gerrit.metrics;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/** Describes a metric created by {@link MetricMaker}. */
public class Description {
  public static final String DESCRIPTION = "DESCRIPTION";
  public static final String UNIT = "UNIT";
  public static final String CUMULATIVE = "CUMULATIVE";
  public static final String RATE = "RATE";
  public static final String GAUGE = "GAUGE";
  public static final String CONSTANT = "CONSTANT";
  public static final String FIELD_ORDERING = "FIELD_ORDERING";
  public static final String TRUE_VALUE = "1";

  public static class Units {
    public static final String SECONDS = "seconds";
    public static final String MILLISECONDS = "milliseconds";
    public static final String MICROSECONDS = "microseconds";
    public static final String NANOSECONDS = "nanoseconds";

    public static final String BYTES = "bytes";

    private Units() {
    }
  }

  public enum FieldOrdering {
    /** Default ordering places fields at end of the parent metric name. */
    AT_END,

    /**
     * Splits the metric name by inserting field values before the last '/' in
     * the metric name. For example {@code "plugins/replication/push_latency"}
     * with a {@code Field.ofString("remote")} will create submetrics named
     * {@code "plugins/replication/some-server/push_latency"}.
     */
    PREFIX_FIELDS_BASENAME;
  }

  private final Map<String, String> annotations;

  /**
   * Describe a metric.
   *
   * @param helpText a short one-sentence string explaining the values captured
   *        by the metric. This may be made available to administrators as
   *        documentation in the reporting tools.
   */
  public Description(String helpText) {
    annotations = Maps.newLinkedHashMapWithExpectedSize(4);
    annotations.put(DESCRIPTION, helpText);
  }

  /** Set unit used to describe the value.
   *
   * @param unitName name of the unit, e.g. "requests", "seconds", etc.
   * @return this
   */
  public Description setUnit(String unitName) {
    annotations.put(UNIT, unitName);
    return this;
  }

  /**
   * Mark the value as constant for the life of this process. Typically used for
   * software versions, command line arguments, etc. that cannot change without
   * a process restart.
   *
   * @return this
   */
  public Description setConstant() {
    annotations.put(CONSTANT, TRUE_VALUE);
    return this;
  }

  /**
   * Indicates the metric may be usefully interpreted as a count over short
   * periods of time, such as request arrival rate. May only be applied to a
   * {@link Counter0}.
   *
   * @return this
   */
  public Description setRate() {
    annotations.put(RATE, TRUE_VALUE);
    return this;
  }

  /**
   * Instantaneously sampled value that may increase or decrease at a later
   * time. Memory allocated or open network connections are examples of gauges.
   *
   * @return this
   */
  public Description setGauge() {
    annotations.put(GAUGE, TRUE_VALUE);
    return this;
  }

  /**
   * Indicates the metric accumulates over the lifespan of the process. A
   * {@link Counter0} like total requests handled accumulates over the process
   * and should be {@code setCumulative()}.
   *
   * @return this
   */
  public Description setCumulative() {
    annotations.put(CUMULATIVE, TRUE_VALUE);
    return this;
  }

  /**
   * Configure how fields are ordered into submetric names.
   *
   * @param ordering field ordering
   * @return this
   */
  public Description setFieldOrdering(FieldOrdering ordering) {
    annotations.put(FIELD_ORDERING, ordering.name());
    return this;
  }

  /** @return true if the metric value never changes after startup. */
  public boolean isConstant() {
    return TRUE_VALUE.equals(annotations.get(CONSTANT));
  }

  /** @return true if the metric may be interpreted as a rate over time. */
  public boolean isRate() {
    return TRUE_VALUE.equals(annotations.get(RATE));
  }

  /** @return true if the metric is an instantaneous sample. */
  public boolean isGauge() {
    return TRUE_VALUE.equals(annotations.get(GAUGE));
  }

  /** @return true if the metric accumulates over the lifespan of the process. */
  public boolean isCumulative() {
    return TRUE_VALUE.equals(annotations.get(CUMULATIVE));
  }

  /** @return the suggested field ordering. */
  public FieldOrdering getFieldOrdering() {
    String o = annotations.get(FIELD_ORDERING);
    return o != null ? FieldOrdering.valueOf(o) : FieldOrdering.AT_END;
  }

  /**
   * Decode the unit as a unit of time.
   *
   * @return valid time unit.
   * @throws IllegalArgumentException if the unit is not a valid unit of time.
   */
  public TimeUnit getTimeUnit() {
    return getTimeUnit(annotations.get(UNIT));
  }

  private static final ImmutableMap<String, TimeUnit> TIME_UNITS = ImmutableMap.of(
      Units.NANOSECONDS, TimeUnit.NANOSECONDS,
      Units.MICROSECONDS, TimeUnit.MICROSECONDS,
      Units.MILLISECONDS, TimeUnit.MILLISECONDS,
      Units.SECONDS, TimeUnit.SECONDS);

  public static TimeUnit getTimeUnit(String unit) {
    if (Strings.isNullOrEmpty(unit)) {
      throw new IllegalArgumentException("no unit configured");
    }
    TimeUnit u = TIME_UNITS.get(unit);
    if (u == null) {
      throw new IllegalArgumentException(String.format(
          "unit %s not TimeUnit", unit));
    }
    return u;
  }

  /** @return immutable copy of all annotations (configurable properties). */
  public ImmutableMap<String, String> getAnnotations() {
    return ImmutableMap.copyOf(annotations);
  }

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