package bar;

import jason.asSyntax.Literal;

import jason.environment.grid.GridWorldModel;
import jason.environment.grid.Location;

import java.util.logging.Level;
import java.util.logging.Logger;

import java.util.Random;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Map;
import java.util.Iterator;
import java.util.GregorianCalendar;

public class WorldModel extends GridWorldModel {

	// Size of the environment
	public static final int   SIZE_X = 32;
	public static final int   SIZE_Y = 32;

	// Distance to determine if an agent is near to a resource
	public static final int   NEAR_DIST = 2;
	public static final int   NOISE     = 1;
	public static final int   THRESHOLD = 2;

	// Time of use for each resource
	public static final int   T_SCALE         = 1;
	public static final int   T_COFFEEMACHINE = 3000;
	public static final int   T_JUICEMACHINE  = 5000;
	public static final int   T_GRILL         = 9000;
	public static final int   T_PASTRIES      = 2000;
	public static final int   T_COCKTAILS     = 7000;
	public static final int   T_SNACKS        = 1000;

	// World Resources
	public static final int   NB_RESOURCES   = 6;
	public static final int   ENTRANCE       = 8;
	public static final int   COFFEE_MACHINE = 16;
	public static final int   JUICE_MACHINE  = 32;
	public static final int   GRILL          = 64;
	public static final int   PASTRIES       = 128;
	public static final int   COCKTAILS      = 256;
	public static final int   SNACKS         = 512;
	public static final int   TABLE          = 1024;
	public static final int   TRASH          = 2048;
	public static final int   BAR            = 4096;
	public static final int   EXIT           = 8192;
	
	// Number of request and consume points
	public static final int   NB_REQUESTPOINTS = 15; 
	public static final int   NB_CONSUMEPOINTS = 24;
	public static final int   NB_TABLES        = 6;

	Map<String, Boolean>			resourceAvailability; // Resource availability
	Map<String, Integer>		    resourceUse;          // Simultaneous Use of a Resource
    Map<String, Vector<String> >    resourceQueue;        // Queue of agents in resource
	
	Vector<Literal>				    orders;           // Unattended orders
	Map<Literal, GregorianCalendar> unattendedOrders; // Unattended orders
	Map<Literal, GregorianCalendar[]> attendedOrders; // Attended orders
	Map<Literal, Double[]>          servedOrders;     // Served orders

	int		 				nbOrders    = 0;  // Number of order
    int                     nbWaiters   = 0;  // Number of waiters
    int                     nbCustomers = 0;  // Number of customers

	Location[]              prevPosition;     // Previos position for each agent       

	boolean[]               customerIntoBar;  // Flag for a customer into the bar

	public static final int   NB_TYPES = 3;   // Number of types of customers
	int[]                     customerType;   // Type of customer

    public Map<String, Vector<String> >     table2chairs;     // Chairs in each table
    public Map<String, Location[]> 			requestPoints;    // Map of request points	
    public Map<String, Boolean>    			rPAvailability;   // Availability of request points	
    public Map<String, Location>   			consumePoints;    // Map of consume points	
    public Map<String, Boolean>    			cPAvailability;   // Availability of consume points	
	
	int 					p_coffeeMachine = 0; // Probability of coffeeMachine
	int 					p_juiceMachine  = 0; // Probability of juiceMachine
	int 					p_grill         = 0; // Probability of grill
	int 					p_pastries      = 0; // Probability of pastries
	int 					p_cocktails     = 0; // Probability of cocktails
	int 					p_snacks        = 0; // Probability of snacks

    public static Random random = new Random(System.currentTimeMillis());

    private Logger            logger   = Logger.getLogger("bar.mas2j." + WorldModel.class.getName());

    protected static WorldModel model = null;


	/* ---------------------- WORLD CREATION FUNCTIONS ----------------------*/

    /** Bar with waiters and customers */
    static WorldModel createWorld(int nbCustomers, int nbWaiters) 
	{		
        WorldModel model = WorldModel.create(SIZE_X, SIZE_Y, nbCustomers, nbWaiters);
      
        model.add(WorldModel.COFFEE_MACHINE, 24, 0);
        model.add(WorldModel.COFFEE_MACHINE, 25, 0);
        model.add(WorldModel.COFFEE_MACHINE, 26, 0);
        model.add(WorldModel.JUICE_MACHINE, 31, 9);
        model.add(WorldModel.JUICE_MACHINE, 31, 10);
        model.add(WorldModel.JUICE_MACHINE, 31, 11);
        model.add(WorldModel.GRILL, 31, 1);
        model.add(WorldModel.GRILL, 31, 2);
        model.add(WorldModel.GRILL, 31, 3);
        model.add(WorldModel.PASTRIES, 12, 0);
        model.add(WorldModel.PASTRIES, 12, 1);
        model.add(WorldModel.PASTRIES, 12, 2);
        model.add(WorldModel.COCKTAILS, 31, 5);
        model.add(WorldModel.COCKTAILS, 31, 6);
        model.add(WorldModel.COCKTAILS, 31, 7);
        model.add(WorldModel.SNACKS, 18, 0);
        model.add(WorldModel.SNACKS, 19, 0);
        model.add(WorldModel.SNACKS, 20, 0);
        model.add(WorldModel.TRASH, 20, 31);
        model.add(WorldModel.TRASH, 21, 31);
        model.add(WorldModel.TRASH, 22, 31);
        model.add(WorldModel.TRASH, 31, 19);
        model.add(WorldModel.TRASH, 31, 20);
        model.add(WorldModel.TRASH, 31, 21);
        model.add(WorldModel.BAR, 12, 3); model.add(WorldModel.BAR, 12, 9);
        model.add(WorldModel.BAR, 12, 4); model.add(WorldModel.BAR, 12, 10);
        model.add(WorldModel.BAR, 12, 5); model.add(WorldModel.BAR, 12, 11);
        model.add(WorldModel.BAR, 12, 6); model.add(WorldModel.BAR, 12, 12);
        model.add(WorldModel.BAR, 12, 7); model.add(WorldModel.BAR, 12, 13);
        model.add(WorldModel.BAR, 12, 8); model.add(WorldModel.BAR, 12, 14);
        model.add(WorldModel.BAR, 12, 15); model.add(WorldModel.BAR, 22, 15);
        model.add(WorldModel.BAR, 13, 15); model.add(WorldModel.BAR, 23, 15);
        model.add(WorldModel.BAR, 14, 15); model.add(WorldModel.BAR, 24, 15);
        model.add(WorldModel.BAR, 15, 15); model.add(WorldModel.BAR, 25, 15);
        model.add(WorldModel.BAR, 16, 15); model.add(WorldModel.BAR, 26, 15);
        model.add(WorldModel.BAR, 17, 15); model.add(WorldModel.BAR, 27, 15);
        model.add(WorldModel.BAR, 18, 15); model.add(WorldModel.BAR, 28, 15);
        model.add(WorldModel.BAR, 19, 15); model.add(WorldModel.BAR, 29, 15);
        model.add(WorldModel.BAR, 20, 15); model.add(WorldModel.BAR, 30, 15);
        model.add(WorldModel.BAR, 21, 15); model.add(WorldModel.BAR, 31, 15);
        model.add(WorldModel.BAR, 0, 22); model.add(WorldModel.BAR, 0, 23); 
        model.add(WorldModel.BAR, 0, 24); model.add(WorldModel.BAR, 2, 31);
        model.add(WorldModel.BAR, 0, 25); model.add(WorldModel.BAR, 3, 31);
        model.add(WorldModel.BAR, 0, 26); model.add(WorldModel.BAR, 4, 31);
        model.add(WorldModel.BAR, 0, 27); model.add(WorldModel.BAR, 5, 31);
        model.add(WorldModel.BAR, 0, 28); model.add(WorldModel.BAR, 6, 31);
        model.add(WorldModel.BAR, 0, 29); model.add(WorldModel.BAR, 7, 31);
        model.add(WorldModel.BAR, 8, 31); model.add(WorldModel.BAR, 9, 31);
        model.add(WorldModel.BAR, 10, 31); model.add(WorldModel.BAR, 11, 31);
        model.add(WorldModel.ENTRANCE, 3, 0);
        model.add(WorldModel.ENTRANCE, 4, 0);
        model.add(WorldModel.ENTRANCE, 5, 0);
        model.add(WorldModel.EXIT, 31, 25);
        model.add(WorldModel.EXIT, 31, 26);
        model.add(WorldModel.EXIT, 31, 27);

        model.add(WorldModel.TABLE, 7, 7); model.add(WorldModel.TABLE, 8, 7);
        model.add(WorldModel.TABLE, 7, 8); model.add(WorldModel.TABLE, 8, 8);
        model.add(WorldModel.TABLE, 2, 17); model.add(WorldModel.TABLE, 3, 17);
        model.add(WorldModel.TABLE, 2, 18); model.add(WorldModel.TABLE, 3, 18);
        model.add(WorldModel.TABLE, 10, 23); model.add(WorldModel.TABLE, 11, 23);
        model.add(WorldModel.TABLE, 10, 24); model.add(WorldModel.TABLE, 11, 24);
        model.add(WorldModel.TABLE, 20, 19); model.add(WorldModel.TABLE, 21, 19);
        model.add(WorldModel.TABLE, 20, 20); model.add(WorldModel.TABLE, 21, 20);

		try
		{
			int i;
			for (i = 0; i < nbCustomers; i++)
				model.setAgPos(i, 4, 0);
			for (i = 0; i < nbWaiters; i++)
				model.setAgPos(i + nbCustomers, random.nextInt(14) + 15, random.nextInt(10) + 3);
		}
		catch(Exception ex)
		{
			System.out.println("Error initializing agent positions ");
		}
		
        return model;
    }
    
    synchronized public static WorldModel create(int w, int h, int nbC, int nbW) {
        if (model == null) {
            model = new WorldModel(w, h, nbC, nbW);
        }
        return model;
    }
    
    /** WorlModel constructor */
    private WorldModel(int w, int h, int nbC, int nbW) {
        super(w, h, nbC + nbW);
		int i; 

		nbCustomers = nbC;
	    nbWaiters = nbW;
		
		prevPosition = new Location[nbCustomers + nbWaiters];
		for (i = 0; i < nbCustomers+nbWaiters; i++)
			prevPosition[i] = new Location(0,0);

		customerIntoBar = new boolean[nbCustomers];
		customerType = new int[nbCustomers];
		for (i = 0; i < nbCustomers; i++)
		{
			customerIntoBar[i] = false;
			customerType[i] = 0;
		}
		
	    requestPoints = new Hashtable<String, Location[]>();
		rPAvailability = new Hashtable<String, Boolean>();
		Vector<Location> vrqpos = new Vector<Location>();
		Vector<Location> vatpos = new Vector<Location>();
		
		vrqpos.add(new Location(11,3)); vatpos.add(new Location(13,3));
		vrqpos.add(new Location(11,4)); vatpos.add(new Location(13,4));
		vrqpos.add(new Location(11,6)); vatpos.add(new Location(13,6));
		vrqpos.add(new Location(11,7)); vatpos.add(new Location(13,7));
		vrqpos.add(new Location(11,9)); vatpos.add(new Location(13,9));
		vrqpos.add(new Location(11,10)); vatpos.add(new Location(13,10));
		vrqpos.add(new Location(11,12)); vatpos.add(new Location(13,12));
		vrqpos.add(new Location(11,13)); vatpos.add(new Location(13,13));
		vrqpos.add(new Location(13,16)); vatpos.add(new Location(13,14));
		vrqpos.add(new Location(15,16)); vatpos.add(new Location(15,14));
		vrqpos.add(new Location(18,16)); vatpos.add(new Location(18,14));
		vrqpos.add(new Location(21,16)); vatpos.add(new Location(21,14));
		vrqpos.add(new Location(24,16)); vatpos.add(new Location(24,14));
		vrqpos.add(new Location(27,16)); vatpos.add(new Location(27,14));
		vrqpos.add(new Location(29,16)); vatpos.add(new Location(29,14));
		for (i = 1; i <= NB_REQUESTPOINTS; i++)
		{
			Location v_l[] = {vrqpos.get(i - 1), vatpos.get(i - 1)};
			requestPoints.put("bar"+i, v_l);
			rPAvailability.put("bar"+i, true);
		}

	    consumePoints = new Hashtable<String, Location>();
		consumePoints.put("chair1", new Location(8, 6)); consumePoints.put("chair2", new Location(9, 8));
		consumePoints.put("chair3", new Location(7, 9)); consumePoints.put("chair4", new Location(6, 7));
		consumePoints.put("chair5", new Location(3, 16)); consumePoints.put("chair6", new Location(4, 18));
		consumePoints.put("chair7", new Location(2, 19)); consumePoints.put("chair8", new Location(1, 17));
		consumePoints.put("chair9", new Location(1, 23)); consumePoints.put("chair10", new Location(1, 25));
		consumePoints.put("chair11", new Location(1, 28)); consumePoints.put("chair12", new Location(3, 30));
		consumePoints.put("chair13", new Location(7, 30)); consumePoints.put("chair14", new Location(10, 30));
		consumePoints.put("chair15", new Location(11, 22)); consumePoints.put("chair16", new Location(12, 24));
		consumePoints.put("chair17", new Location(10, 25)); consumePoints.put("chair18", new Location(9, 23));
		consumePoints.put("chair19", new Location(21, 18)); consumePoints.put("chair20", new Location(22, 20));
		consumePoints.put("chair21", new Location(20, 21)); consumePoints.put("chair22", new Location(19, 19));
		consumePoints.put("chair23", new Location(0, 21)); consumePoints.put("chair24", new Location(12, 31));
		cPAvailability = new Hashtable<String, Boolean>();
		for (i = 1; i <= NB_CONSUMEPOINTS; i++)
			cPAvailability.put("chair"+i, true);
		Vector<String> v_chairs = new Vector<String>();
	    table2chairs = new Hashtable<String, Vector <String> >();
		v_chairs.add("chair1");v_chairs.add("chair2");v_chairs.add("chair3");v_chairs.add("chair4");
		table2chairs.put("table1", v_chairs);
		v_chairs = new Vector<String>();
		v_chairs.add("chair5");v_chairs.add("chair6");v_chairs.add("chair7");v_chairs.add("chair8");
		table2chairs.put("table2", v_chairs);
		v_chairs = new Vector<String>();
		v_chairs.add("chair9");v_chairs.add("chair10");v_chairs.add("chair11");v_chairs.add("chair23");
		table2chairs.put("table3", v_chairs);
		v_chairs = new Vector<String>();
		v_chairs.add("chair12");v_chairs.add("chair13");v_chairs.add("chair14");v_chairs.add("chair24");
		table2chairs.put("table4", v_chairs);
		v_chairs = new Vector<String>();
		v_chairs.add("chair15");v_chairs.add("chair16");v_chairs.add("chair17");v_chairs.add("chair18");
		table2chairs.put("table5", v_chairs);
		v_chairs = new Vector<String>();
		v_chairs.add("chair19");v_chairs.add("chair20");v_chairs.add("chair21");v_chairs.add("chair22");
		table2chairs.put("table6", v_chairs);

	    resourceQueue = new Hashtable<String, Vector<String> >(NB_RESOURCES);
		resourceQueue.put("coffeeMachine", new Vector<String>());
		resourceQueue.put("juiceMachine", new Vector<String>());
		resourceQueue.put("grill", new Vector<String>());
		resourceQueue.put("pastries", new Vector<String>());
		resourceQueue.put("cocktails", new Vector<String>());
		resourceQueue.put("snacks", new Vector<String>());
		
		resourceAvailability = new Hashtable<String, Boolean>(NB_RESOURCES);
		resourceAvailability.put("coffeeMachine", true);
		resourceAvailability.put("juiceMachine", true);
		resourceAvailability.put("grill", true);
		resourceAvailability.put("pastries", true);
		resourceAvailability.put("cocktails", true);
		resourceAvailability.put("snacks", true);
		resourceUse = new Hashtable<String, Integer>(NB_RESOURCES);
		
		orders = new Vector<Literal>();
		unattendedOrders = new Hashtable<Literal, GregorianCalendar>();
		attendedOrders = new Hashtable<Literal, GregorianCalendar[]>();
		servedOrders = new Hashtable<Literal, Double[]>();
    }
	
	/** Destroys the current world model */
	public static void destroy() {
        model = null;
    }

	/** Gets the current world model*/
    public static WorldModel get() {
        return model;
    }
	
	/* ------------------------- GET & SET FUNCTIONS ------------------------*/

	/** Sets the probabilities for generating orders */
    public void setProbabilities(int p_cof, int p_jui, int p_gri, int p_pas, int p_coc, int p_sna)
	{
        p_coffeeMachine = p_cof;
		p_juiceMachine = p_jui;
		p_grill = p_gri;
		p_pastries = p_pas;
		p_cocktails = p_coc;
		p_snacks = p_sna;
    }

	/** Gets the number of customers */
    public int getNbCustomers()
	{
        return nbCustomers;
    }

	/** Gets the number of waiters */
    public int getNbWaiters()
	{
        return nbWaiters;
    }

	/** Gets the number of orders waiting in the Cash Desk*/
    public int ordersInCue()
	{
        return unattendedOrders.size();
    }

	/** Checks whether the queue of a resource is empty */
    public boolean isFree(String resource)
	{
        return (resourceQueue.get(resource).size() == 0);
    }

	/** Gets the size of the queue of a resource */
    public synchronized int getSizeOfQueue(String resource)
	{
        return (resourceQueue.get(resource).size());
    }

	/** Gets the name of the agent located at a certain position in the queue of a resource */
    public synchronized String getAgentAtQueue(String resource, int pos)
	{
		if ( (pos < 0) || (pos >= resourceQueue.get(resource).size()) )
			return "";
        return ((String)resourceQueue.get(resource).elementAt(pos));
    }

	/** Returns the names (separated by ',') of the agents waiting in queue for a resource */
    public String getQueue(String resource)
	{
		String cad = "";
		
		Iterator<String> itAg = resourceQueue.get(resource).iterator();
		while (itAg.hasNext())
			cad += itAg.next() + ",";

		if (cad.length() != 0)
			cad = cad.substring(0, cad.length() - 1); 
		
        return "[" + cad + "]";
    }
	
	/** Checks whether a customer is inside the bar */
	public boolean isIntoBar(int agId)
	{
		return (customerIntoBar[agId]);
	}
	
	/** Gets the type of a a customer */
	public int getTypeOfCustomer(int agId)
	{
		return (customerType[agId]);
	}

	/* ------------------------- ACTION FUNCTIONS ---------------------------*/

	/** Generates a random order */
    public synchronized Vector<Literal> generateOrders(String agName, int Num, String rqPoint)
	{
		int r;
		Vector<Literal> vOrders = new Vector<Literal>(Num);
		
		for (int i = 0; i < Num; i++)
		{
			nbOrders++;
			String resource = ""; 
			r = random.nextInt(100) + 1;
			
			if (r <= p_coffeeMachine) 
				resource = "coffeeMachine";
			else if (r <= p_coffeeMachine + p_juiceMachine)
				resource = "juiceMachine";
			else if (r <= p_coffeeMachine + p_juiceMachine + p_grill)
				resource = "grill";
			else if (r <= p_coffeeMachine + p_juiceMachine + p_grill + p_pastries)
				resource = "pastries";
			else if (r <= p_coffeeMachine + p_juiceMachine  + p_grill + p_pastries + p_cocktails)
				resource = "cocktails";
			else			
				resource = "snacks";
		
			Literal l = Literal.parseLiteral("order(" + nbOrders + "," + agName + "," + rqPoint + ",service(1," + resource + "))");
			if (l == null)
			{
				logger.info("Literal nulo!");
				return null;
			}
			else
			{
				orders.add(l);
				unattendedOrders.put(l, new GregorianCalendar());
				vOrders.add(l);
			}
		}
		
		return vOrders;
    }
    
    /** Attends an order requested by a customer */
    public synchronized Literal attendOrder(String ag)
	{
		if (orders.isEmpty())
			return null;
		
		Literal l = orders.remove(0);
		GregorianCalendar t_init = unattendedOrders.remove(l); 
		GregorianCalendar vTimes[] = {t_init, new GregorianCalendar()};
        attendedOrders.put(l, vTimes);
		return l;
    }   

    /** Joins the queue of a resource in order to serve an order */
    public synchronized int queue(String resource, String agName)
	{
		boolean isFree = resourceAvailability.get(resource);

		if (isFree)
			resourceAvailability.put(resource, false);
		
		if (!resourceQueue.get(resource).contains(agName))
		    resourceQueue.get(resource).add(agName);

		if ( (isFree) || (resourceQueue.get(resource).firstElement().equals(agName)) )
		{
			resourceUse.put(resource, 0);
			return 0;
		}
		else
		{
			int pos = resourceQueue.get(resource).indexOf(agName);
			return pos;
		}
	}				

    /** Leaves the queue of a resource */
    public synchronized boolean unQueue(String resource, String agName)
	{
		return resourceQueue.get(resource).remove(agName);
	}				

    /** Uses a resource in order to serve an order */
    public long useResource(String resource)
	{
		Integer n_uses = resourceUse.get(resource);
		n_uses++;
		resourceUse.put(resource, n_uses);

		long tWait = 0;
		
		if (resource.equals("coffeeMachine"))
		    tWait = T_SCALE * T_COFFEEMACHINE;
		else if (resource.equals("juiceMachine"))
		    tWait = T_SCALE * T_JUICEMACHINE;
		else if (resource.equals("grill"))
		    tWait = T_SCALE * T_GRILL;
		else if (resource.equals("pastries"))
		    tWait = T_SCALE * T_PASTRIES;
		else if (resource.equals("cocktails"))
		    tWait = T_SCALE * T_COCKTAILS;
		else if (resource.equals("snacks"))
		    tWait = T_SCALE * T_SNACKS;
		
		return tWait;
	}				

    /** Releases a resource after serving an order */
    public String finishUsing(String resource, String agName)
	{
		String nextAg = null;
		
		Integer n_uses = resourceUse.get(resource);
		n_uses--;
		resourceUse.put(resource, n_uses);
		
		if (n_uses > 0)
			return agName;
		
		resourceQueue.get(resource).remove(agName);
		
		if (isFree(resource))
			resourceAvailability.put(resource, true);
        else
			nextAg = (String)resourceQueue.get(resource).firstElement();				

		return nextAg;
	}				

    /** Finishes serving an order */
    public boolean giveOrder(Literal l)
	{
		GregorianCalendar[] vTimes = attendedOrders.remove(l);
			
		if (vTimes != null)
		{
			GregorianCalendar timeEnd = new GregorianCalendar();
		    double cueTime = (timeEnd.getTimeInMillis() - vTimes[0].getTimeInMillis() ) / 1000.0;
		    double execTime = (timeEnd.getTimeInMillis() - vTimes[1].getTimeInMillis() ) / 1000.0;
			
			Double v_t[] = {cueTime, execTime};
            servedOrders.put(l, v_t);
			
			logger.info("Order served: " + l + " -> " + execTime + " s.");
			
			return true;
		}
		else
			return false;
    }   

	/** Moves an agent towards a location avoids obstacles and agents*/
    Location moveTowards(int agId, int x, int y) throws Exception 
	{
		Location dst  = new Location(x, y);
        Location r1   = getAgPos(agId);
		int i;
		int d, min = r1.distance(dst);

		// Initialize adjacent cells
		Vector<Location> vlocs = new Vector<Location>();
		for (i = 0; i < 8; i++)
			vlocs.add(new Location(r1.x, r1.y));
		vlocs.get(0).x--;  // 0 left
		vlocs.get(1).x--; vlocs.get(1).y--; // 1 left up
		vlocs.get(2).y--; // 2 up
		vlocs.get(3).x++; vlocs.get(3).y--; // 3 right up
		vlocs.get(4).x++; // 4 right
		vlocs.get(5).x++; vlocs.get(5).y++; // 5 right down
		vlocs.get(6).y++; // 6 down
		vlocs.get(7).x--; vlocs.get(7).y++; // 7 left down
	
		// For each adjacent cell: compute distance to goal and choose the best free path
		for (i = 0; i < vlocs.size(); i++)
		{
		   if (isFree(vlocs.get(i)) && (data[vlocs.get(i).x][vlocs.get(i).y] == 0))
		   {
			   d = vlocs.get(i).distance(dst);
			   
			   if (d <= min)
			   {
				   r1 = vlocs.get(i);
				   min = d;
			   }
		   }
		}
		
        setAgPos(agId, r1);
			
		return r1;
    }

	/** Put a customer into the bar */
	public void goIntoBar(int agId)
	{
		customerIntoBar[agId] = true;
		customerType[agId] = random.nextInt(NB_TYPES);
	}

	/** Put a customer out of the bar */
	public void exitBar(int agId)
	{
		try
		{
			setAgPos(agId, 4, 0);
			customerIntoBar[agId] = false;
		}
		catch (Exception ex)
		{
			logger.log(Level.SEVERE, "Error moving agent out of the bar: ", ex);
		}
	}
	
	/** Reserves a request point */
	public synchronized boolean reserveRequestPoint(String rqPoint)
	{
		if (rPAvailability.get(rqPoint) == true)
		{
			rPAvailability.put(rqPoint, false);
			return true;
		}
		else
			return false;
	}

	/** Frees a request point */
	public void freeRequestPoint(String rqPoint)
	{
		rPAvailability.put(rqPoint, true);
	}
	
	
	/** Reserves a consume point */
	public synchronized boolean reserveConsumePoint(String cPoint)
	{
		if (cPAvailability.get(cPoint) == true)
		{
			cPAvailability.put(cPoint, false);
			return true;
		}		
		else
			return false;
	}

	/** Frees a consume point */
	public void freeConsumePoint(String cPoint)
	{
		cPAvailability.put(cPoint, true);
	}
	
	/** Gets a wandering position for the waiters */
	public Location getWanderPosition()
	{
		return new Location(random.nextInt(14) + 15, random.nextInt(10) + 3);
	}
}
