package cz.cuni.amis.pogamut.base.utils.logging;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;

/**
 * Class that wraps the map with log categories. It allows you
 * to simply create new categories or query it's mapping.
 * <p><p>
 * The only constructor LogCategories(Logger) is protected and is instantiated
 * during the construction of AgentLogger.
 * 
 * @author Jimmy
 */
public class LogCategories implements ILogCategories {
	
	private Map<String, LogCategory> categories = Collections.synchronizedMap(new HashMap<String, LogCategory>());
	
	private Map<String, LogCategory> immutableCategories = Collections.unmodifiableMap(categories);
	
	private Comparator<String> stringComparator = new Comparator<String>() {

		@Override
		public int compare(String o1, String o2) {
			if (o1 == null) {
				if (o1 == o2) return 0;
				return -1;
			}
			if (o2 == null) return 1;
			return o1.compareTo(o2);
		}
		
	};
	
	/**
	 * Whether some category with specified name exists.
	 * @param name
	 * @return
	 */
	public boolean hasCategory(String name) {
		return categories.containsKey(name);
	}
	
	/**
	 * Returns IMMUTABLE mapping of cathegories names to instances of those log cathegories.
	 * @return
	 */
	public Map<String, LogCategory> getCategories() {
		return immutableCategories;
	}
	
	/**
	 * Returns names of all existing log categories.
	 * @return
	 */
	public String[] getCategoryNames() {
		return categories.keySet().toArray(new String[0]);
	}
	
	/**
	 * Returns names of all existing log categories sorted alphabetically.
	 * @return
	 */
	public String[] getCategoryNamesSorted() {
		String[] names = getCategoryNames();
		Arrays.sort(names, stringComparator);
		return names;
	}
	
	/**
	 * Returns existing category by the name or adds new one.
	 * <p><p>
	 * Note that new category doesn't have any handler appended,
	 * you have to create at least one for the category to produce something.
	 * <p>
	 * Example:<p>
	 * LogCategory myCategory = categories.getCategory("my log"); // create new category
	 * myCategory.newHandler(new LogPublisher.ConsolePublisher()); // add new handler with output to the console
	 * 
	 * @param name
	 * @return
	 */
	public LogCategory getCategory(String name) {
		LogCategory category = categories.get(name);
		if (category != null) return category;
		category = new LogCategory(name);
		categories.put(name, category);
		return category;
	}
	
	/**
	 * Set level for all handlers of all categories.
	 * 
	 * @param newLevel
	 */
	public void setLevel(Level newLevel) {
		for (LogCategory category : categories.values()) {
			category.setLevel(newLevel);
		}
	}

}