gt: 		return new MessageFormatter(player, result, generated, count);
context: /*
   *  ExperienceMod - Bukkit server plugin for modifying the experience system in Minecraft.
   *  Copyright (C) 2012 Kristian S. Stangeland
   *
   *  This program 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 2 of 
   *  the License, or (at your option) any later version.
   *
   *  This program 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 this program; 
   *  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
   *  02111-1307 USA
   */
  
  package com.comphenix.xp.messages;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import org.apache.commons.lang.NullArgumentException;
  import org.apache.commons.lang.ObjectUtils;
  import org.apache.commons.lang.StringEscapeUtils;
  import org.bukkit.ChatColor;
  import org.bukkit.entity.Player;
  
  import com.comphenix.xp.parser.Utility;
  import com.comphenix.xp.rewards.ResourceHolder;
  
  public class MessageFormatter {
  
  	private Player source;
  	private Integer count;
  	
  	private Collection<ResourceHolder> result;
  	private List<ResourceHolder> generated;
  	
  	private static Pattern parameterPattern = Pattern.compile("\\{\\w+\\}");
  	
  	// Default
  	public MessageFormatter() {
  		setCount(1);
  	}
  
  	public MessageFormatter(Player player, Collection<ResourceHolder> result, List<ResourceHolder> generated) {
  		this(player, result, generated, 1);
  	}
  	
  	public MessageFormatter(Player player, Collection<ResourceHolder> result, 
  							List<ResourceHolder> generated, Integer count) {
  		setSource(player);
  		setResult(result);
  		setGenerated(generated);
  		setCount(count);
  	}
  	
  	/**
  	 * Replaces parameters in the text with their respective value.
  	 * @param message - message to format.
  	 * @return Message with every parameter replaced with the corresponding value.
  	 */
  	public String formatMessage(String message) {
  		
  		if (message == null)
  			return null;
  		
  		Map<String, ResourceHolder> lookup = getResultMapping();
  		
  		StringBuffer output = new StringBuffer();
  	    Matcher matcher = parameterPattern.matcher(message);
  	    
  	    // Simple variables
  	    // TODO: Add more variables.
  	    String sourceText = source != null ? source.getDisplayName() : "Unknown";
  	    String countText = count != null ? count.toString() : "N/A";
  	    
  	    while (matcher.find()) {
  
  	    	String enumed = Utility.getEnumName(matcher.group());
  	    	
  	    	// Replace parameters
  	    	if (enumed.equals("PLAYER"))
  	    		matcher.appendReplacement(output, sourceText);
  	    	else if (enumed.equals("COUNT"))
  	    		matcher.appendReplacement(output, countText);
  	    	else if (lookup.containsKey(enumed)) 
  	    		matcher.appendReplacement(output, lookup.get(enumed).toString());
  	    	else 
  	    		matcher.appendReplacement(output, "{CANNOT FIND " + matcher.group() + "}");
  	    }
  
  		// Remember color
  		matcher.appendTail(output);
  		return formatUnescape(formatColor(output));
  	}
  
  	private String formatColor(StringBuffer input) {
  
  		// Treat ampersand as a color character
  		return translateAlternateColorCodes('&', input.toString());
  	}
  
  	private String formatUnescape(String input) {
  
  		return StringEscapeUtils.unescapeJava(input);
  	}
  
  	// Don't translate color codes when the ampersand is escaped
  	private static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
  
  		boolean hasEscape = false;
  		char[] b = textToTranslate.toCharArray();
  
  		// Handle Java escaping as well
  		for (int i = 0; i < b.length - 1; i++) {
  			if (!hasEscape && b[i] == '\\') {
  				hasEscape = true;
  			} else if (!hasEscape && b[i] == altColorChar
  					&& "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i + 1]) > -1) {
  				b[i] = ChatColor.COLOR_CHAR;
  				b[i + 1] = Character.toLowerCase(b[i + 1]);
  
  			} else {
  				hasEscape = false;
  			}
  		}
  		return new String(b);
  	}
  
  	// Convert a list of resources into a Hash Table
  	private Map<String, ResourceHolder> getResultMapping() {
  		 Map<String, ResourceHolder> lookup = new HashMap<String, ResourceHolder>();
  		 
  		 for (ResourceHolder resource : getResult()) {
  			 lookup.put(resource.getName(), resource);
  		 }
  		 
  		 return lookup;
  	}
  	
  	/**
  	 * Retrieves the number of times this message has been generated since it was last transmitted.
  	 * @return The number of outstanding messages of this type.
  	 */
  	public Integer getCount() {
  		return count;
  	}
  
  	/**
  	 * Sets the number of times this message has been generated since it was last transmitted.
  	 * @param count - new count.
  	 */
  	public void setCount(Integer count) {
  		this.count = count;
  	}
  
  	/**
  	 * Retrieves the player that caused this message to be sent, or NULL if it was caused by the environment.
  	 * @return The player, if any, that caused the message to be sent.
  	 */
  	public Player getSource() {
  		return source;
  	}
  
  	/**
  	 * Sets the player that caused this message to be sent.
  	 * @param source - the player that caused the message, or NULl it if was the enviornment.
  	 */
  	public void setSource(Player source) {
  		this.source = source;
  	}
  	
  	/**
  	 * Retrieves the list of resources awarded.
  	 * @return List of resources.
  	 */
  	public Collection<ResourceHolder> getResult() {
  		return result;
  	}
  
  	/**
  	 * Sets the list of resources awarded.
  	 * @param result - the new list of resources awarded.
  	 */
  	public void setResult(Collection<ResourceHolder> result) {
  		this.result = result;
  	}
  	
  	/**
  	 * Retrieves the list of resources generated, ordered by reward providers.
  	 * <p>
  	 * This list is the sum of all previous lists.
  	 * @return The current list.
  	 */
  	public List<ResourceHolder> getGenerated() {
  		return generated;
  	}
  
  	/**
  	 * Sets the list of resources generated, ordered by reward providers.
  	 * @param generated - new list of resources.
  	 */
  	public void setGenerated(List<ResourceHolder> generated) {
  		this.generated = generated;
  	}
  	
  	/**
  	 * Adds every parameter in both message formatters. Note that a and b
  	 * must be non-null and have the same player source.
  	 * @param a - first message formatter to add.
  	 * @param b - second message formatter to add.
  	 * @return The resulting message formatter.
  	 */
  	public static MessageFormatter add(MessageFormatter a, MessageFormatter b) {
  		if (a == null)
  			throw new NullArgumentException("a");
  		if (b == null)
  			throw new NullArgumentException("b");
  		
  		// Add the two formatters
  		return a.add(b);
  	}
  	
  	/**
  	 * Adds every parameter in both message formatters, creating a new message 
  	 * formatter with the results.
  	 * @param other - message formatter to add.
  	 * @return The resulting message formatter.
  	 */
  	public MessageFormatter add(MessageFormatter other) {
  		
  		if (!ObjectUtils.equals(getSource(), other.getSource()))
  			throw new IllegalArgumentException("Message formatters for different players cannot be added.");
  		
  		// Add values
  		return new MessageFormatter(
  				getSource(), 
  				addResults(other),
  				addGenerated(other),
  				getInt(getCount()) + getInt(other.getCount())
  		);
  	}
  		
  	// Merge resources
  	private Collection<ResourceHolder> addResults(MessageFormatter other) {
  		
  		Map<String, ResourceHolder> current = getResultMapping();
  
  		// Add every resource from other
  		for (ResourceHolder resource : other.getResult()) {
  			String name = resource.getName();
  			
  			if (current.containsKey(name))
  				current.put(name, current.get(name).add(resource));
  			else
  				current.put(name, resource);
  		}
  		
  		return current.values();
  	}
  	
  	// Merge generated
  	private List<ResourceHolder> addGenerated(MessageFormatter other) {
  		
  		List<ResourceHolder> current = new ArrayList<ResourceHolder>(getGenerated());
  		List<ResourceHolder> adding = other.getGenerated();
  		
  		// Add each resource
  		for (int i = 0; i < adding.size(); i++) {
  			// Elements outside the list are treated as empty
  			if (i < current.size())
  				current.set(i, current.get(i).add(adding.get(i)));
  			else
  				current.add(adding.get(i));
  		}
  		
  		return current;
  	}
  	
  	private static int getInt(Integer value) {
  		return value != null ? value : 0;
  	}
  	
  	/**
  	 * Create a copy of the message formatter with the given parameters
  	 * @param player - the player that caused the current action.
  	 * @param result - combined resources after awarding a player.
  	 * @param generated - the generated list of resources, in the same order as the reward providers.
  	 * @return A copy of the current message formatter.
  	 */
  	public MessageFormatter createView(Player player, Collection<ResourceHolder> result, List<ResourceHolder> generated) {
  		return new MessageFormatter(player, result, generated);
  	}
  	
  	/**
  	 * Create a copy of the message formatter with the given parameters
  	 * @param player - the player that caused the current action.
  	 * @param result - combined resources after awarding a player.
  	 * @param generated - the generated list of resources, in the same order as the reward providers.
  	 * @param count - number of times the message has been sent.
  	 * @return A copy of the current message formatter.
  	 */
  	public MessageFormatter createView(Player player, Collection<ResourceHolder> result, List<ResourceHolder> generated, Integer count) {
  