/*

Copyright (C) 2009 NTT DATA INTELLILINK CORPORATION

This program is free software; you can redistribute it and/or
Modify it under the terms of the GNU General Public License 
as published by the Free Software Foundation, version 2.

This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied 
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
PURPOSE.  See the GNU General Public License for more details.

 */

package jp.co.intellilink.hinemos.importtool.conf.repository;

import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;

import javax.ejb.DuplicateKeyException;

import jp.co.intellilink.hinemos.util.CheckString;
import jp.co.intellilink.hinemos.util.Config;
import jp.co.intellilink.hinemos.util.EjbConnectionManager;
import jp.co.intellilink.hinemos.util.Messages;
import jp.co.intellilink.hinemos.util.ReadCsvFile;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.clustercontrol.bean.DataRangeConstant;
import com.clustercontrol.bean.Property;
import com.clustercontrol.bean.PropertyConstant;
import com.clustercontrol.bean.YesNoConstant;
import com.clustercontrol.repository.ejb.session.RepositoryController;
import com.clustercontrol.repository.factory.NodeProperty;
import com.clustercontrol.util.PropertyUtil;

/**
 * ノード情報をインポートするクラス<br>
 * 
 * @version 1.0.0
 * @since 1.0.0
 */
public class ImportNode {

	// ログ出力
	private static Log log = LogFactory.getLog(ImportNode.class);

	@SuppressWarnings("unchecked")
	private ArrayList<Property> nodeList = null;

	private ArrayList<ArrayList<String>> nodeInfos = null;

	/**
	 * ノード情報をインポートする。<br>
	 */
	public void importNode() {
		log.info(Messages.getMsg("Node.Start", new String[]{Messages.getMsg("ImportTool.Import")}));

		//ノード情報のCSVファイルを読み込む
		nodeInfos = ReadCsvFile.readCsvFile(Config.getConfig("Import.Dir") + "/NODE.csv");

		//ノードリスト取得
		nodeList = getNodeList();

		for(ArrayList<String> info : nodeInfos){
			Property property = createNodeInfo(info);
			registerNodeInfo(property);
		}

		log.info(Messages.getMsg("Node.End", new String[]{Messages.getMsg("ImportTool.Import")}));
	}

	/**
	 * ノード情報を作成する。<br>
	 * 
	 * @param info ノード情報配列
	 * @return ノード情報オブジェクト
	 */
	public Property createNodeInfo(ArrayList<String> info) {
		Property property = getNodeProperty();

		@SuppressWarnings("unchecked")
		ArrayList propertyList = null;

		//ファシリティID
		String id = CheckString.checkLength(info.get(0), DataRangeConstant.VARCHAR_64);
		if(!id.equals(info.get(0))){
			String[] args = { com.clustercontrol.util.Messages.getString("facility.id"), "64" };
			log.error(Messages.getMsg("ImportTool.Common.2", args));
			System.exit(20);
		}
		propertyList = PropertyUtil.getProperty(property, NodeProperty.FACILITY_ID);
		((Property)propertyList.get(0)).setValue(id);
		//ファシリティ名
		String name = CheckString.checkLength(info.get(1), DataRangeConstant.VARCHAR_256);
		if(!name.equals(info.get(1))){
			String[] args = { com.clustercontrol.util.Messages.getString("facility.name"), "256" };
			log.warn(Messages.getMsg("ImportTool.Common.2", args));
		}
		propertyList = PropertyUtil.getProperty(property, NodeProperty.FACILITY_NAME);
		((Property)propertyList.get(0)).setValue(name);
		//説明
		String description = CheckString.checkLength(info.get(2), DataRangeConstant.VARCHAR_1024);
		if(!description.equals(info.get(2))){
			String[] args = { com.clustercontrol.util.Messages.getString("description"), "1024" };
			log.warn(Messages.getMsg("ImportTool.Common.2", args));
		}
		propertyList = PropertyUtil.getProperty(property, NodeProperty.DESCRIPTION);
		((Property)propertyList.get(0)).setValue(description);
		//プラットフォーム
		propertyList = PropertyUtil.getProperty(property, NodeProperty.PLATFORM_FAMILY_NAME);
		((Property)propertyList.get(0)).setValue(info.get(3));
		//H/Wタイプ
		propertyList = PropertyUtil.getProperty(property, NodeProperty.HARDWARE_TYPE);
		((Property)propertyList.get(0)).setValue(info.get(4));
		//画面アイコンイメージ
		propertyList = PropertyUtil.getProperty(property, NodeProperty.ICONIMAGE);
		((Property)propertyList.get(0)).setValue(info.get(5));
		//管理対象
		propertyList = PropertyUtil.getProperty(property, NodeProperty.VALID);
		((Property)propertyList.get(0)).setValue(
				YesNoConstant.typeToBoolean(YesNoConstant.stringToType(info.get(6))));
		//SNMPポート番号
		propertyList = PropertyUtil.getProperty(property, NodeProperty.SNMP_PORT);
		try {
			((Property)propertyList.get(0)).setValue(Integer.parseInt(info.get(7)));
		} catch (NumberFormatException e) {
		}
		//SNMPコミュニティ名
		propertyList = PropertyUtil.getProperty(property, NodeProperty.SNMP_COMMUNITY);
		((Property)propertyList.get(0)).setValue(info.get(8));
		//SNMPバージョン
		propertyList = PropertyUtil.getProperty(property, NodeProperty.SNMP_VERSION);
		((Property)propertyList.get(0)).setValue(info.get(9));
		//SNMPタイムアウト
		propertyList = PropertyUtil.getProperty(property, NodeProperty.SNMP_VERSION);
		try {
			((Property)propertyList.get(0)).setValue(Integer.parseInt(info.get(10)));
		} catch (NumberFormatException e) {
		}
		//SNMPリトライ回数
		propertyList = PropertyUtil.getProperty(property, NodeProperty.SNMPRETRIES);
		try {
			((Property)propertyList.get(0)).setValue(Integer.parseInt(info.get(11)));
		} catch (NumberFormatException e) {
		}
		//SNMPプロキシ
		propertyList = PropertyUtil.getProperty(property, NodeProperty.SNMPPROXY);
		((Property)propertyList.get(0)).setValue(info.get(12));
		//DHCPクライアント
		propertyList = PropertyUtil.getProperty(property, NodeProperty.DHCP_CLIENT);
		((Property)propertyList.get(0)).setValue(
				YesNoConstant.typeToBoolean(YesNoConstant.stringToType(info.get(13))));
		//IPアドレス種別
		propertyList = PropertyUtil.getProperty(property, NodeProperty.IP_ADDRESS_TYPE);
		try {
			((Property)propertyList.get(0)).setValue(Integer.parseInt(info.get(14)));
		} catch (NumberFormatException e) {
		}
		//IPアドレスバージョン
		propertyList = PropertyUtil.getProperty(property, NodeProperty.IP_ADDRESS_VERSION);
		try {
			((Property)propertyList.get(0)).setValue(Integer.parseInt(info.get(15)));
		} catch (NumberFormatException e) {
		}
		//IPアドレスV4
		propertyList = PropertyUtil.getProperty(property, NodeProperty.IP_ADDRESS_V4);
		((Property)propertyList.get(0)).setValue(info.get(16));
		//IPアドレスV6
		propertyList = PropertyUtil.getProperty(property, NodeProperty.IP_ADDRESS_V6);
		((Property)propertyList.get(0)).setValue(info.get(17));
		//ホスト名
		propertyList = PropertyUtil.getProperty(property, NodeProperty.HOST_NAME);
		((Property)propertyList.get(0)).setValue(info.get(18));
		//ノード名
		propertyList = PropertyUtil.getProperty(property, NodeProperty.NODE_NAME);
		((Property)propertyList.get(0)).setValue(info.get(19));
		//OS名
		if(info.size() >= 21){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.OS_NAME);
			((Property)propertyList.get(0)).setValue(info.get(20));
		}
		//OSリリース
		if(info.size() >= 22){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.OS_RELEASE);
			((Property)propertyList.get(0)).setValue(info.get(21));
		}
		//OSバージョン
		if(info.size() >= 23){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.OS_VERSION);
			((Property)propertyList.get(0)).setValue(info.get(22));
		}
		//文字セット
		if(info.size() >= 24){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.CHARACTER_SET);
			((Property)propertyList.get(0)).setValue(info.get(23));
		}
		//仮想化ノード種別
		if(info.size() >= 25){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.VIRTNODETYPE);
			((Property)propertyList.get(0)).setValue(info.get(24));
		}
		//仮想化管理ノード
		if(info.size() >= 26){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.VMMANAGEMENTNODE);
			((Property)propertyList.get(0)).setValue(info.get(25));
		}
		//仮想マシンINDEX
		if(info.size() >= 27){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.VMINDEX);
			try {
				((Property)propertyList.get(0)).setValue(Integer.parseInt(info.get(26)));
			} catch (NumberFormatException e) {
			}
		}
		//仮想マシン名
		if(info.size() >= 28){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.VMNAME);
			((Property)propertyList.get(0)).setValue(info.get(27));
		}
		//仮想化ソリューション
		if(info.size() >= 29){
			propertyList = PropertyUtil.getProperty(property, NodeProperty.VIRTSOLUTION);
			((Property)propertyList.get(0)).setValue(info.get(28));
		}

		return property;
	}

	/**
	 * ノード一覧に指定したファシリティIDが存在するかチェックする。<br>
	 * 
	 * @param facilityId ファシリティID
	 * @return チェック結果
	 */
	protected Property checkNodeList(String facilityId) {
		@SuppressWarnings("unchecked")
		ArrayList propertyList = null;

		for(Property property : nodeList){

			propertyList = PropertyUtil.getProperty(property, NodeProperty.FACILITY_ID);
			String id = (String)((Property)propertyList.get(0)).getValue();

			if(id.compareTo(facilityId) == 0)
				return property;
		}

		return null;
	}

	/**
	 * ノード情報を登録する。<br>
	 * 
	 * @param property ノード情報
	 */
	protected void registerNodeInfo(Property property) {

		RepositoryController repository = EjbConnectionManager.getConnectionManager().getRepositoryController();

		@SuppressWarnings("unchecked")
		ArrayList propertyList = null;

		propertyList = PropertyUtil.getProperty(property, NodeProperty.FACILITY_ID);
		String facilityId = (String)((Property)propertyList.get(0)).getValue();

		try {
			@SuppressWarnings("unchecked")
			Property line = checkNodeList(facilityId);
			if(line instanceof Property){
				propertyList = PropertyUtil.getProperty(line, NodeProperty.CREATE_TIME);
				Date createTime = (Date)((Property)propertyList.get(0)).getValue();
				propertyList = PropertyUtil.getProperty(line, NodeProperty.CREATOR_NAME);
				String createUser = (String)((Property)propertyList.get(0)).getValue();
				propertyList = PropertyUtil.getProperty(property, NodeProperty.CREATE_TIME);
				((Property)propertyList.get(0)).setValue(createTime);
				propertyList = PropertyUtil.getProperty(property, NodeProperty.CREATOR_NAME);
				((Property)propertyList.get(0)).setValue(createUser);
				
				copyDeviceProperty(property, line);
				copyFileSystemProperty(property, line);
				
				Object[] args = {facilityId};
				log.info(Messages.getMsg("FacilityID", args) + 
						" (" + Messages.getMsg("modify") + ")");

				repository.modifyNode(property);
			}
			else{
				Object[] args = {facilityId};
				log.info(Messages.getMsg("FacilityID", args) + 
						" (" + Messages.getMsg("add") + ")");

				repository.addNode(property);
			}
		} catch (DuplicateKeyException e) {
			String args[] = {facilityId};
			log.error(Messages.getMsg("ImportTool.Common.1", args));
			System.exit(20);
		} catch (Exception e) {
			log.error(Messages.getMsg("ConnectManagerFailed"), e);
			System.exit(14);
		}
	}

	/**
	 * ノードデバイス情報をコピーする。<br>
	 * 
	 * @param property コピー先プロパティ
	 * @param sourceProperty コピー元プロパティ
	 */
	@SuppressWarnings("unchecked")
	protected void copyDeviceProperty(Property property, Property sourceProperty) {
		ArrayList propertyList = null;
		ArrayList deviceList = null;

		propertyList = PropertyUtil.getProperty(property, NodeProperty.DEVICE);
		Property deviceProperty = (Property)propertyList.get(0);
		int addIndex = PropertyUtil.getPropertyIndex(property, deviceProperty);

		deviceList = PropertyUtil.getProperty(sourceProperty, NodeProperty.DEVICE);
		for(int i = 0; i < deviceList.size(); i++){
			Property sourceDevice = (Property)deviceList.get(i);

			ArrayList name = PropertyUtil.getProperty(sourceDevice, NodeProperty.DEVICE_NAME);
			ArrayList oid = PropertyUtil.getProperty(sourceDevice, NodeProperty.DEVICE_OID);
			ArrayList index = PropertyUtil.getProperty(sourceDevice, NodeProperty.DEVICE_INDEX);
			ArrayList type = PropertyUtil.getProperty(sourceDevice, NodeProperty.DEVICE_TYPE);
			ArrayList description = PropertyUtil.getProperty(sourceDevice, NodeProperty.DEVICE_DESCRIPTION);

			if(i == 0){
				//デバイスと書いてあるところにデバイス名を表示
				deviceProperty.setValue(((Property)name.get(0)).getValue());
				//デバイス名
				propertyList = PropertyUtil.getProperty(deviceProperty, NodeProperty.DEVICE_NAME);
				((Property)propertyList.get(0)).setValue(((Property)name.get(0)).getValue());
				//デバイスOID
				propertyList = PropertyUtil.getProperty(deviceProperty, NodeProperty.DEVICE_OID);
				((Property)propertyList.get(0)).setValue(((Property)oid.get(0)).getValue());
				//デバイスINDEX
				propertyList = PropertyUtil.getProperty(deviceProperty, NodeProperty.DEVICE_INDEX);
				((Property)propertyList.get(0)).setValue(((Property)index.get(0)).getValue());
				//デバイス種別
				propertyList = PropertyUtil.getProperty(deviceProperty, NodeProperty.DEVICE_TYPE);
				((Property)propertyList.get(0)).setValue(((Property)type.get(0)).getValue());
				//説明
				propertyList = PropertyUtil.getProperty(deviceProperty, NodeProperty.DEVICE_DESCRIPTION);
				((Property)propertyList.get(0)).setValue(((Property)description.get(0)).getValue());
			}
			else{
				Property copy = PropertyUtil.copy(deviceProperty);

				//デバイスと書いてあるところにデバイス名を表示
				copy.setValue(((Property)name.get(0)).getValue());

				//デバイス名
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.DEVICE_NAME);
				((Property)propertyList.get(0)).setValue(((Property)name.get(0)).getValue());
				//デバイスOID
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.DEVICE_OID);
				((Property)propertyList.get(0)).setValue(((Property)oid.get(0)).getValue());
				//デバイスINDEX
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.DEVICE_INDEX);
				((Property)propertyList.get(0)).setValue(((Property)index.get(0)).getValue());
				//デバイス種別
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.DEVICE_TYPE);
				((Property)propertyList.get(0)).setValue(((Property)type.get(0)).getValue());
				//説明
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.DEVICE_DESCRIPTION);
				((Property)propertyList.get(0)).setValue(((Property)description.get(0)).getValue());

				property.addChildren(copy, addIndex + i);
			}
		}
	}
	
	/**
	 * ノードファイルシステム情報をコピーする。<br>
	 * 
	 * @param property コピー先プロパティ
	 * @param sourceProperty コピー元プロパティ
	 */
	@SuppressWarnings("unchecked")
	protected void copyFileSystemProperty(Property property, Property sourceProperty) {
		ArrayList propertyList = null;
		ArrayList fsList = null;

		propertyList = PropertyUtil.getProperty(property, NodeProperty.FILE_SYSTEM);
		Property fsProperty = (Property)propertyList.get(0);
		int addIndex = PropertyUtil.getPropertyIndex(property, fsProperty);

		fsList = PropertyUtil.getProperty(sourceProperty, NodeProperty.FILE_SYSTEM);
		for(int i = 0; i < fsList.size(); i++){
			Property sourceDevice = (Property)fsList.get(i);

			ArrayList index = PropertyUtil.getProperty(sourceDevice, NodeProperty.FILE_SYSTEM_INDEX);
			ArrayList point = PropertyUtil.getProperty(sourceDevice, NodeProperty.FILE_SYSTEM_MOUNT_POINT);
			ArrayList oid = PropertyUtil.getProperty(sourceDevice, NodeProperty.FILE_SYSTEM_OID);
			ArrayList type = PropertyUtil.getProperty(sourceDevice, NodeProperty.FILE_SYSTEM_TYPE);
			ArrayList description = PropertyUtil.getProperty(sourceDevice, NodeProperty.FILE_SYSTEM_DESCRIPTION);
			
			if(i == 0){
				//ファイルシステムと書いてあるところにマウントポイントを表示
				fsProperty.setValue(((Property)point.get(0)).getValue());
				//ファイルシステムINDEX
				propertyList = PropertyUtil.getProperty(fsProperty, NodeProperty.FILE_SYSTEM_INDEX);
				((Property)propertyList.get(0)).setValue(((Property)index.get(0)).getValue());
				//マウント位置
				propertyList = PropertyUtil.getProperty(fsProperty, NodeProperty.FILE_SYSTEM_MOUNT_POINT);
				((Property)propertyList.get(0)).setValue(((Property)point.get(0)).getValue());
				//ファイルシステムOID
				propertyList = PropertyUtil.getProperty(fsProperty, NodeProperty.FILE_SYSTEM_OID);
				((Property)propertyList.get(0)).setValue(((Property)oid.get(0)).getValue());
				//ファイルシステム種別
				propertyList = PropertyUtil.getProperty(fsProperty, NodeProperty.FILE_SYSTEM_TYPE);
				((Property)propertyList.get(0)).setValue(((Property)type.get(0)).getValue());
				//説明
				propertyList = PropertyUtil.getProperty(fsProperty, NodeProperty.FILE_SYSTEM_DESCRIPTION);
				((Property)propertyList.get(0)).setValue(((Property)description.get(0)).getValue());
			}
			else{
				Property copy = PropertyUtil.copy(fsProperty);

				//ファイルシステムと書いてあるところにマウントポイントを表示
				copy.setValue(((Property)point.get(0)).getValue());

				//ファイルシステムINDEX
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.FILE_SYSTEM_INDEX);
				((Property)propertyList.get(0)).setValue(((Property)index.get(0)).getValue());
				//マウント位置
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.FILE_SYSTEM_MOUNT_POINT);
				((Property)propertyList.get(0)).setValue(((Property)point.get(0)).getValue());
				//ファイルシステムOID
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.FILE_SYSTEM_OID);
				((Property)propertyList.get(0)).setValue(((Property)oid.get(0)).getValue());
				//ファイルシステム種別
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.FILE_SYSTEM_TYPE);
				((Property)propertyList.get(0)).setValue(((Property)type.get(0)).getValue());
				//説明
				propertyList = PropertyUtil.getProperty(copy, NodeProperty.FILE_SYSTEM_DESCRIPTION);
				((Property)propertyList.get(0)).setValue(((Property)description.get(0)).getValue());

				property.addChildren(copy, addIndex + i);
			}
		}
	}

	/**
	 * ノードプロパティを取得する。<br>
	 * 
	 * @return ノードプロパティ
	 */
	protected Property getNodeProperty() {

		RepositoryController repository = EjbConnectionManager.getConnectionManager().getRepositoryController();

		Property property = null;
		try {
			property = repository.getNodeProperty("", PropertyConstant.MODE_ADD, Locale.getDefault());
		} catch (Exception e) {
			log.error(Messages.getMsg("ConnectManagerFailed"), e);
			System.exit(14);
		}
		return property;
	}

	/**
	 * ファシリティリストを取得する。<br>
	 * 
	 * @return ファシリティ一覧
	 */
	@SuppressWarnings("unchecked")
	protected ArrayList<Property> getNodeList() {

		RepositoryController repository = EjbConnectionManager.getConnectionManager().getRepositoryController();

		ArrayList<Property> nodeList = new ArrayList<Property>();
		try {
			ArrayList<String> records = repository.getNodeFacilityIdList();
			for(String facilityId : records){
				Property node = repository.getNodeProperty(facilityId, PropertyConstant.MODE_SHOW, Locale.getDefault());
				nodeList.add(node);
			}
		} catch (Exception e) {
			log.error(Messages.getMsg("ConnectManagerFailed"), e);
			System.exit(14);
		}
		return nodeList;
	}
}