/*
 * Copyright 2020, OpenTelemetry 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 io.opentelemetry.sdk.metrics.aggregator;

import com.google.errorprone.annotations.concurrent.GuardedBy;
import io.opentelemetry.sdk.metrics.data.MetricData.Point;
import io.opentelemetry.sdk.metrics.data.MetricData.SummaryPoint;
import io.opentelemetry.sdk.metrics.data.MetricData.ValueAtPercentile;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;

@ThreadSafe
public final class LongMinMaxSumCount extends AbstractAggregator {

  private static final AggregatorFactory AGGREGATOR_FACTORY =
      new AggregatorFactory() {
        @Override
        public Aggregator getAggregator() {
          return new LongMinMaxSumCount();
        }
      };

  // The current value. This controls its own internal thread-safety via method access. Don't
  // try to use its fields directly.
  private final LongSummary current = new LongSummary();

  public static AggregatorFactory getFactory() {
    return AGGREGATOR_FACTORY;
  }

  private LongMinMaxSumCount() {}

  @Override
  void doMergeAndReset(Aggregator target) {
    LongMinMaxSumCount other = (LongMinMaxSumCount) target;

    thinger(other);
  }

  private void thinger(LongMinMaxSumCount other) {
    current.mergeAndReset(other.current);
    //    LongSummary copy = current.copyAndReset();
    //    other.current.update(copy);
  }

  @Nullable
  @Override
  public Point toPoint(long startEpochNanos, long epochNanos, Map<String, String> labels) {
    return current.toPoint(startEpochNanos, epochNanos, labels);
  }

  @Override
  public void recordLong(long value) {
    current.record(value);
  }

  private static final class LongSummary {

    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    @GuardedBy("lock")
    private long sum = 0;

    @GuardedBy("lock")
    private long count = 0;

    @GuardedBy("lock")
    private long min = Long.MAX_VALUE;

    @GuardedBy("lock")
    private long max = Long.MIN_VALUE;

    private void record(long value) {
      lock.writeLock().lock();
      try {
        count++;
        sum += value;
        min = Math.min(value, min);
        max = Math.max(value, max);
      } finally {
        lock.writeLock().unlock();
      }
    }

    private void mergeAndReset(LongSummary other) {
      long myCount;
      long mySum;
      long myMin;
      long myMax;
      lock.writeLock().lock();
      try {
        if (this.count == 0) {
          return;
        }
        myCount = this.count;
        mySum = this.sum;
        myMin = this.min;
        myMax = this.max;
        this.count = 0;
        this.sum = 0;
        this.min = Long.MAX_VALUE;
        this.max = Long.MIN_VALUE;
      } finally {
        lock.writeLock().unlock();
      }
      other.lock.writeLock().lock();
      try {
        other.count += myCount;
        other.sum += mySum;
        other.min = Math.min(myMin, other.min);
        other.max = Math.max(myMax, other.max);
      } finally {
        other.lock.writeLock().unlock();
      }
    }

    @Nullable
    private SummaryPoint toPoint(
        long startEpochNanos, long epochNanos, Map<String, String> labels) {
      lock.readLock().lock();
      try {
        return count == 0
            ? null
            : SummaryPoint.create(
                startEpochNanos,
                epochNanos,
                labels,
                count,
                sum,
                Arrays.asList(
                    ValueAtPercentile.create(0.0, min), ValueAtPercentile.create(100.0, max)));
      } finally {
        lock.readLock().unlock();
      }
    }
  }
}

@@ -1829,210 +1829,43 @@
     
-thinger(other);%0A  %7D%0A%0A  private void thinger(LongMinMaxSumCount other) %7B%0A    current.mergeAndReset(other.current);%0A    //    LongSummary copy = current.copyAndReset();%0A    //    other.current.update(copy
+current.mergeAndReset(other.current
 );%0A 

remove some junk code that snuck in (#1327)