package org.wikiwebserver.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;

public class ConfigManager {

	private static final HashMap<String, String> config = new HashMap<String, String>();
	
	public static final String DEFAULT_SERVER_PASSWORD = "wikiwebserver";
	
	// Default configuration	
	static {
		put("server-password", DEFAULT_SERVER_PASSWORD);
		
		put("writable-location", ".");
		put("not-writable-location", "org/wikiwebserver/core");
		
		put("class-servers", "http://www.wikiwebserver.org/");
		put("slow-class-load-warning-threshold", 500);
		
		put("library-location", "lib");
		put("persist-map-period", 2 * 60 * 1000);
		put("unaccessed-map-unload-delay", 15 * 60 * 1000);
		
		put("flush-log-period", 1 * 60 * 1000);
		
		put("service-test-period", 2 * 60 * 1000);
		put("low-memory-time-allowance", 15 * 1000);
		
		put("networkaddress.cache.ttl", 60);
		put("networkaddress.cache.negative.ttl", 1);
		
		put("http.keepAlive", true);
		put("http.maxConnections", 100);
		put("sun.net.client.defaultConnectTimeout", 5000);
		put("sun.net.client.defaultReadTimeout", 20000);	
		
		put("echo-handler-bind-port", 9);
		put("echo-handler-bind-address", null);
		put("echo-handler-class", "org.wikiwebserver.handler.echo.EchoHandler");
		
		put("iptocountry-handler-bind-port", 8084);
		put("iptocountry-handler-bind-address", null);
		put("iptocountry-handler-class", "org.wikiwebserver.handler.iptocountry.IPToCountryHandler");		
		
		put("wikiwebserver-handler-bind-port", 8080);
		put("wikiwebserver-handler-bind-address", null);
		put("wikiwebserver-handler-class", "org.wikiwebserver.handler.http.HTTPHandler");		
		put("wikiwebserver-handler-configuration-class", "page.config.SiteConfiguration");			
		
		put("ssl-wikiwebserver-handler-bind-port", 8081);
		put("ssl-wikiwebserver-handler-bind-address", null);
		put("ssl-wikiwebserver-handler-class", "org.wikiwebserver.handler.http.HTTPHandler");
		
		
		put("listener-default-burst-period", 5 * 1000);
		put("listener-untrusted-handler-run-period", 30 * 1000);
		put("listener-max-concurrent-connections", 512);
		put("listener-max-queued-connections", 1000);
		
		put("user-package-root", "user.");
		put("user-file-root", "user/");
		
		put("map-file-root", ".maps/");
		put("log-file-root", ".logs/");
		
		put("wiki-cache-purge-delay", 10 * 1000);		
		put("wiki-cache-max-size", 64 * 1024 * 1024);
		
		put("identity-offset", 0);
		put("max-size-for-map", 1000000);
		put("max-size-for-internal-map", 100);
		
		put("http.read-timeout", 5 * 1000);
		put("http.read-buffer-size", 2 * 1024);
		put("http.max-string-scan-size", 100 * 1024);
		put("http.max-data-scan-size", 1024 * 1024);		
		put("http.chunked-buffer-size", 2 * 1024);
		put("http.chunked-small-write-delay-ns", 1000000);
		put("http.max-cacheable-response-size", 10 * 1024 * 1024);
		put("http.file-expiration", 48 * 60 * 60 * 1000);
		put("http.max-cacheable-file-size", 5 * 1024 * 1024);
		put("http.file-read-buffer-size", 32 * 1024);
		put("http.cookie-expiration", "Tue, 31-Dec-2020 23:59:59 GMT");


		put("security.debug-file-access", false);
		put("map.debug-file-access", false);
		put("http.debug-request", false);
		put("http.debug-read", false);
		
		put("disaster-recovery-enabled", false);
		put("disaster-recovery-sync-period", 5 * 60 * 1000);
		put("disaster-recovery-end-point", 
				"http://dr.wikiwebserver.org" +
				"/org/wikiwebserver/handler/http/responder/WikiMapSyncResponder.class");
		
		put("disaster-recovery-server-password", "wikiwebserver");
	}
	
	private static void put(String property, Object obj) {
		if (obj == null) config.put(property, null);
		else config.put(property, String.valueOf(obj));
	}
	
	public static String getString(String property) {
		return config.get(property);
	}
	
	public static String getString(String property, String def) {
		String value = config.get(property);
		if (value == null) return def;
		else return value;
	}
	
	public static boolean getBoolean(String property) {
		return Boolean.parseBoolean(getString(property));
	}	
	
	public static boolean getInt(String property, boolean def) {
		return Boolean.parseBoolean(getString(property, String.valueOf(def)));
	}	
	
	public static int getInt(String property) {
		return Integer.parseInt(getString(property));
	}	
	
	public static int getInt(String property, int def) {
		return Integer.parseInt(getString(property, String.valueOf(def)));
	}	
	
	public static long getLong(String property) {
		return Long.parseLong(getString(property));
	}	
	
	public static long getLong(String property, long def) {
		return Long.parseLong(getString(property, String.valueOf(def)));
	}	
	
	public static void load(File configFile) {
		
		// Try to load configuration from working directory
		StructuredDataReader reader = null;
		try {
		    //System.out.println("Attempting to load config from: " + configFile.getAbsolutePath());
		    reader = new StructuredDataReader(new InputStreamReader(new FileInputStream(configFile), "utf8"));
		    
		    config.putAll(reader.readPairs('=', '\n'));
		}
		catch (FileNotFoundException ex) {
			// A new configuration file is written in finally block
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
		finally {
			try { reader.close(); } catch (Exception ex) {}
			
			// Update configuration file (default configuration may add new entries to file)
			save(configFile);
		}
	}
	
	static void clearSensitiveConfigurationData() {
		put("server-password", "Removed for security");
		put("disaster-recovery-server-password", "Removed for security");
	}

	
	private static void save(File configFile) {
		
		// Save configuration to working directory
		File tmpFile = new File(configFile.getPath() + ".tmp");
		StructuredDataWriter writer = null;
		try {
		   writer = new StructuredDataWriter(new OutputStreamWriter(new FileOutputStream(tmpFile), "utf8"));
		   //config.storeToXML(fout, "WikiWebServer configuration");
		   
		   writer.writePairs(config, '=', '\n');
		}
		catch (IOException ex) {
			ex.printStackTrace();
		}
		finally {
			try { writer.close(); } catch (Exception ex) {}
			if (tmpFile.length() > 0) {
				configFile.delete();
				tmpFile.renameTo(configFile);
				configFile.setLastModified(System.currentTimeMillis());
			}
		}
	}	
}

