
package de.ivu.elect.presentation.dokumente;

import java.io.Serializable;
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import javax.inject.Inject;

import de.ivu.elect.business.dokumente.control.ProgressMonitor;
import de.ivu.elect.business.system.entity.LogNachrichtArt;
import de.ivu.elect.jee.exception.ElectCommonException;
import de.ivu.elect.jee.faces.Messages;


import static org.apache.commons.lang3.StringUtils.isNotBlank;

public abstract class AbstractProgressMonitor implements ProgressMonitor, Serializable {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient Messages messages;

  private final DateFormat dateFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM);

  private final AtomicBoolean cancelRequested = new AtomicBoolean(false);

  private final CopyOnWriteArrayList<String> progressMessages = new CopyOnWriteArrayList<>();

  private Enum< ? > lastProgress = null;

  private final AtomicInteger progressBar = new AtomicInteger(0);

  public AbstractProgressMonitor() {
    super();
  }

  public void reset() {
    progressBar.set(0);
    lastProgress = null;
    progressMessages.clear();
    cancelRequested.set(false);
  }

  @Override
  public void progress(Enum< ? > progress) {
    progress(progress, 0, 0);
  }

  @Override
  public void progress(Enum< ? > progress, int count, int size) {
    progress(messages.lokalisiere(progress, count, size), progress, count, size);
  }

  private void progress(String message, Enum< ? > progress, int count, int size) {
    if (progress.equals(lastProgress)) {
      progressMessages.remove(progressMessages.size() - 1);
    }

    progressMessages.add(dateFormat.format(new Date()) + " - " + message);

    lastProgress = progress;

    if (count != 0) {
      progressBar.set(Long.valueOf(Math.round(100.0d * count / size)).intValue());
    }
  }

  @Override
  public void progress(Enum< ? > progress, String message) {
    progress(progress);

    if (isNotBlank(message)) {
      progressMessages.add(message);
    }
  }

  @Override
  public void progress(Enum< ? > progress, int count, int size, Object... params) {
    progress(getMessage(progress, params), progress, count, size);
  }

  @Override
  public boolean isCanceled() {
    return cancelRequested.get();
  }

  public CopyOnWriteArrayList<String> getProgressMessages() {
    return progressMessages;
  }

  public AtomicInteger getProgressBar() {
    return progressBar;
  }

  public AtomicBoolean getCancelRequested() {
    return cancelRequested;
  }

  @Override
  public void addError(String msgKey, Exception throwable) {
    progressMessages.add(dateFormat.format(new Date()) + " - " + getMessage(LogNachrichtArt.FEHLER) + " - " + getMessage(msgKey));

    Throwable lastCause = throwable;
    String lastMessage = "";

    while (lastCause != null) {
      String message = getMessageForThrowable(lastCause);

      if (isNotBlank(message) && !lastMessage.equals(message)) {
        progressMessages.add(message);

        lastMessage = message;
      }

      lastCause = lastCause.getCause();
    }
  }

  private String getMessageForThrowable(Throwable throwable) {
    if (throwable instanceof ElectCommonException) {
      ElectCommonException electCommonException = (ElectCommonException) throwable;

      return getMessage(electCommonException.getMessageKey(), electCommonException.getObjects());
    }

    return throwable.getLocalizedMessage();
  }

  protected String getMessage(String msgKey, Object... params) {
    return messages.getMessageForMessageKey(msgKey, params);
  }

  protected String getMessage(Enum< ? > enumValue, Object... params) {
    return messages.lokalisiere(enumValue, params);
  }
}
