/*
 * Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
 *
 * This file is part of PeerfactSim.KOM.
 * 
 * PeerfactSim.KOM is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * PeerfactSim.KOM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with PeerfactSim.KOM.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package de.tud.kom.p2psim.impl.topology.util;

import java.util.LinkedList;
import java.util.List;

import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.simengine.Simulator;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationListener;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationRequest;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationSensor;

/**
 * Update 15.03.16 added support for multiple listeners (however, frequency
 * etc. is immune after the first request is registered.)
 *
 * @author Bjoern Richerzhagen
 * @version 1.0, Mar 15, 2016
 */
public class LocationRequestImpl implements LocationRequest, EventHandler {

	private boolean immune = false;

	private long interval = 1 * Simulator.MINUTE_UNIT;

	private int priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY;

	private Location lastLocation = null;

	private List<LocationListener> listeners = new LinkedList<LocationListener>();

	private int eventTypeSeq = 0;
	
	private SimHost host;

	private LocationSensor locationSensor;
	
	public LocationRequestImpl(SimHost host, LocationSensor locationSensor) {
		this.host = host;
		this.locationSensor = locationSensor;
	}

	public void cancel(LocationListener listener) {
		boolean removed = listeners.remove(listener);
		if (listeners.isEmpty()) {
			// upcoming event is no longer valid!
			eventTypeSeq++;
		}
		assert removed;
	}

	public void immunizeAndStart(LocationListener listener) {
		immune = true;
		assert interval > 0;
		if (listeners.isEmpty()) {
			// Only start once!
			lastLocation = null;
			Event.scheduleImmediately(this, null, eventTypeSeq);
		} else {
			// Fire each new listener at least once
			listener.onLocationChanged(host, locationSensor.getLastLocation());
		}
		listeners.add(listener);
	}

	@Override
	public void setInterval(long interval) {
		if (!immune) {
			this.interval = interval;
		}
	}

	@Override
	public void setPriority(int priority) {
		if (!immune) {
			this.priority = priority;
		}
	}

	@Override
	public void eventOccurred(Object content, int type) {
		if (eventTypeSeq != type) {
			/*
			 * Discard invalid events caused when a client cancels updates
			 * but reactivates the request within the update frequency
			 * interval. In this case, the old events continue rescheduling
			 * themselves.
			 */
			return;
		}
		if (!listeners.isEmpty()) {
			// Only reschedule, if at least one listener is ... listening
			Location newLoc = locationSensor.getLastLocation();
			listeners.forEach((LocationListener listener) -> listener
					.onLocationChanged(host, newLoc));
			lastLocation = newLoc;
			Event.scheduleWithDelay(interval, this, null, eventTypeSeq);
		}
	}

}
