/*
* Copyright (c) Henrik Niehaus
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the project (Lazy Bones) nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package lazybones.conflicts;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import lazybones.ChannelManager;
import lazybones.LazyBones;
import lazybones.LazyBonesTimer;
import lazybones.utils.StartStopEvent;
import lazybones.utils.Utilities;
import org.hampelratte.svdrp.responses.highlevel.BroadcastChannel;
import org.hampelratte.svdrp.responses.highlevel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConflictFinder {
private static transient Logger logger = LoggerFactory.getLogger(ConflictFinder.class);
private final Set<Conflict> conflicts = new HashSet<Conflict>();
private final HashMap<Integer, Integer> transponderUse = new HashMap<Integer, Integer>();
private final HashSet<LazyBonesTimer> runningEvents = new HashSet<LazyBonesTimer>();
private void reset() {
conflicts.clear();
transponderUse.clear();
runningEvents.clear();
}
public Set<Conflict> findConflictingTimers(List<LazyBonesTimer> timers) {
logger.debug("Looking for conflicts");
// clear old status data
reset();
int numberOfCards = Integer.parseInt(LazyBones.getProperties().getProperty("numberOfCards"));
logger.debug("Number of cards: {}", numberOfCards);
// the following is a scan line algorithm, which runs over the start and stop events of
// the timers and increases / decreases the transponder usage accordingly
List<StartStopEvent> startStopEvents = Utilities.createStartStopEventList(timers);
boolean conflictFound = false;
Conflict conflict = new Conflict();
for (Iterator<StartStopEvent> iter = startStopEvents.iterator(); iter.hasNext();) {
StartStopEvent event = iter.next();
LazyBonesTimer timer = event.getTimer();
if (event.isStartEvent()) {
increaseTransponderUse(timer);
runningEvents.add(timer);
if (transponderUse.size() > numberOfCards) {
conflictFound = true;
conflict.getInvolvedTimers().addAll(runningEvents);
if (conflict.getPeriod().getStartTime() == null) {
conflict.getPeriod().setStartTime(event.getEventTime());
}
}
} else {
decreaseTransponderUse(timer);
if (conflictFound && transponderUse.size() <= numberOfCards) {
conflictFound = false;
conflict.getPeriod().setEndTime(event.getEventTime());
conflicts.add(conflict);
conflict = new Conflict();
}
runningEvents.remove(timer);
}
}
return conflicts;
}
public int getConflictCount() {
return conflicts.size();
}
public Set<Conflict> getConflicts() {
return conflicts;
}
private void increaseTransponderUse(LazyBonesTimer timer) {
Channel _chan = ChannelManager.getInstance().getChannelByNumber(timer.getChannelNumber());
if (_chan instanceof BroadcastChannel) {
BroadcastChannel chan = (BroadcastChannel) _chan;
if (chan != null && transponderUse.containsKey(chan.getFrequency())) {
int count = transponderUse.get(chan.getFrequency());
count++;
transponderUse.put(chan.getFrequency(), count);
} else {
transponderUse.put(chan.getFrequency(), 1);
}
}
}
private void decreaseTransponderUse(LazyBonesTimer timer) {
Channel _chan = ChannelManager.getInstance().getChannelByNumber(timer.getChannelNumber());
if (_chan instanceof BroadcastChannel) {
BroadcastChannel chan = (BroadcastChannel) _chan;
if (transponderUse.containsKey(chan.getFrequency())) {
int count = transponderUse.get(chan.getFrequency());
if (count == 1) {
transponderUse.remove(chan.getFrequency());
} else {
count--;
transponderUse.put(chan.getFrequency(), count);
}
}
}
}
}