/**
 * Moxkiriya standalone Wiki.
 * Setting manager.
 * 
 * @author Ryuhei Terada
 * See the '<a href="{@docRoot}/copyright.html">Copyright</a>'
 */
package com.wiki.standalone.moxkiriya;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Set;

import com.wiki.standalone.moxkiriya.util.FileIO;

/**
 * セッティングマネージャ
 */
public class SettingManager {
	/** SETTINGSMAPKEY USER_HOME */
	public static final String SETTINGSKEY_USER_HOME = "USER_HOME";

	/** SETTINGSMAPKEY MOXKIRIYA_USER_DIR*/
	public static final String SETTINGSKEY_MOXKIRIYA_USER_DIR = "MOXKIRIYA_USER_DIR";

	/** SETTINGSMAPKEY MOXKIRIYAROOT */
	public static final String SETINGKEY_MOXKIRIYAROOT = "moxkiriyaroot";
	
	/** SETTINGSMAPKEY WIKIROOT */
	public static final String SETTINGSKEY_WIKIROOT = "wikiroot";

	/** SETTINGSMAPKEY_CLUSTER */
	public static final String SETINGKEY_CLUSTER = "clustersetting";
	
	/** SETTINGSMAPKEY_DBSERVERURL*/
	public static final String SETINGKEY_DBSERVER_URL = "dbserverurl";
	
	/** SETTINGSMAPKEY_DBSERVERPORT*/
	public static final String SETINGKEY_DBSERVER_PORT = "dbserverport";

	/** SETTINGSMAPKEY_DBSERVERPORT*/
	public static final String SETINGKEY_JDBC_DRIVER = "jdbcdriver";
			
	/**/ 
	private static final String MOXKIRIYA_USER_DIR = "_moxkiriya";
	
	/** 設定ファイル名 */
	public static final String CONFIG_FILENAME = "_moxkiriya.config";
	
	/** Party設定ファイル名 */
	private static final String PARTY_FILENAME = "_party.config";

	private static SettingManager singleton_ = null;

	/** party map */
	private Hashtable<String, Boolean> partyTable_ = new Hashtable<String, Boolean>();

	/** setting map */
	private Hashtable<String, String> settingsTable_ = new Hashtable<String, String>();

	/** fullpath map */
	private Hashtable<String, String> fullpathTable_ = new Hashtable<String, String>();
	
	/** selected party */
	private String selectedParty_ = null;
	
	/**
	 * コンストラクタ
	 */
	private SettingManager() {
	}

	/**
	 * インスタンスを取得する。
	 */
	public static SettingManager getInstance() {
		try {
			if (singleton_ == null) {
				singleton_ = new SettingManager();
				singleton_.initializeSettingsMap();
			}
		} catch (Exception e) {
			singleton_ = null;
			e.printStackTrace();
		}
		
		return singleton_;
	}
	
	/**
	 * 設定Mapを初期化する
	 * @throws Exception 
	 */
	private void initializeSettingsMap() throws Exception {
		String userHome         = System.getProperty("user.home");
		File   moxkiriyaUserDir = new File(userHome + "/" + MOXKIRIYA_USER_DIR);

		put(SETTINGSKEY_USER_HOME, userHome);
		put(SETTINGSKEY_MOXKIRIYA_USER_DIR, moxkiriyaUserDir.getAbsolutePath());
		if(moxkiriyaUserDir.exists() != true) {
			moxkiriyaUserDir.mkdirs();
		}

		loadPartyFile(moxkiriyaUserDir.getAbsolutePath());
		if( (selectedParty_ != null)
		 && (selectedParty_.isEmpty() != true)) {
			loadSettingFiles(moxkiriyaUserDir.getAbsolutePath());			
		}
	}

	/**
	 * Party fileを読み込む。
	 * @param path
	 * @throws Exception 
	 */
	private void loadPartyFile(String path) throws Exception {
		File partyFile = new File(path + "/" + PARTY_FILENAME);

		if(partyFile.exists() != true) {
			partyFile.createNewFile();
		}
		BufferedReader buffreader = FileIO.bufferedReader(partyFile);

		String line = null;
		while ((line = buffreader.readLine()) != null) {
			String[] list  = line.split("=", 2);
			String   key   = list[0].trim();
			String   value = list[1].trim();
			putParty(key, Boolean.valueOf(value));			
		}

		Hashtable<String, Boolean> partyTable = getPartyTable();

		if(partyTable.isEmpty() != true) {
			selectedParty_ = "";

			Set<String> keySet = partyTable.keySet();
			for(String key: keySet) {
				boolean value = partyTable.get(key);
				if(value == true) {
					selectedParty_ = key;
					break;
				}
			}
		}
	}

	/**
	 * Configファイルを読み込む。
	 * @throws Exception 
	 * @parma path Configファイルのパス名
	 */
	public void loadSettingFiles(String path) throws Exception {
		String selectedParty = getSelectedParty();
		
		if( (selectedParty != null)
		 && (selectedParty.isEmpty() != true)) {
			settingsTable_ = loadConfigSettings(path, selectedParty);
		}

		String wikiroot          = get(SETTINGSKEY_WIKIROOT);
		if(wikiroot != null) {
			String moxkiriya_userDir = get(SETTINGSKEY_MOXKIRIYA_USER_DIR);
	
			fullpathTable_.put(WikiEngine.TEMPLATE_HTMLHEADER_FILE, moxkiriya_userDir + "/" + selectedParty);
			fullpathTable_.put(WikiEngine.USER_STYLESHEET_FILENAME, moxkiriya_userDir + "/" + selectedParty);
			fullpathTable_.put(WikiEngine.FIXED_STYLESHEET_FILENAME, wikiroot);
			fullpathTable_.put(WikiEngine.DEFAULT_STYLESHEET_FILENAME, wikiroot);
			fullpathTable_.put(WikiRepository.REPOSITORY_CUSTER_FILENAME, moxkiriya_userDir + "/" + selectedParty);
			fullpathTable_.put(WikiRepository.REPOSITORY_LOCAL_FILENAME, moxkiriya_userDir + "/" + selectedParty);
	
			if(Boolean.valueOf(get(SETINGKEY_CLUSTER)) == true) {
				fullpathTable_.put(WikiRepository.REOPSITORY_DIRNAME, moxkiriya_userDir + "/" + selectedParty);
			}
			else {
				fullpathTable_.put(WikiRepository.REOPSITORY_DIRNAME, wikiroot);
			}
		}
	}

	/**
	 * Load config settings of specified party name.
	 * @param partyName
	 * @throws Exception
	 */
	public Hashtable<String, String> loadConfigSettings(String path, String partyName) throws Exception {
		Hashtable<String, String> settingsTable    = new Hashtable<String, String>();
		
		File partyDir = new File(path + "/" + partyName);
		if( (partyDir.exists() != true)
		 && (partyDir.isDirectory() != true)) {
			partyDir.mkdirs();
		}

		File inifile = new File(partyDir.getAbsolutePath()
						+ "/" + SettingManager.CONFIG_FILENAME);
		if (inifile.exists() != true) {
			/* 
			 * ファイルが存在しなかった場合、ファイルを新規作成
			 */
			inifile.createNewFile();
		}
		
		BufferedReader buffreader = FileIO.bufferedReader(inifile);

		String userHome         = System.getProperty("user.home");
		File   moxkiriyaUserDir = new File(userHome + "/" + MOXKIRIYA_USER_DIR);

		settingsTable.put(SETTINGSKEY_USER_HOME, userHome);
		settingsTable.put(SETTINGSKEY_MOXKIRIYA_USER_DIR, moxkiriyaUserDir.getAbsolutePath());

		String line = null;
		while ((line = buffreader.readLine()) != null) {
			String[] list = line.split("=", 2);

			if (list.length >= 2) {
				String   key   = list[0].trim();
				
				if (key.length() > 0) {
					settingsTable.put(key, list[1].trim());
				}
			}
		}
		buffreader.close();
		
		return settingsTable;
	}

	/**
	 * Party table getter.
	 * @return Hashtable<String, Boolean>
	 */
	public Hashtable<String, Boolean> getPartyTable() {
		return partyTable_;
	}
	
	/**
	 * Selected party getter.
	 * @return String
	 */
	public String getSelectedParty() {
		return selectedParty_;
	}

	/**
	 * Selected party setter.
	 * @return String
	 * @throws Exception 
	 */
	public void setSelectedParty(String partyName) throws Exception {
		selectedParty_ = partyName;

		File moxkiriyaUserDir = new File(get(SETTINGSKEY_MOXKIRIYA_USER_DIR));
		loadSettingFiles(moxkiriyaUserDir.getAbsolutePath());					
	}

	/**
	 * Party list getter.
	 * @return ArrayList<String>
	 */
	public ArrayList<String> getPartyList() {
		ArrayList<String> PartyList = new ArrayList<String>();		
		Set<String>       keySet       = partyTable_.keySet();

		for(String key: keySet) {
			PartyList.add(key);
		}
		
		return PartyList;
	}
	
	/**
	 * Put party.
	 * @param partyName
	 * @param isDefault
	 */
	public void putParty(String partyName, boolean isDefault) {
		if(partyName.isEmpty() != true) {
			if(isDefault == true) {
				Set<String> keySet = partyTable_.keySet();
				
				for(String key: keySet) {
					partyTable_.put(key, false);
				}
			}
			partyTable_.put(partyName, isDefault);
		}
	}
	
	/**
	 * 設定情報を追加する。
	 * @param key 設定キー
	 * @parm val 設定値
	 */
	public void put(String key, String val) {
		settingsTable_.put(key, val);
	}
	
	/**
	 * keyに該当する設定値を取得する。
	 * @param key
	 * @return
	 */
	public String get(String key) {
		return settingsTable_.get(key);
	}
	
	/**
	 * 設定を保存する。
	 * @throws Exception 
	 */
	public void save() throws Exception {
		String path             = get(SETTINGSKEY_MOXKIRIYA_USER_DIR);
		File   moxkiriyaHomeDir = new File(path);
		
		if( (moxkiriyaHomeDir.exists() != true)
		 || (moxkiriyaHomeDir.isDirectory() != true)) {
			moxkiriyaHomeDir.mkdirs();
		}

		/*
		 * save _party.config 
		 */
		savePartyConfig(path);
		
		/*
		 * save _moxkiriya.config.
		 */
		saveSettingConfig(path);

		/*
		 * (Re)load _moxkiriya.config.
		 */
		loadSettingFiles(path);
	}

	/**
	 * Translate the setting filename to the absolutepath.
	 * @param filename
	 * @return String
	 */
	public String getAbsolutePath(String filename) {
		String path = fullpathTable_.get(filename);
		
		return  path + "/" + filename;
	}
	
	/**
	 * Save party configuration to file.
	 * @param path
	 * @throws Exception 
	 */
	public void savePartyConfig(String path) throws Exception {
		StringBuffer        stringBuf = new StringBuffer("");
		Enumeration<String> keys      = partyTable_.keys();

		while (keys.hasMoreElements() == true) {
			String  key   = keys.nextElement();
			boolean value = partyTable_.get(key);
			stringBuf.append(key + "=" + value + "\n");
		}

		File           inifile  = new File(path + "/" + PARTY_FILENAME);
		BufferedWriter writer   = FileIO.bufferedWriter(inifile);

		writer.write(stringBuf.toString());
		writer.close();
	}

	/**
	 * Save setting configuration to file.
	 * @param path
	 * @throws Exception
	 */
	public void saveSettingConfig(String path) throws Exception {
		saveSettingConfig(path, selectedParty_, settingsTable_);
	}

	/**
	 * Save setting configuration to file.
	 * @param path
	 * @param partyName
	 * @param settingTable
	 * @throws Exception
	 */
	public void saveSettingConfig(String path, String partyName, Hashtable<String, String> settingTable) throws Exception {
		StringBuffer        stringBuf = new StringBuffer("");
		Enumeration<String> keys      = settingTable.keys();

		while (keys.hasMoreElements() == true) {
			String key   = keys.nextElement();
			String value = settingTable.get(key);
			stringBuf.append(key + "=" + value + "\n");
		}
		File partyDir = new File(path + "/" + partyName);
		
		if(partyDir.exists() != true) {
			partyDir.mkdirs();
		}

		File           inifile  = new File(partyDir.getAbsolutePath() + "/" + CONFIG_FILENAME);
		BufferedWriter writer   = FileIO.bufferedWriter(inifile);

		writer.write(stringBuf.toString());
		writer.close();
	}
}
