package de.dhbwstuttgart.logger;

import java.io.PrintStream;
import java.util.HashMap;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

public class Logger {

	private static LoggerConfiguration standardConfiguration = new LoggerConfiguration();
	private static final HashMap<String, Logger> LOGGER_DIRECTORY = new HashMap<>();
	
	private String name;
	private final HashMap<Section, java.util.logging.Logger> logger;
	
	protected Logger(String name, LoggerConfiguration config) {
		this.name = name;
		this.logger  = new HashMap<>();
		config.forEach((s,o)->{
			java.util.logging.Logger log = java.util.logging.Logger.getLogger( name );
			log.setLevel(Level.FINE);
			log.addHandler(new OutputHandler(o));
			logger.put(s, log);
		});
	}

	public static LoggerConfiguration getConfiguration(){
		return Logger.standardConfiguration;
	}
	
	/**
	 * Logt eine Debug Message, welche zusätzlich einer bestimmten Section zugewiesen wird.
	 * Dadurch lässt sich die DEBUG ausgabe übersichtlicher gestalten.
	 * @param message
	 * @param section
	 */
	public void debug(String message, Section section){
		output(message, Level.FINE, section);
	}
	
	/**
	 * Liefert den Logger mit dem angegebenen Namen.
	 * Üblicherweise wird diese Methode mit dem Namen der Klasse aufgerufen, in welcher der Logger tätig ist.
	 * @param name - Name der Klasse ( Ermittelbar mittels <Klasse>.class.getName() )
	 * @return
	 */
	public static Logger getLogger(String name) {
		Logger ret;
		if(LOGGER_DIRECTORY.containsKey(name)){
			ret = LOGGER_DIRECTORY.get(name);
		}else{
			ret = new Logger(name, standardConfiguration);
			LOGGER_DIRECTORY.put(name, ret);
		}
		return ret;
	}

	public static SectionLogger getSectionLogger(String name, Section s) {
		Logger ret;
		if(LOGGER_DIRECTORY.containsKey(name)){
			ret = LOGGER_DIRECTORY.get(name);
		}else{
			ret = new Logger(name, standardConfiguration);
			LOGGER_DIRECTORY.put(name, ret);
		}
		return new SectionLogger(ret,s);
	}
	
	protected void output(String msg , Level logLevel, Section section){
		if(logger.containsKey(section)){
			java.util.logging.Logger log = logger.get(section);
			log.log(logLevel, msg);
		}
		/*
		if(output != null){
			output.println(msg);
		}else if(standardOutput != null){
			standardOutput.println(msg);	
		}
		*/
	}
	
	public void info(String message, Section s) {
		output(message, Level.INFO, s);		
	}

	public void error(String message, Section s) {
		output(message, Level.WARNING, s);
	}

	/**
	 * wird hier null übergeben, so wird sämtliches Logging unterdrückt.
	 */
	public static void setStandardConfiguration(LoggerConfiguration config) {
		Logger.standardConfiguration = config;
	}

}

class OutputHandler extends Handler{

	private PrintStream output;
	
	public OutputHandler(PrintStream output){
		this.output = output;
	}
	
	@Override
	public void publish(LogRecord record) {
		output.println(record.getMessage());
	}

	@Override
	public void flush() {
	}

	@Override
	public void close() throws SecurityException {
	}
}