/**
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -
 - JASS: Java Advanced tranSaction Support
 -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -
 - This module was originally developed by 
 -
 -    LSD (Distributed Systems Lab, http://lsd.ls.fi.upm.es/lsd/lsd.htm)
 -    at Universidad Politecnica de Madrid (UPM) as an ObjectWeb Consortium
 -    (http://www.objectweb.org) project.
 -
 -    This project has been partially funded by the European Commission under
 -    the IST programme of V FP grant IST-2001-37126 and by the Spanish
 -    Ministry of Science & Technology (MCyT) grants TIC2002-10376-E and
 -    TIC2001-1586-C03-02
 -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -  The original code and portions created by LSD are 
 -  Copyright (c) 2004 LSD (UPM)  
 -  All rights reserved.
 -  
 - Redistribution and use in source and binary forms, with or without 
 - modification, are permitted provided that the following conditions are met:
 -
 - -Redistributions of source code must retain the above copyright notice, this
 - list of conditions and the following disclaimer. 
 -
 - -Redistributions in binary form must reproduce the above copyright notice, 
 - this list of conditions and the following disclaimer in the documentation 
 - and/or other materials provided with the distribution. 
 -
 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 - POSSIBILITY OF SUCH DAMAGE.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -
 -  Author: Francisco Perez Sorrosal (frperezs)
 -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/

package org.objectweb.jass.as.util;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;

import javax.activity.coordination.Action;
import javax.activity.coordination.SignalSet;

import org.apache.log4j.Logger;

/**
 * Manages information about a signal set.
 * @author fran
 * Date: Feb 16, 2004
 * org.objectweb.jass.as.utilSignalSetInfo.java
 */
public class SignalSetInfo {

	private static Logger log = Logger.getLogger(SignalSetInfo.class);

	//	Attributes -------------------------------------------------------------

	private SignalSet signalSet;
	private HashMap registeredActions = new HashMap();
	private int numberOfActions = 0;

	/**
	 * Constructor.
	 * @param signalSet the signal set.
	 */
	public SignalSetInfo(SignalSet signalSet) {
		this.signalSet = signalSet;
	}

	/**
	 * Returns the managed signal set.
	 * @return the signal set
	 */
	public SignalSet getSignalSet() {
		return signalSet;
	}

	/**
	 * Registers an action into the managed signal set.
	 * @param action the action.
	 * @param priority its priority.
	 * @param global true if the action is global.
	 */
	public void addAction(Action action, int priority, boolean global) {

		LinkedList actions = null;

		if (priority >= 0)
			actions = (LinkedList) registeredActions.get(new Integer(priority));
		else
			actions = (LinkedList) registeredActions.get(new Integer(0));

		if (actions == null)
			actions = new LinkedList();

		actions.add(new ActionInfo(action, global));

		// We put the action in the corresponding priority
		if (priority >= 0)
			registeredActions.put(new Integer(priority), actions);
		else // Implementation specific for invalid priority values
			registeredActions.put(new Integer(0), actions);

		numberOfActions = numberOfActions + 1;
	}

	// Returns an array containing the actions classified by priority
	public Action[] getActions() {
		Action[] actions = null;

		// We obtain sorted the registered priorities (keys of the HashMap).
		Object[] keys = registeredActions.keySet().toArray();
		Arrays.sort(keys);

		// With those keys, we obtain an array of actions ordered by priority in three steps:

		// First, we get the complete actionInfo list...
		LinkedList actionInfoList = new LinkedList();

		for (int j = (keys.length - 1); j >= 0; j--)
			actionInfoList.addAll((LinkedList) registeredActions.get(keys[j]));

		// ...then, we get the actions from that list obtaining a new list and...
		LinkedList actionList = new LinkedList();
		Iterator it = actionInfoList.iterator();

		while (it.hasNext()) {
			actionList.add(((ActionInfo) it.next()).getAction());
		}

		// ...finally, we cast the list of actions to an array of Actions
		Object[] array = actionList.toArray();
		actions = (Action[]) Array.newInstance(Action.class, array.length);
		for (int i = 0; i < array.length; i++)
			actions[i] = (Action) array[i];

		return actions;
	}

	/**
	 * Removes an action from the managed signal set.
	 * @param action the action.
	 * @param global true if the action to remove is global.
	 * @return true if the action has been removed.
	 */
	public boolean removeAction(Action action, boolean global) {

		boolean removed = false;
		Set keys = registeredActions.keySet();
		Iterator itra = keys.iterator();

		while (itra.hasNext() && (removed == false)) {
			Integer priority = (Integer) itra.next();
			LinkedList actionInfoList =
				(LinkedList) registeredActions.get(priority);
			Iterator itail = actionInfoList.iterator();

			while (itail.hasNext() && (removed == false)) {
				ActionInfo actionInfo = ((ActionInfo) itail.next());

				// If we want to remove a global action, the registered action
				// must be global
				if (global) {
					if ((action.equals(actionInfo.getAction()))
						&& (actionInfo.isGlobal() == true)) {
						actionInfoList.remove(actionInfo);
						removed = true;
					}

				} else {
					if ((action.equals(actionInfo.getAction()))
						&& (actionInfo.isGlobal() == false)) {
						actionInfoList.remove(actionInfo);
						removed = true;
					}
				}
			}
			if (removed == true) {
				numberOfActions = numberOfActions - 1;
				if (actionInfoList.isEmpty())
					registeredActions.remove(priority);
			}
		}

		return removed;
	}

	/**
	 * Returns the number of registered actions in the managed signal set.
	 * @return the number of registered actions.
	 */
	public int getNumberRegisteredActions() {
		return numberOfActions;
	}
	/**
	 * Returns the string representation of the managed signal set.
	 */
	public String toString() {
		String result = "Signal Set: " + signalSet.getSignalSetName() + "\n";
		Action[] actions = null;

		// We obtain sorted the registered priorities (keys of the HashMap).
		Object[] keys = registeredActions.keySet().toArray();
		Arrays.sort(keys);

		// With those keys, we obtain an array of actions ordered by priority in three steps:

		// First, we get the complete actionInfo list...
		LinkedList actionInfoList = new LinkedList();

		for (int j = (keys.length - 1); j >= 0; j--) {
			result = result + "\nActions in Priority = " + keys[j] + "\n";
			result = result + registeredActions.get(keys[j]);
		}

		return result;
	}

}
