/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.config.commands.progress;

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

import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

public class ProgressManager_old implements Observer {

    private static final String DEFAULT = "_DEFAULT";

    private static final Logger LOG = LoggerFactory.getLogger("std");

	private final ConcurrentMap<String, Integer> totals = new ConcurrentHashMap<String, Integer>();

	private final ConcurrentMap<String, LongAdder> progresses = new ConcurrentHashMap<String, LongAdder>();

	private final ConcurrentMap<String, AtomicInteger> previousPercentages = new ConcurrentHashMap<String, AtomicInteger>();

	private final ConcurrentMap<String, AtomicLong> startingTimes = new ConcurrentHashMap<String, AtomicLong>();

    public ProgressManager_old() {
        resetProgress();
    }

    public void initProgress(final int total, final String id) {
        progresses.put(id, new LongAdder());
        previousPercentages.put(id, new AtomicInteger());
        totals.put(id, total);
        startingTimes.put(id, new AtomicLong(currentTimeStamp()));
    }

    public void resetProgress(final String id) {
        progresses.remove(id);
        previousPercentages.remove(id);
        totals.remove(id);
        startingTimes.remove(id);
    }

    public void resetProgress() {
        progresses.put(DEFAULT, new LongAdder());
        previousPercentages.put(DEFAULT, new AtomicInteger());
        totals.put(DEFAULT, 1);
        startingTimes.put(DEFAULT, new AtomicLong());
    }

    public void initProgress(final int total) {
        initProgress(total, DEFAULT);
    }

    @Override
    public  void update(final Observable o, final Object arg) {
        String id = arg == null ? DEFAULT : arg.toString();
        inc(id);
    }

    /**
     * @param id progress to increment its value
     * 
     * Increment progress for specific ID
     */
	public synchronized void inc(String id) {
		final int percentage = updateProgressAndGetPercentage(id);
        if (percentage > previousPercentages.get(id).get()) {
            final String progressBar = buildProgressBar(percentage);
            LOG.info(progressBar);
            previousPercentages.get(id).set(percentage);
        }
	}
    
	/**
	 * Increment progress for {@link ProgressManager_old#DEFAULT} progress
	 */
    public synchronized void inc() {
    	inc(DEFAULT);
    }

    public AtomicInteger getPercentage() {
        return getPercentage(DEFAULT);
    }

    public AtomicInteger getPercentage(final String id) {
        return previousPercentages.get(id);
    }

    private int updateProgressAndGetPercentage(final String id) {
        progresses.get(id).add(1);
        return (int) Math.round(
            ((double) progresses.get(id).longValue() / totals.get(id))
                * 100);
    }

    private String buildProgressBar(final int percentage) {

        final StringBuilder bar = new StringBuilder("[");

        for (int columns = 0; columns < 50; columns++) {
            if (columns < (percentage / 2)) {
                bar.append("=");
            } else if (columns == (percentage / 2)) {
                bar.append(">");
            } else {
                bar.append(" ");
            }
        }

        bar.append("]   " + percentage + "%");
        return bar.toString();
    }

    public AtomicLong getRemainingTime() {
        return getRemainingTime(DEFAULT);
    }

    public AtomicLong getRemainingTime(final String id) {
        AtomicInteger percentage = getPercentage(id);
        if (percentage != null && percentage.intValue() != 0) {
            double cohef = 100 / percentage.doubleValue() - 1;
			return new AtomicLong((long) (cohef * (currentTimeStamp() - startingTimes.get(id).longValue())));
        } else {
            return new AtomicLong(-1);
        }

    }

    private long currentTimeStamp() {
        return System.currentTimeMillis();
    }

}
