/*
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2005 satoshi akabane(akabane@logical-paradox.org)
 * $Id: DacConfig.java,v 1.2 2005/09/07 13:38:06 rampil Exp $
 */
package org.logical_paradox.vsan.dac;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;

import org.logical_paradox.common.cli.Argument;
import org.logical_paradox.common.cli.ArgumentParser;
import org.logical_paradox.common.util.StringUtils;
import org.logical_paradox.vsan.*;

/**
 * ディスクアレイコントローラーのコンフィグレーション
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.2 $
 */
public class DacConfig {
	/** コンフィグファイル名 */
	public static final String OPT_CONFIG = "config";

	/** 設定値 - ポート番号 */
	public static final String KEY_PORT = "port";
	/** 設定値 - 同時接続数 */
	public static final String KEY_CONNECTIONS = "connections";
	/** 設定値 - 受信バッファサイズ */
	public static final String KEY_RECVSIZE = "recvsize";
	/** 設定値 - データベースファイル名 */
	public static final String KEY_DATABASE_DIR = "database-dir";
	/** 設定値 - ノードID */
	public static final String KEY_NODE_ID = "node-id";
	/** 設定値 - 起動時にドメインに接続するかどうか */
	public static final String KEY_JOIN_ON_STARTUP = "join-on-startup";
	/** 設定値 - ドメインコントローラー */
	public static final String KEY_DOMAIN_CONTROLLER = "domain-controller";

	/** デフォルトの設定ファイル名 */
	public static final String DEFAULT_CONFIG_FILENAME = "conf/dac.conf";
	/** デフォルトのリスニングポート番号 */
	public static final int DEFAULT_PORT_NUMBER = 9876;
	/** デフォルトのコネクション数 */
	public static final int DEFAULT_CONNECTIONS = 25;
	/** デフォルトの受信バッファサイズ */
	public static final int DEFAULT_RECV_SIZE = 4096;
	/** デフォルトのデータベースディレクトリ名 */
	public static final String DEFAULT_DATABASE_DIR = "./database";
	/** デフォルトの起動設定 - 起動時にドメインに接続するかどうか */
	public static final boolean DEFAULT_JOIN_ON_STARTUP = true;

	/** コンフィグファイル名 */
	private String config = DEFAULT_CONFIG_FILENAME;
	/** DACエージェクトがlistenするポート番号 */
	private int port = DEFAULT_PORT_NUMBER;
	/** 最大コネクション数 */
	private int connections = DEFAULT_CONNECTIONS;
	/** 受信バッファサイズ */
	private int recvsize = DEFAULT_RECV_SIZE;
	/** データベースディレクトリ名 */
	private String databaseDir = DEFAULT_DATABASE_DIR;
	/** ノードID */
	private String nodeId;
	/** 起動時にドメインに接続するかどうか */
	private boolean joinOnStartup = DEFAULT_JOIN_ON_STARTUP;
	/** ドメインコントローラー */
	private String domainController = null;

	/**
	 * コンストラクタ
	 * @param args 引数
	 */
	public DacConfig(String[] args) throws FileNotFoundException, ConfigException, IOException {
		parse(args);
	}

	/**
	 * 設定ファイル名を返す
	 * @return 設定ファイル名
	 */
	public String getConfigFilename() {
		return config;
	}
	/**
	 * ホストアドレスを返す．
	 * @return ホストアドレス
	 */
	public String getHost() {
		try {
			String hostname = InetAddress.getLocalHost().toString();
			if(hostname.indexOf("/") < 0) {
				return hostname;
			} else {
				return hostname.split("/")[1];
			}
		} catch (UnknownHostException e) {
			return "localhost";
		}
	}
	/**
	 * DACエージェントがlisteningしているポート番号を返す
	 * @return ポート番号
	 */
	public int getPort() {
		return port;
	}
	/**
	 * ノードIDを返す
	 * @return ノードID
	 */
	public String getNodeId() {
		return nodeId;
	}
	/**
	 * 同時接続数を返す
	 * @return 同時接続数
	 */
	public int getConnections() {
		return connections;
	}
	/**
	 * 受信バッファのサイズを返す
	 * @return 受信バッファのサイズ
	 */
	public int getRecvsize() {
		return recvsize;
	}
	/**
	 * データベースディレクトリ名を返す
	 * @return データベースディレクトリ名
	 */
	public String getDatabaseDir() {
		return databaseDir;
	}
	/**
	 * 起動時にドメインに接続するかどうかを返す．
	 * @return true:接続する / false:接続しない
	 */
	public boolean isJoinOnStartup() {
		return joinOnStartup;
	}
	/**
	 * ドメインコントローラーを返す．
	 * @return ドメインコントローラー
	 */
	public String getDomainController() {
		return domainController;
	}
	/**
	 * 指定されたオプションを取り込む
	 * @param args 引数
	 * @throws ConfigException 取り込みに失敗した場合に発生する例外
	 */
	protected void parse(String[] args) throws ConfigException, FileNotFoundException, IOException {
		Argument[] arguments = ArgumentParser.parse(args);

		for(int i = 0; i < arguments.length; i++) {
			Argument arg = arguments[i];
			if(arg.isOption() == true) {
				if(OPT_CONFIG.equals(arg.getName())) {
					config = arg.getValue();
				} else {
					throw new ConfigException("不正なオプションが指定されました:" + arg.getName());
				}
			} else {
				throw new ConfigException("不正な引数が指定されました:" + arg.getValue());
			}
		}

		// コンフィグファイルをロードする
		Properties p = loadConfigration();

		// プロパティ値を取り込む
		// 'port'
		if(StringUtils.isEmpty(p.getProperty(KEY_PORT)) == false) {
			port = Integer.parseInt(p.getProperty(KEY_PORT));
		}
		// 'connections'
		if(StringUtils.isEmpty(p.getProperty(KEY_CONNECTIONS)) == false) {
			connections = Integer.parseInt(p.getProperty(KEY_CONNECTIONS));
		}
		// 'recvsize'
		if(StringUtils.isEmpty(p.getProperty(KEY_RECVSIZE)) == false) {
			recvsize = Integer.parseInt(p.getProperty(KEY_RECVSIZE));
		}
		// 'database-filename'
		if(StringUtils.isEmpty(p.getProperty(KEY_DATABASE_DIR)) == false) {
			databaseDir = p.getProperty(KEY_DATABASE_DIR);
		}
		// 'node-id'
		if(StringUtils.isEmpty(p.getProperty(KEY_NODE_ID)) == true) {
			throw new ConfigException("node-idは必須です");
		} else {
			nodeId = p.getProperty(KEY_NODE_ID);
		}
		// 'join-on-startup'
		if(StringUtils.isEmpty(p.getProperty(KEY_JOIN_ON_STARTUP)) == false &&
			"true".equals(p.getProperty(KEY_JOIN_ON_STARTUP).toLowerCase()) == true
		) {
			joinOnStartup = true;
		} else {
			joinOnStartup = false;
		}
		// 'domain-controller'
		if(joinOnStartup == true) {
			if(StringUtils.isEmpty(p.getProperty(KEY_DOMAIN_CONTROLLER)) == true) {
				throw new ConfigException("join-on-startup設定時，domain-controllerは必須です");
			} else {
				domainController = p.getProperty(KEY_DOMAIN_CONTROLLER);
			}
		}
	}
	/**
	 * コンフィグファイルをロードする
	 * @return プロパティとしてロードされた値
	 */
	protected Properties loadConfigration() throws FileNotFoundException, IOException {
		Properties p = new Properties();
		p.load(new FileInputStream(getConfigFilename()));

		return p;
	}
}
