package cz.muni.fi.lasaris.sbms.data.util;

import java.time.ZonedDateTime;
import java.util.LinkedList;
import java.util.List;

import com.cronutils.model.Cron;
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.time.ExecutionTime;
import com.cronutils.parser.CronParser;

import cz.muni.fi.lasaris.sbms.data.entities.SeriesSpecs;

public class TimestampGenerator {
	public static List<ZonedDateTime> generateTimestamps(SeriesSpecs s) {
		switch(s.getSampling()) {
		case DURATION:
			return generateDurationTimestamps(s);
		case CRON:
			return generateCRONTimestamps(s);
		case NONE:
		default:
			throw new IllegalArgumentException("Sampling must be set");
		}
	}
	
	private static List<ZonedDateTime> generateDurationTimestamps(SeriesSpecs s) {
		List<ZonedDateTime> r = new LinkedList<ZonedDateTime>();
		
		ZonedDateTime t = s.getStart();
		while (t.isBefore(s.getEnd()) || t.isEqual(s.getEnd())) {
			r.add(t);
			t = t.plus(s.getDuration());
		}
		
		return r;
	}
	
	private static List<ZonedDateTime> generateCRONTimestamps(SeriesSpecs s) {
		List<ZonedDateTime> r = new LinkedList<ZonedDateTime>();
		
		CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
		Cron expr = null;
		try {
			expr = parser.parse(s.getCron());
			expr.validate();
		} catch(Exception e) {
			r.add(s.getStart());
			r.add(s.getEnd());
			return r;
		}
		
		ZonedDateTime t = s.getStart();
		ExecutionTime et = ExecutionTime.forCron(expr);
		t = et.nextExecution(t);
		while (t.isBefore(s.getEnd()) || t.isEqual(s.getEnd())) {
			r.add(t);
			t = et.nextExecution(t);
		}
		
		return r;
	}
}
