/////////////////////////////////////////////////////////////////
//Copyright (C) 2005 NTT CORPORATION.
//
//	画面レイアウト情報管理クラス
//
//		変更履歴
//			2005.02.19  新規作成  村上 靖征
//
//	機能
//
//	このクラスは画面レイアウト情報を管理するクラスです。
//
////////////////////////////////////////////////////////////////

package jp.co.ntt.lms.xmf;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;


/**
 *  画面レイアウト情報管理クラス
 * 
 *  このクラスは画面レイアウト情報を管理するクラスです。
 * 
 *  @author 村上 靖征
 *  @version 1.0
 */
public class CustomLayoutManager
{
	/**
	 * ユーザー定義の設定情報
	 */
	public static final int RESULT_USERDEF = 0;

	/**
	 * グループ定義の設定情報
	 */
	public static final int RESULT_GROUPDEF = 1;

	/**
	 * デフォルト定義の設定情報
	 */
	public static final int RESULT_DEFAULTDEF = 2;

	/**
	 * エラー
	 */
	public static final int RESULT_ERROR = 3;

	private FrameLayout topFrame;

	private FrameLayout leftFrame;

	private FrameLayout contentFrame;

	/**
	 * 
	 * デフォルトの設定情報を読み込む。
	 * 
	 * @param servletContext サーブレットコンテキスト
	 * @return 読み込み結果を表す数値
	 * 			2 - 正常終了
	 *          3 - 異常終了
	 */
	public int loadDefaultDef(ServletContext servletContext)
	{
		return loadDef(servletContext, "", "");
	}

	/**
	 * 
	 * 指定したユーザーIDとグループID に関連付けられた設定情報を読み込む。
	 * 以下の順に設定が存在すれば、上書きして取得する。
	 * デフォルト定義のレイアウト設定
	 * グループ定義のレイアウト設定
	 * ユーザー定義のレイアウト設定
	 * 
	 * @param servletContext サーブレットコンテキスト
	 * @param userId ユーザーID
	 * @param groupId グループID
	 * @return 読み込み結果を示す数値
	 * 			0 - ユーザー定義のレイアウト設定を読み込み正常終了
	 * 			1 - グループ定義のレイアウト設定を読み込み正常終了
	 * 			2 - デフォルト定義のレイアウト設定を読み込み正常終了
	 * 			3 - 異常終了
	 */
	public int loadDef(ServletContext servletContext, String userId,
			String groupId)
	{
		return loadDef(servletContext,
				getBaseDirKey(), userId, groupId);
	}

	private String getBaseDirKey()
	{
		return "jp.co.ntt.lms.xmf.customizeview.basedir";
	}
	
	/**
	 * 
	 * 上フレームを表示するかどうかのフラグを取得する。
	 * 
	 * @return 上フレームを表示するかどうかのフラグ
	 */
	public boolean isTopFrameVisible()
	{
		return (topFrame != null);
	}
	
	/**
	 * 
	 * 左フレームを表示するかどうかのフラグを取得する。
	 * 
	 * @return 左フレームを表示するかどうかのフラグ
	 */
	public boolean isLeftFrameVisible()
	{
		return (leftFrame != null);
	}
	
	/**
	 * 上フレームのレイアウト情報を取得する。
	 * 
	 * @return 上フレームのレイアウト情報
	 */
	public FrameLayout getTopFrame()
	{
		return topFrame;
	}

	/**
	 * 左フレームのレイアウト情報を取得する。
	 * 
	 * @return 左フレームのレイアウト情報
	 */
	public FrameLayout getLeftFrame()
	{
		return leftFrame;
	}

	/**
	 * コンテンツフレームのレイアウト情報を取得する。
	 * 
	 * @return コンテンツフレームのレイアウト情報
	 */
	public FrameLayout getContentFrame()
	{
		return contentFrame;
	}

	protected int loadDef(ServletContext servletContext, String baseDirKey,
			String userId, String groupId)
	{
		int result = RESULT_ERROR;
		DocumentBuilder parser = null;
		String baseDir = null;
		try
		{
			parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			baseDir = servletContext.getInitParameter(baseDirKey);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return result;
		}
		if (baseDir == null)
		{
			return result;
		}
		else
		{
			if (!baseDir.endsWith("/"))
			{
				baseDir = baseDir.concat("/");
			}
		}
		try
		{
			//デフォルト定義の読み込み
			loadDefaultDef(parser, servletContext, baseDir, userId, groupId);
			result = RESULT_DEFAULTDEF;
			if (userId == null) userId = "";
			if (groupId == null) groupId = "";
			if (userId.length() == 0 && groupId.length() == 0) { return result; }
			//グループ定義の読み込み
			loadGroupDef(parser, servletContext, baseDir, userId, groupId);
			result = RESULT_GROUPDEF;
			//ユーザー定義の読み込み
			loadUserDef(parser, servletContext, baseDir, userId, groupId);
			result = RESULT_USERDEF;
		}
		catch (IOException ex1)
		{
			switch (result)
			{
			case 3:
				//デフォルト定義読み込み時にエラー
				//異常終了とする
				break;
			case 2:
				//グループ定義読み込み時にエラー
				try
				{
					//ユーザー定義の読み込み
					loadUserDef(parser, servletContext, baseDir, userId,
							groupId);
					result = RESULT_USERDEF;
				}
				catch (SAXException ex)
				{
					ex.printStackTrace();
					result = RESULT_ERROR;
				}
				catch (IOException ex)
				{
					//グループ定義もユーザー定義もない。
				}
				break;
			case 1:
				break;
			}
		}
		catch (SAXException e)
		{
			e.printStackTrace();
			result = 3;
		}
		return result;
	}

	protected void loadDefaultDef(DocumentBuilder parser,
			ServletContext servletContext, String baseDir, String userId,
			String groupId) throws SAXException, IOException
	{
		//デフォルト定義の読み込み
		loadFrames(parser, servletContext
				.getResourceAsStream(makeDefaultCLDPath(baseDir)));
	}

	protected void loadGroupDef(DocumentBuilder parser,
			ServletContext servletContext, String baseDir, String userId,
			String groupId) throws SAXException, IOException
	{
		loadFrames(parser, servletContext
				.getResourceAsStream(makeGroupCLDPath(baseDir, groupId)));
	}

	protected void loadUserDef(DocumentBuilder parser,
			ServletContext servletContext, String baseDir, String userId,
			String groupId) throws SAXException, IOException
	{
		loadFrames(parser, servletContext
				.getResourceAsStream(makeUserCLDPath(baseDir, userId)));
	}

	private String makeUserCLDPath(String baseDir, String userId)
	{
		if (userId.length() > 0)
		{
			return baseDir + "/users/" + userId + "/user.cld";
		}
		else
		{
			return baseDir + "/users/default.cld";
		}
	}

	private String makeGroupCLDPath(String baseDir, String groupId)
	{
		if (groupId.length() > 0)
		{
			return baseDir + "/groups/" + groupId + "/group.cld";
		}
		else
		{
			return baseDir + "/groups/default.cld";
		}
	}

	private String makeDefaultCLDPath(String baseDir)
	{
		return baseDir + "default.cld";
	}

	private void loadFrames(DocumentBuilder parser, InputStream is)
			throws SAXException, IOException
	{
		Node document = parser.parse(new InputSource(is));
		Node root = document.getFirstChild();
		List list = NodeUtil.getNamedChildElementList(root, "frame");
		for (int i = 0; i < list.size(); i++)
		{
			Node node = (Node) list.get(i);
			if ("top".equals(NodeUtil.getAttribute(node, "name")))
			{
				topFrame = new FrameLayout();
				topFrame.loadLayout(node);
			}
			if ("left".equals(NodeUtil.getAttribute(node, "name")))
			{
				leftFrame = new FrameLayout();
				leftFrame.loadLayout(node);
			}
			if ("content".equals(NodeUtil.getAttribute(node, "name")))
			{
				contentFrame = new FrameLayout();
				contentFrame.loadLayout(node);
			}
		}

	}

	/**
	 * 指定された Document オブジェクトをデフォルト定義として保存する。
	 * 
	 * @param servletContext サーブレットコンテキスト
	 * @param document XML ドキュメント
	 * @throws Exception
	 */
	public void saveDefaultDef(ServletContext servletContext, Document document) throws Exception
	{
		String baseDir = servletContext.getInitParameter(getBaseDirKey());
		if (!baseDir.endsWith("/"))
		{
			baseDir += "/";
		}
		String path = servletContext.getRealPath(makeDefaultCLDPath(baseDir));
		
		File target = new File(path);
		FileOutputStream file = new FileOutputStream(target);
		
		TransformerFactory tff = TransformerFactory.newInstance();
		Transformer tf = tff.newTransformer();
		tf.setOutputProperty(OutputKeys.INDENT, "yes");
		DOMSource source = new DOMSource();
		source.setNode(document.getDocumentElement());
		StreamResult result = new StreamResult();
		result.setOutputStream(file);
		tf.transform(source, result);
		file.flush();
		file.close();
	}
}