/*
 * 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.views;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;

import de.tud.kom.p2psim.api.linklayer.mac.Link;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
import de.tud.kom.p2psim.api.linklayer.mac.MacLayer;
import de.tud.kom.p2psim.api.linklayer.mac.PhyType;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.api.topology.obstacles.Obstacle;
import de.tud.kom.p2psim.api.topology.obstacles.ObstacleModel;
import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.topology.views.wifi.phy.InterferenceHelper;
import de.tud.kom.p2psim.impl.util.LiveMonitoring;
import de.tud.kom.p2psim.impl.util.LiveMonitoring.ProgressValue;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;

/**
 * A topology view where connectivity is based on the distance between hosts.
 * This basic version supports movement (ie. Neighborhoods change over time) and
 * obstacles in that connectivity is only enabled if a link does not intersect
 * with any obstacles. Extending classes could add a more versatile handling of
 * obstacles, for example in allowing them to dampen the signal rather than
 * completely destroying it.
 * 
 * This View provides GlobalKnowledgeRouting information by implementing a
 * cached version of Dijkstra. Depending on the requirements of your simulation
 * you might find it useful to alter some parameters of the
 * Dijkstra-Implementation - they are commented in the Dijkstra-subclass.
 * 
 * @author Bjoern Richerzhagen
 * @version 1.0, 07.03.2012
 */
public abstract class RangedTopologyView extends AbstractTopologyView<RangedLink> {

	/**
	 * communication range for the static case
	 */
	private double range = 150;

	/**
	 * Just a List of all Links
	 */
	protected List<RangedLink> linkList = new ArrayList<RangedLink>();

	/**
	 * These are used for the GlobalKnowledge-Functions
	 */

	/**
	 * Again, only used for the GlobalKnowledge-Functions
	 */
	protected List<MacAddress> allMacAddresses = new ArrayList<MacAddress>();

	/**
	 * A Pointer to the Obstacle Model
	 */
	private ObstacleModel obstacleModel;

	/**
	 * A Pointer to the Waypoint Model
	 */
	private WaypointModel waypointModel;
	
	protected InterferenceHelper interferenceHelper;
	
	public static long _dijkstraCalculated, _dijkstraCached, _dijkstraPartly;

	/**
	 * This View supports movement as well as obstacles (at least in a very
	 * basic form)
	 * 
	 * @param phy
	 * 
	 */
	public RangedTopologyView(PhyType phy) {
		super(phy, true);
		setHasRealLinkLayer(true);
	}

	@XMLConfigurableConstructor({ "phy", "range" })
	public RangedTopologyView(String phy, double range) {
		this(PhyType.WIFI);
		setPhy(phy);
	}

	@Override
	protected void addedMac(MacLayer mac) {
		allMacAddresses.add(mac.getMacAddress());
	}

	@Override
	protected RangedLink createLink(MacAddress source, MacAddress destination) {
		Location p1,p2;
		
		p1 = this.getPosition(source);
		p2 = this.getPosition(destination);
		
		RangedLink link = new RangedLink(source, destination,p1,p2, true,
				determineLinkDropProbability(source, destination),
				determineLinkBandwidth(source, destination),
				determineLinkLatency(source, destination), getPhyType()
						.getDefaultMTU(), null);
		synchronized (linkList) {
			linkList.add(link);
		}
		return link;
	}



	@Override
	protected List<MacAddress> updateNeighborhood(MacAddress source) {
		/*
		 * We cache this information as well to reach consistency between
		 * getNeighbors and Link-Information.
		 */
		List<MacAddress> updatedNeighbors = new ArrayList<MacAddress>();
		for (MacAddress neighbor : allMacAddresses) {
			RangedLink link = getLinkBetween(source, neighbor);
			if (link.isConnected()) {
				assert !neighbor.equals(source);
				updatedNeighbors.add(neighbor);
			}
		}
		return updatedNeighbors;
	}
	
	long lastMovementTime = 0;
	
	@Override
	public void onLocationChanged(Host host, Location location) {
		super.onLocationChanged(host, location);
		if (lastMovementTime != Time.getCurrentTime()) {
			lastMovementTime = Time.getCurrentTime();
			/*
			 * mark all links as outdated
			 */
			synchronized (linkList) {
				for (RangedLink link : linkList) {
					link.setOutdated(true);
				}
			}
		}
	}

	


	@Override
	public Link getBestNextLink(MacAddress source, MacAddress lastHop,
			MacAddress currentHop, MacAddress destination) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void changedWaypointModel(WaypointModel model) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void changedObstacleModel(ObstacleModel model) {
		// TODO Auto-generated method stub
		
	}



	

}
