package org.lucci.madhoc.network.net;

import java.awt.Color;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.lucci.madhoc.network.Network;
import org.lucci.madhoc.network.Station;
import org.lucci.madhoc.network.cost.Cost;
import org.lucci.madhoc.network.cost.CostModel;
import org.lucci.madhoc.simulation.Configurable;
import org.lucci.madhoc.simulation.Simulation;

/*
 * Created on Jul 23, 2004
 */

/**
 * @author luc.hogie
 */
public class NetworkingTechnology implements Configurable
{
    private Network network;

    private boolean automatic = true; 
    private double minimumCoverageRadius = 8;
    private double maximumCoverageRadius = 100;
    private int maximumNumberOfConnectionsPossible = 1;
    private double maximumBandwith; 
    private String name;
    private Collection<NetworkingTechnology> complianceSet;
    private Collection<NetworkingTechnology> interferenceSet;
    private int packetSize;
    private Color color;
    private CostModel costModel;
    
    private Map<Station, Cost> transferHistory = new HashMap<Station, Cost>();  
    
    public void configure()
        throws Throwable
    {
        Simulation simulation = getNetwork().getSimulation();
        this.automatic = simulation.getConfiguration().getBoolean(getName() + "_automatic");
        
        double[] coverageRadius = simulation.getConfiguration().getInterval(getName() + "_coverage_radius_interval");
        setCoverageRadiusInterval(coverageRadius[0], coverageRadius[1]);

        this.maximumNumberOfConnectionsPossible = simulation.getConfiguration().getInteger(getName() + "_maximum_number_of_simulatenous_connections");
        
        setMaximumBandwith(simulation.getConfiguration().getDouble(getName() + "_maximum_bandwidth") / 10);
        setPacketSize((int) simulation.getConfiguration().getDouble(getName() + "_packet_size"));
        this.complianceSet = new HashSet(Arrays.asList(simulation.getConfiguration().getStrings(getName() + "_is_compliant_with")));
        this.complianceSet.remove("none");
        this.interferenceSet = new HashSet(Arrays.asList(simulation.getConfiguration().getStrings(getName() + "_interferes_with")));
        this.interferenceSet.remove("none");
        setColor(simulation.getConfiguration().getColor(getName() + "_representation_color"));
        this.costModel = (CostModel) simulation.getConfiguration().getInstantiatedClass(getName() + "_cost_model_class");
        this.costModel.setSimulation(simulation);
        this.costModel.configure();
    }

    public boolean isAutomatic()
    {
        return this.automatic;
    }
    
    public void charge(Station station, int numberOfBytes)
    {
        Cost cost = transferHistory.get(station);
        
        if (cost == null)
        {
            cost = new Cost();
            transferHistory.put(station, cost);
        }
        
        double additionalPrice = this.costModel.getCost(numberOfBytes, cost.getNumberOfBytesTransfered());
        cost.setCost(cost.getCost() + additionalPrice);
        cost.setNumberOfBytesTransfered(cost.getNumberOfBytesTransfered() + numberOfBytes);
    }
    
    
    public boolean isCompliantWith(NetworkingTechnology otherType)
    {
        if (otherType == this)
        {
            return true;
        }
        else
        {
            return this.complianceSet.contains(otherType.getName());
        }
    }

    
    public boolean isInterferesWith(NetworkingTechnology otherType)
    {
        return this.interferenceSet.contains(otherType.getName());
    }

    
    /**
     * @return Returns the maximumBandwith.
     */
    public double getMaximumBandwith()
    {
        return maximumBandwith;
    }
    /**
     * @param maximumBandwith The maximumBandwith to set.
     */
    public void setMaximumBandwith(double maximumBandwith)
    {
        if (maximumBandwith < 0)
            throw new IllegalArgumentException();

        this.maximumBandwith = maximumBandwith;
    }
    
    
    public int getPacketSize()
    {
        return this.packetSize;
    }
    
    public int getMaximumNumberOfConnectionsPossible()
    {
        return maximumNumberOfConnectionsPossible;
    }
    public void setMaximumNumberOfConnectionsPossible(int maximumNumberOfConnectionsPossible)
    {
        this.maximumNumberOfConnectionsPossible = maximumNumberOfConnectionsPossible;
    }
    public Network getNetwork()
    {
        return network;
    }
    public void setNetwork(Network network)
    {
        this.network = network;
    }
    public double getMaximumCoverageRadius()
    {
        return maximumCoverageRadius;
    }
    public double getMinimumCoverageRadius()
    {
        return minimumCoverageRadius;
    }
    public void setCoverageRadiusInterval(double min, double max)
    {
        if (min <= max && min >= 0)
        {
            this.minimumCoverageRadius = min;
            this.maximumCoverageRadius = max;
        }
        else
        {
            throw new IllegalArgumentException("invalid coverage radius for technology " + getName());
        }
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public void setPacketSize(int packetSize)
    {
        this.packetSize = packetSize;
    }
    public Color getColor()
    {
        return color;
    }
    public void setColor(Color color)
    {
        this.color = color;
    }

    public Map<Station, Cost> getTransferHistory()
    {
        return transferHistory;
    }
}