package org.ff4j.audit.chart;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.ff4j.audit.Event;
import org.ff4j.audit.MutableHitCount;
import org.ff4j.utils.JsonUtils;
/*
* #%L
* ff4j-core
* %%
* Copyright (C) 2013 - 2014 Ff4J
* %%
* 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.
* #L%
*/
/**
* Information for timeSerie.
*
* @author Cedrick LUNVEN (@clunven)
*/
public class TimeSeriesChart extends AbstractChart {
/** Serial. */
private static final long serialVersionUID = 4131401051473272099L;
/** Target Simple Date format. */
private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
/** Init Once. */
private List < String > timeSlots = new ArrayList<String>();
/** SerieID -> Serie (label/color/value) value=<slotID, nombre de point> */
private Map < String, Serie < Map < String, MutableHitCount >>> series =
new HashMap<String, Serie<Map<String,MutableHitCount>>>();
/**
* Default constuctor
*/
public TimeSeriesChart() {
}
/**
* Parameterized constructor.
*
* @param from
* starting date
* @param to
* ending date
* @param units
* time slot
*/
public TimeSeriesChart(long from, long to, TimeUnit units) {
this.initSlots(from, to, units);
}
/**
* Create slots and initiate data structure.
*
* @param startTime
* period start date
* @param endTime
* period end date
* @param units
* current units
* @return
*
*/
public void initSlots(long from, long to, TimeUnit units) {
long slotWitdh = 0;
switch (units) {
case MINUTES:
slotWitdh = 1000 * 60;
this.sdf = new SimpleDateFormat("yyyyMMdd-HH:mm");
break;
case HOURS:
slotWitdh = 1000 * 60 * 60;
this.sdf = new SimpleDateFormat("yyyyMMdd-HH");
break;
case DAYS:
slotWitdh = 1000 * 60 * 60 * 24;
this.sdf = new SimpleDateFormat("yyyyMMdd");
break;
default:
slotWitdh = 1000;
this.sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
break;
}
// Create slots for the timeSeries base ones
int nbslot = new Long(1 + (to - from) / slotWitdh).intValue();
for (int i = 0; i < nbslot; i++) {
long startSlotTime = from + slotWitdh * i;
String slotLabel = sdf.format(new Date(startSlotTime));
getTimeSlots().add(slotLabel);
}
}
/**
* Add Event to chart.
*
* @param evt
* current event
*/
public void addEvent(Event evt) {
if (!series.containsKey(evt.getName())) {
createNewSerie(evt.getName());
}
String targetSlot = sdf.format(new Date(evt.getTimestamp()));
Serie < Map <String, MutableHitCount > > targetSerie = series.get(evt.getName());
if (targetSerie != null) {
MutableHitCount mhc = targetSerie.getValue().get(targetSlot);
if (mhc != null) {
mhc.inc();
}
}
}
/**
* Create new Serie with existing slots.
*
* @param idSerie
* target serie id
*/
public void createNewSerie(String idSerie) {
// Init new Serie
Serie< Map < String, MutableHitCount >> newSerie = new Serie<Map<String,MutableHitCount>>(idSerie);
// Populate slots
Map < String, MutableHitCount > val = new HashMap<String, MutableHitCount>();
for (String slot : timeSlots) {
val.put(slot, new MutableHitCount());
}
newSerie.setValue(val);
series.put(idSerie, newSerie);
}
/** {@inheritDoc} */
@Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
sb.append("\"slots\" : " + JsonUtils.collectionAsJson(timeSlots));
StringBuilder sbNames = new StringBuilder("[");
StringBuilder sbColors = new StringBuilder("[");
StringBuilder sbValues = new StringBuilder("[");
boolean first = true;
for (Serie< Map < String, MutableHitCount >> serie : series.values()) {
// Name
sbNames.append(first ? "" : ",");
sbNames.append(JsonUtils.valueAsJson(serie.getLabel()));
// Color
sbColors.append(first ? "" : ",");
sbColors.append(JsonUtils.valueAsJson("#" + serie.getColor()));
// Values
sbValues.append(first ? "" : ",");
sbValues.append(serie.getValue().values().toString());
first = false;
}
sbNames.append("]");
sbColors.append("]");
sbValues.append("]");
sb.append(", \"serieNames\" : " + sbNames.toString());
sb.append(", \"serieColors\" : " + sbColors.toString());
sb.append(", \"serieValues\" : " + sbValues.toString());
sb.append("}");
return sb.toString();
}
/**
* Getter accessor for attribute 'sdf'.
*
* @return
* current value of 'sdf'
*/
public SimpleDateFormat getSdf() {
return sdf;
}
/**
* Setter accessor for attribute 'sdf'.
* @param sdf
* new value for 'sdf '
*/
public void setSdf(SimpleDateFormat sdf) {
this.sdf = sdf;
}
/**
* Getter accessor for attribute 'timeSlots'.
*
* @return
* current value of 'timeSlots'
*/
public List<String> getTimeSlots() {
return timeSlots;
}
/**
* Setter accessor for attribute 'timeSlots'.
* @param timeSlots
* new value for 'timeSlots '
*/
public void setTimeSlots(List<String> timeSlots) {
this.timeSlots = timeSlots;
}
/**
* Getter accessor for attribute 'series'.
*
* @return
* current value of 'series'
*/
public Map<String, Serie<Map<String, MutableHitCount>>> getSeries() {
return series;
}
/**
* Setter accessor for attribute 'series'.
* @param series
* new value for 'series '
*/
public void setSeries(Map<String, Serie<Map<String, MutableHitCount>>> series) {
this.series = series;
}
}