/*
 * Copyright (C) 2012 The Guava Authors
 *
 * 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.common.base;

import com.google.caliper.Benchmark;
import com.google.caliper.Param;
import java.util.Arrays;
import java.util.Collections;

/**
 * Some microbenchmarks for the {@link MoreObjects.ToStringHelper} class.
 *
 * @author Osvaldo Doederlein
 */
public class ToStringHelperBenchmark {

  @Param({"0", "1", "5"})
  int dataSize;

  @Param({"false", "true"})
  boolean omitNulls;

  enum Dataset {
    SMALL {
      void addEntries(MoreObjects.ToStringHelper helper) {
        helper
            .add(SHORT_NAME, 10)
            .addValue(10L)
            .add(SHORT_NAME, 3.14f)
            .addValue(3.14d)
            .add(LONG_NAME, false)
            .add(LONG_NAME, LONG_NAME);
      }
    },
    CONDITIONAL {
      void addEntries(MoreObjects.ToStringHelper helper) {
        helper
            .add(SHORT_NAME, "x")
            .add(LONG_NAME, "y")
            .add(SHORT_NAME, null)
            .add(LONG_NAME, null)
            .addValue("z")
            .addValue("")
            .addValue(null)
            .add(SHORT_NAME, Arrays.asList("A"))
            .add(LONG_NAME, Arrays.asList("B"))
            .add(SHORT_NAME, Arrays.asList())
            .add(LONG_NAME, Arrays.asList())
            .addValue(Arrays.asList("C"))
            .addValue(Arrays.asList())
            .add(SHORT_NAME, Collections.singletonMap("k1", "v1"))
            .add(LONG_NAME, Collections.singletonMap("k2", "v2"))
            .addValue(Collections.singletonMap("k3", "v3"))
            .addValue(Collections.emptyMap())
            .addValue(null)
            .add(SHORT_NAME, Optional.of("1"))
            .add(LONG_NAME, Optional.of("1"))
            .add(SHORT_NAME, Optional.absent())
            .add(LONG_NAME, Optional.absent())
            .add(SHORT_NAME, Optional.of("2"))
            .add(SHORT_NAME, Optional.absent())
            .addValue(null)
            .add(SHORT_NAME, new int[] {1})
            .add(LONG_NAME, new int[] {2})
            .addValue(new int[] {3})
            .addValue(new int[] {})
            .addValue(null);
      }
    },
    UNCONDITIONAL {
      void addEntries(MoreObjects.ToStringHelper helper) {
        helper
            .add(SHORT_NAME, false)
            .add(LONG_NAME, false)
            .addValue(true)
            .add(SHORT_NAME, (byte) 1)
            .add(LONG_NAME, (byte) 2)
            .addValue((byte) 3)
            .add(SHORT_NAME, 'A')
            .add(LONG_NAME, 'B')
            .addValue('C')
            .add(SHORT_NAME, (short) 4)
            .add(LONG_NAME, (short) 5)
            .addValue((short) 6)
            .add(SHORT_NAME, 7)
            .add(LONG_NAME, 8)
            .addValue(9)
            .add(SHORT_NAME, 10L)
            .add(LONG_NAME, 11L)
            .addValue(12L)
            .add(SHORT_NAME, 13.0f)
            .add(LONG_NAME, 14.0f)
            .addValue(15.0f);
      }
    };

    void addEntries(MoreObjects.ToStringHelper helper) {}
  }

  @Param Dataset dataset;

  private static final String SHORT_NAME = "userId";
  private static final String LONG_NAME = "fluxCapacitorFailureRate95Percentile";

  private MoreObjects.ToStringHelper newHelper() {
    MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper("klass");
    if (omitNulls) {
      helper = helper.omitNullValues();
    }
    return helper;
  }

  @Benchmark
  int toString(int reps) {
    int dummy = 0;
    for (int i = 0; i < reps; i++) {
      MoreObjects.ToStringHelper helper = newHelper();
      for (int j = 0; j < dataSize; ++j) {
        dataset.addEntries(helper);
      }
      dummy ^= helper.toString().hashCode();
    }
    return dummy;
  }

  // When omitEmptyValues() is released, remove this method and add a new @Param "omitEmptyValues".
}
