// ----------------------------------------------------------------------------
// Copyright (C) 2008 Francisco Grimaldo, Miguel Lozano, Fernando Barber
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library 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
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// 
// To contact the authors:
// francisco.grimaldo@uv.es, miguel.lozano@uv.es, fernando.barber@uv.es
// http://www.uv.es/grimo
// http://grev.uv.es
//
//----------------------------------------------------------------------------

package jmadem;

import jason.NoValueException;
import jason.asSyntax.NumberTerm;
import jason.asSyntax.Term;
import jason.asSyntax.Atom;

import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Logger;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.List;


/** 
 * Data structure holding all the information related to a specific decision
 * problem.
 *
 * @author Francisco Grimaldo
 */
public class DecisionData 
{
	/** Class logger */
	private Logger logger = Logger.getLogger(DecisionData.class.getName());
	
	/** Decision id generator*/
	static private int id_generator = 1;
	
	/** Decision id */
	private int id;
	
	/**
	 * Agents involved in the decision-making.
	 */
	private List<Atom> agents;

	/**
	 * Allocations being considered as solutions for the decision problem.
	 */
	private List<Term> allocations;

	/**
	 * Names of the utility functions being considered.
	 */
	private List<Atom> utilityFunctions;
	 
	/**
	 * Utility weights representing the importance given to each point of view
	 * in the multi-modal agent decision making.
	 */
	private Map<Atom, Float> utilityWeights;
	
	/**
	 * Personal weights representing the internal attitude of the agent towards
	 * other individuals.
	 */
	private Map<Atom, Float> personalWeights;
	
	/** Social welfare considered by the agent */
	private Cuf welfare;

	/** Type of multimodality used in the Winner Determination Problem */
	private Multimodality multimodality;

	/**
	 * Utility values received from the agents involved in the decision.
	 */
	private ConcurrentMap<Atom, List<Float>> utilityValues;

	/** 
	 * Flag indicating that the winner determination problem as already
	 * started for this decision. 
	 */
	private boolean decisionClosed;

	/** 
	 * Flag indicating whether the winner determination problem returns all 
	 * possible winners for the decision or just one randomly chosen. 
	 */
	private boolean multipleSolution;

	/** 
	 * Flag indicating whether the winner determination problem returns 
	 * the social welfare of winner allocations. 
	 */
	private boolean returnWelfare;

	/** 
	 * Task object that can be used to cancel or check execution of the timeout. 
	 */
	private ScheduledFuture<?> timeoutTask;
	
	/**
	  * DecisionData constructor.
	  *
	  * @param	ags					names of the agents involved in the decision
	  * @param	allocs				allocations being considered as solutions for the decision problem
	  * @param	uFuncs				names of the different utility functions to pay attention to 
	  * @param	pW					personal weights to be applied over external preferences
	  * @param	uW					utility weights in the multi-modal decision
	  * @param	sw					type of social welfare being considered
	  * @param	m					type of multimodality used in the Winner Determination Problem
	  * @param	multipleSolutions	ask for all possible winners or just one randomly chosen  
	  * @param	returnWelfare		whether to return the social welfare of winner allocations 
	  */
	DecisionData(List<Atom> ags, List<Term> allocs, List<Atom> uFuncs,
				 ConcurrentMap<Atom, Float> pW, ConcurrentMap<Atom, Float> uW, 
				 Cuf sw, Multimodality m, boolean multipleSolutions, boolean returnWelfare)
	{
		// Assign decision id
		synchronized(DecisionData.class)
		{
			id = id_generator;
			if (id_generator == Integer.MAX_VALUE)
				id_generator = 1;
			else
				id_generator++;
		}
		
		// Init logger 
		logger = Logger.getLogger(DecisionData.class.getName());

		// Store current MADeM parameters 
		agents = ags;
		allocations = allocs;
		utilityFunctions = uFuncs;
		personalWeights = new HashMap<Atom, Float>( (int)(pW.size() * 0.75) + 1 );
		personalWeights.putAll(pW);
		utilityWeights = new HashMap<Atom, Float>( (int)(uW.size() * 0.75) + 1 );
		utilityWeights.putAll(uW);
		welfare = sw;
		multimodality = m;
		utilityValues = new ConcurrentHashMap<Atom, List<Float>>( (int)(ags.size() * 0.75) + 1 );
		decisionClosed = false;
		multipleSolution = multipleSolutions;
		this.returnWelfare = returnWelfare;
	}
	
	/**
	  * Sets the task object that can be used to cancel or check execution of the timeout.
	  *
	  * @param	timeoutTask the timeout task object	
	  */
	public void setTimeoutTask(ScheduledFuture<?> timeoutTask) {
		this.timeoutTask = timeoutTask;
	}

	/**
	  * Returns the task object that can be used to cancel or check execution of the timeout..  
	  *
	  * @return	the timeout task object
	  */
	public ScheduledFuture<?> getTimeoutTask() {
		return timeoutTask;
	}

	/**
	  * Returns the identifier of the decision making.
	  *
	  * @return	decision id for the decision making
	  */
	public int getId()
	{
		return id;
	}
	
	/**
	  * Returns whether the winner determination problem (WDP) has already started for 
	  * this decision.
	  *
	  * @return	<tt>true</tt> if the WDP has already started, <tt>false</tt> otherwise
	  */
	public boolean isDecisionClosed() {
		return decisionClosed;
	}

	/**
	  * Sets the value of the flag indicating whether the winner determination problem (WDP) 
	  * has already started for this decision.
	  *
	  * @param	decisionClosed new value for the flag	
	  */
	public void setDecisionClosed(boolean decisionClosed) {
		this.decisionClosed = decisionClosed;
	}

	/**
	  * Sets the value of the flag indicating whether the winner determination problem (WDP) 
	  * returns all possible winners for the decision or just one randomly chosen.
	  *
	  * @param	multipleSolution new value for the flag	
	  */
	public void setMultipleSolution(boolean multipleSolution) {
		this.multipleSolution = multipleSolution;
	}

	/**
	  * Returns whether the winner determination problem (WDP) returns all possible winners 
	  * for the decision or just one randomly chosen.
	  *
	  * @return	<tt>true</tt> if the WDP returns all possible winners, <tt>false</tt> otherwise
	  */
	public boolean isMultipleSolution() {
		return multipleSolution;
	}
	
	/**
	  * Sets the value of the flag indicating whether the winner determination problem (WDP) 
	  * returns the social welfare of winner allocations.
	  *
	  * @param	returnWelfare new value for the flag	
	  */
	public void setReturnWelfare(boolean returnWelfare) {
		this.returnWelfare = returnWelfare;
	}

	/**
	  * Returns whether the winner determination problem (WDP) returns the social welfare 
	  * of winner allocations.
	  *
	  * @return	<tt>true</tt> if the WDP returns the social welfare, <tt>false</tt> otherwise
	  */
	public boolean getReturnWelfare() {
		return returnWelfare;
	}
	
	/**
	  * Adds a bid to the MADeM decision data.
	  *
	  * @param	bidder	name of the bidder agent
	  * @param	uValues	utility values obtained by the set utility functions
	  *                 being considered for the different allocations
	  */
	public void addBid(String bidder, List<Term> uValues)
	{
		List<Float> uV = new Vector<Float>( (int)(uValues.size() * 0.75) + 1 );
		for (Term t : uValues)
		{
			if (t.isNumeric())
			{
				try
				{
					uV.add(new Float( ((NumberTerm) t).solve() ));
				}
				catch(NoValueException e) 
				{
					uV.add(null);
					logger.severe("Utility value \"" + t + "\" is not numeric while adding a bid.");
					e.printStackTrace();
				}
			}
			else
				uV.add(null);
		}
		
		// Store utility values
		utilityValues.put(new Atom(bidder), uV);
	}
	
	/**
	  * Checks whether all agents have already bid and their bids have been received.  
	  *
	  * @return	<tt>true</tt> if all bids have been received, <tt>false</tt> otherwise
	  */
	public boolean areAllBidsReceived()
	{
		return (agents.size() == utilityValues.size());
	}

	/**
	  * Returns the name of the agents involved in the decision.  
	  *
	  * @return	the name of the agents into a <tt>Vector</tt>
	  */
	public List<Atom> getAgents()
	{
		return agents;
	}

	/**
	  * Returns the personal weights for the agents involved in the decision.  
	  *
	  * @return	the personal weights into a <tt>ConcurrentHashMap</tt>, where the 
	  *         keys of the map are the names of the agents
	  */
	public Map<Atom, Float> getPersonalWeights()
	{
		return personalWeights;
	}

	/**
	  * Returns the allocations considered as solutions for the decision problem.  
	  *
	  * @return	the allocations into a <tt>Vector</tt>
	  */
	public List<Term> getAllocations()
	{
		return allocations;
	}

		/**
	  * Returns the name of the utility functions used to express preference.  
	  *
	  * @return	the name of the utility functions into a <tt>Vector</tt>
	  */
	public List<Atom> getUtilityFunctions()
	{
		return utilityFunctions;
	}

	/**
	  * Returns the utility weights for the utility functions being used.  
	  *
	  * @return	the utility weights into a <tt>ConcurrentHashMap</tt>, where the 
	  *         keys of the map are the names of the utility functions
	  */
	public Map<Atom, Float> getUtilityWeights()
	{
		return utilityWeights;
	}

	/**
	  * Returns the social welfare applied to solve the decision problem.  
	  *
	  * @return	the social welfare for the decision
	  */
	public Cuf getWelfare()
	{
		return welfare;
	}

	/**
	  * Returns the utility values received from the agents involved in the decision.  
	  *
	  * @return	the utility values into a <tt>ConcurrentHashMap</tt>, where the 
	  *         keys of the map are the names of the bidders
	  */
	public ConcurrentMap<Atom, List<Float>> getUtilityValues()
	{
		return utilityValues;
	}

	/**
	  * Changes the type of multimodality used in the Winner Determination Problem.  
	  *
	  * @param	new_multimodality	new type of multimodality
	  */
	public void setMultimodality(Multimodality new_multimodality)
	{
		multimodality = new_multimodality;
	}

	/**
	  * Gets the type of multimodality used in the Winner Determination Problem.  
	  *
	  * @return	the name of the type of multimodality
	  */
	public Multimodality getMultimodality()
	{
		return multimodality;
	}

}

