package com.intrbiz.bergamot.model;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.time.Clock;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import com.intrbiz.bergamot.config.model.TimePeriodCfg;
import com.intrbiz.bergamot.data.BergamotDB;
import com.intrbiz.bergamot.model.adapter.TimeRangesAdapter;
import com.intrbiz.bergamot.model.message.TimePeriodMO;
import com.intrbiz.bergamot.model.timeperiod.TimeRange;
import com.intrbiz.data.db.compiler.meta.SQLColumn;
import com.intrbiz.data.db.compiler.meta.SQLTable;
import com.intrbiz.data.db.compiler.meta.SQLUnique;
import com.intrbiz.data.db.compiler.meta.SQLVersion;
/**
* A calendar of when checks should be executed
*/
@SQLTable(schema = BergamotDB.class, name = "timeperiod", since = @SQLVersion({ 1, 0, 0 }))
@SQLUnique(name = "name_unq", columns = { "site_id", "name" })
public class TimePeriod extends SecuredObject<TimePeriodMO, TimePeriodCfg> implements TimeRange
{
private static final long serialVersionUID = 1L;
private transient Logger logger = Logger.getLogger(TimePeriod.class);
@SQLColumn(index = 1, name = "excludes_id", type = "UUID[]", since = @SQLVersion({ 1, 0, 0 }))
private List<UUID> excludesId = new LinkedList<UUID>();
@SQLColumn(index = 2, name = "ranges", type = "TEXT[]", adapter = TimeRangesAdapter.class, since = @SQLVersion({ 1, 0, 0 }))
private List<TimeRange> ranges = new LinkedList<TimeRange>();
public TimePeriod()
{
super();
}
@Override
public void configure(TimePeriodCfg configuration, TimePeriodCfg resolvedConfiguration)
{
super.configure(configuration, resolvedConfiguration);
// load the time ranges
this.ranges.clear();
this.ranges.addAll(resolvedConfiguration.getTimeRanges());
}
public List<TimeRange> getRanges()
{
return ranges;
}
public void addRange(TimeRange range)
{
this.ranges.add(range);
}
public void setRanges(List<TimeRange> ranges)
{
this.ranges = ranges;
}
public List<TimePeriod> getExcludes()
{
List<TimePeriod> r = new LinkedList<TimePeriod>();
if (this.excludesId != null)
{
try (BergamotDB db = BergamotDB.connect())
{
for (UUID id : this.getExcludesId())
{
r.add(db.getTimePeriod(id));
}
}
}
return r;
}
public void addExclude(TimePeriod exclude)
{
try (BergamotDB db = BergamotDB.connect())
{
db.addTimePeriodExclude(this, exclude);
}
}
public void removeExclude(TimePeriod exclude)
{
try (BergamotDB db = BergamotDB.connect())
{
db.removeTimePeriodExclude(this, exclude);
}
}
public List<UUID> getExcludesId()
{
return excludesId;
}
public void setExcludesId(List<UUID> excludesId)
{
this.excludesId = excludesId;
}
/**
* Compute whether the given calendar is within this timeperiod.
*/
@Override
public boolean isInTimeRange(Calendar calendar)
{
logger.trace("Checking if " + calendar.getTime() + " is valid for this time period");
// check the possbile excludes
for (TimePeriod exclude : this.getExcludes())
{
if (exclude.isInTimeRange(calendar)) return false;
}
// check the ranges
if (this.ranges.isEmpty()) return true;
for (TimeRange range : this.getRanges())
{
if (range.isInTimeRange(calendar)) return true;
}
return false;
}
public LocalDateTime computeNextStartTime(Clock clock)
{
return null;
}
public String toString()
{
return "TimePeriod " + this.getName();
}
@Override
public TimePeriodMO toMO(Contact contact, EnumSet<MOFlag> options)
{
TimePeriodMO mo = new TimePeriodMO();
super.toMO(mo, contact, options);
if (options.contains(MOFlag.EXCLUDES)) mo.setExcludes(this.getExcludes().stream().map((x) -> x.toStubMO(contact)).collect(Collectors.toList()));
if (options.contains(MOFlag.RANGES)) mo.setRanges(this.getRanges().stream().map(TimeRange::toString).collect(Collectors.toList()));
return mo;
}
/*
* Serialisation shit
*/
private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException
{
is.defaultReadObject();
this.logger = Logger.getLogger(TimePeriod.class);
}
}