package de.ivu.elect.jee.memory;

import java.io.Serializable;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.List;

import javax.inject.Inject;

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

public class MemoryGc implements Serializable {

  private static final Logger LOG = LoggerFactory.getLogger(MemoryGc.class);

  @Inject
  private transient MemoryGcStore memoryGcStore;

  public MemoryGcData speichereDaten() {
    MemoryGcData memoryGcData = bestimmeMemoryGcData();
    memoryGcStore.add(memoryGcData);
    return memoryGcData;
  }

  private MemoryGcData bestimmeMemoryGcData() {
    return new MemoryGcData(System.currentTimeMillis(), bestimmeMemoryData(), bestimmeGcData());
  }

  private GcData bestimmeGcData() {
    long count = 0;
    long time = 0;

    try {
      for (GarbageCollectorMXBean garbageCollectorMXBean : getGcMXBean()) {
        count += garbageCollectorMXBean.getCollectionCount();
        time += garbageCollectorMXBean.getCollectionTime();
      }
    } catch (Exception e) {
      LOG.warn("Fehler, GC: " + e.getMessage());
    }

    return new GcData(count, time);
  }

  private List<GarbageCollectorMXBean> getGcMXBean() {
    return ManagementFactory.getGarbageCollectorMXBeans();
  }

  private MemoryData bestimmeMemoryData() {
    try {
      MemoryUsage memoryUsage = getMemoryMXBean().getHeapMemoryUsage();
      return new MemoryData(memoryUsage.getMax(), memoryUsage.getCommitted(), memoryUsage.getUsed());
    } catch (Exception e) {
      LOG.warn("Fehler, Speicherverbrauch: " + e.getMessage());
    }
    return new MemoryData(0, 0, 0);
  }

  private MemoryMXBean getMemoryMXBean() {
    return ManagementFactory.getMemoryMXBean();
  }

  public void clear() {
    memoryGcStore.clear();
    speichereDaten();
  }
}
