package ru.yandex.webmaster3.coordinator.http.util;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author aherman
 */
public class ImportMetrics {
    private static final Logger log = LoggerFactory.getLogger(ImportMetrics.class);

    private final long startTime = System.nanoTime();
    private AtomicLong inserted = new AtomicLong();
    private AtomicLong skipped = new AtomicLong();
    private AtomicLong errors = new AtomicLong();

    private AtomicLong lastReport = new AtomicLong();

    private static volatile int refCount = 0;
    private static volatile ImportMetrics currentMetric = null;

    public static synchronized ImportMetrics acquire() {
        ImportMetrics importMetrics = currentMetric;
        if (importMetrics == null) {
            refCount += 1;
            importMetrics = new ImportMetrics();
            currentMetric = importMetrics;
        }

        return importMetrics;
    }

    public static synchronized void release() {
        refCount -= 1;
        if (refCount == 0) {
            currentMetric = null;
        }
    }

    public void inserted(long inserted) {
        this.inserted.addAndGet(inserted);
        report();
    }

    public synchronized void skip() {
        this.skipped.incrementAndGet();
        report();
    }

    public synchronized void errors(long errors) {
        this.errors.addAndGet(errors);
        report();
    }

    private void report() {
        long curInserted = this.inserted.get();
        long curSkipped = this.skipped.get();
        long curErrors = this.errors.get();

        long total = curInserted + curSkipped + curErrors;
        long previousTotal = lastReport.get();
        if (total - previousTotal < 500000) {
            return;
        }
        if (!this.lastReport.compareAndSet(previousTotal, total)) {
            return;
        }

        long dur = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime) + 1;
        log.info("Inserted: {} {} {} {} {}",
                curInserted,
                formatLinesPerSecond(curInserted * 1.0f / dur),
                curSkipped,
                curErrors,
                formatLinesPerSecond(total * 1.0f / dur));
    }

    private String formatLinesPerSecond(float ins) {
        if (ins > 1000000.0f) {
            return String.format("%03.2f ml/s", ins / 1000000.0f);
        } else if (ins > 1000.0f) {
            return String.format("%03.2f kl/s", ins / 1000.0f);
        } else {
            return String.format("%03.2f  l/s", ins);
        }
    }
}
