package com.interpress_project.modernshare.model;

import java.util.Map;

import com.interpress_project.modernshare.ipcommon.SystemBase;
import com.interpress_project.modernshare.model.exceptions.AccountExistException;
import com.interpress_project.modernshare.model.exceptions.AccountNotExistException;
import com.interpress_project.modernshare.model.exceptions.LicenseException;

/**
 * Represents a singleton.
 * @stereotype Manager
 */
public class AccountManager {
	private final SystemBase sb = SystemBase.getInstance();
	private final String filesep = sb.getFileSeparator();
	private final Object lock = new Object();

	/**
	 * @clientCardinality 1
	 * @supplierCardinality 0..1
	 */
	private PropertyManager propmgr;

	/**
	 * @clientCardinality 1
	 * @supplierCardinality 0..1
	 */
	private INIFile iniSvnconfig = null;

	/**
	 * @clientCardinality 1
	 * @supplierCardinality 0..1
	 */
	private static INIFile iniPassword = null;

	/**
	 * @clientCardinality 1
	 * @supplierCardinality 0..1
	 */
	private INIFile iniAuthz = null;

	/**
	 * AccountManager
	 */
	public AccountManager() {

		propmgr = PropertyManager.getInstance();

		String rootdir = propmgr.getSVNRootdir();
		String passwd = rootdir + filesep + "conf" + filesep + "passwd";
		String authz = rootdir + filesep + "conf" + filesep + "authz";
		String svnconf = rootdir + filesep + "conf" + filesep + "svnserve.conf";

		iniPassword = new INIFile(passwd);
		iniAuthz = new INIFile(authz);
		iniSvnconfig = new INIFile(svnconf);

		initializeConfigFiles();
	}

	/**
	 * initializeConfigFiles
	 */
	private void initializeConfigFiles() {
		/**
		 *  First of all try to setup a root account.
		 */
		String account = propmgr.getAdministratorAccount();
		String password = propmgr.getAdministratorPassword();

		synchronized (lock) {
			iniSvnconfig.setStringProperty("general", "anon-access", "none", "");
			iniSvnconfig.setStringProperty("general", "auth-access", "write", "");
			iniSvnconfig.setStringProperty("general", "password-db", "passwd", "");
			iniSvnconfig.setStringProperty("general", "authz-db", "authz", "");
			iniSvnconfig.save();

			iniAuthz.setStringProperty("/", account, "rw", "");
			iniAuthz.setStringProperty("/", "*", "", "");
			iniAuthz.save();

			iniPassword.setStringProperty("users", account, password, "");
			iniPassword.save();
		}
	}

	/**
	 * addUser
	 * @param account
	 * @param password
	 * @throws AccountExistException 
	 * @throws LicenseException 
	 */
	public void addUser(String account, String password) throws AccountExistException, LicenseException {
		synchronized (lock) {
			if (existUser(account)) {
				throw new AccountExistException();
			}

			/*
			 * Personal license, it allows to create just one account.
			 */
//			LMManager lmmgr = LMManager.getInstance();
//			LEntity entity = lmmgr.parse();
//			LicType licType = entity.getLicType();
//			if (licType == LicType.PERSONAL) {
//				int n = getNumberOfAccounts();
//				if (n > 1) { // root account + 1 user account.
//					sb.getLogger().fatal(
//					  "The server run with Personal license. It can manager up to 2 accounts, including root account.");
//					sb.getLogger().fatal("You cannot add account anymore.");
//					throw new LicenseException();
//				}
//			}

			/**
			 * Modification of password
			 */
			iniPassword.setStringProperty("users", account, password, "");
			iniPassword.save();

			/**
			 * Modification of auth.
			 */
			iniAuthz.setStringProperty("/", account, "rw", "");
			iniAuthz.setStringProperty("/" + account, account, "rw", "");
			iniAuthz.setStringProperty("/" + account, propmgr.getAdministratorAccount(), "rw", "");
			iniAuthz.setStringProperty("/" + account, "*", "", "");
			iniAuthz.save();
		}
	}

	/**
	 * deleteUser
	 * @param account
	 * @throws AccountNotExistException
	 */
	public void deleteUser(String account) throws AccountNotExistException {
		if (existUser(account) == false) {
			throw new AccountNotExistException();
		}
		synchronized (lock) {
			iniPassword.removeProperty("users", account);
			iniPassword.save();

			iniAuthz.removeProperty("/", account);
			iniAuthz.removeSection("/" + account);
			iniAuthz.save();
		}
	}

	/**
	 * changePassword
	 * @param account
	 * @param newpass
	 * @throws AccountNotExistException
	 */
	public void changePassword(String account, String newpass) throws AccountNotExistException {
		if (existUser(account) == false) {
			throw new AccountNotExistException();
		}
		synchronized (lock) {
			iniPassword.setStringProperty("users", account, newpass, "");
			iniPassword.save();
		}
	}

	/**
	 * existUser
	 * @param account
	 * @return
	 */
	private boolean existUser(String account) {
		Map map = iniPassword.getProperties("users");
		if (map.containsKey(account)) {
			return true;
		}
		return false;
	}

	/**
	 * getNumberOfAccounts
	 * @return
	 */
	public int getNumberOfAccounts() {
		Map map = iniPassword.getProperties("users");
		return map.size();
	}

	/**
	 * authenticate
	 * @param account
	 * @param password
	 * @return
	 */
	public static boolean authenticate(String account, String password) {
		String passwd = iniPassword.getStringProperty("users", account);
		if (passwd == null) {
			return false;
		}

		if (password.equals(passwd)) {
			return true;
		}
		return false;
	}
}
