/*
 * MosP - Mind Open Source Project    http://www.mosp.jp/
 * Copyright (C) MIND Co., Ltd.       http://www.e-mind.co.jp/
 * 
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 * 
 * 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jp.mosp.framework.utils;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import jp.mosp.framework.base.MospException;
import jp.mosp.framework.constant.MospConst;
import jp.mosp.framework.property.MessageProperty;
import jp.mosp.framework.property.MospProperties;

/**
 * MosPアプリケーションを開発する上で有用なメソッドを提供する。<br><br>
 */
public final class MospUtility {
	
	/**
	 * Bean及びDAO接尾辞リスト。<br>
	 */
	protected static final String[]	SUFFIX_ARRAY				= { "BeanInterface", "Bean", "Interface" };
	
	/**
	 * 人名区切文字(姓と名の間の文字)。
	 */
	protected static final String	STR_HUMANS_NAME_SEPARATOR	= " ";
	
	/**
	 * コマンド末尾のワイルドカード。
	 */
	protected static final String	WILD_CARD_COMMAND			= "*";
	

	/**
	 * 他クラスからのインスタンス化を防止する。<br>
	 */
	private MospUtility() {
		// 処理無し
	}
	
	/**
	 * クラスのBeanキーを取得する。<br>
	 * @param cls 対象クラス
	 * @return クラスのBeanキー
	 */
	public static String getBeanKey(Class<?> cls) {
		// クラス名取得
		String key = cls.getSimpleName();
		// Beanキー取得
		for (String suffix : SUFFIX_ARRAY) {
			if (key.indexOf(suffix) == key.length() - suffix.length()) {
				key = key.replace(suffix, "");
				break;
			}
		}
		return key;
	}
	
	/**
	 * メッセージ設定情報をJavaScriptファイルに変換する。<br>
	 * @param mospProperties MosP設定情報
	 * @throws MospException ファイル出力に失敗した場合 
	 */
	public static void outputMessageJs(MospProperties mospProperties) throws MospException {
		// JavaScriptファイルパス及びJavaScript変数名宣言
		final String path = mospProperties.getApplicationProperty(MospConst.APP_DOCBASE) + "/pub/common/js/message.js";
		final String name = "messages";
		// メッセージ設定情報群取得
		Map<String, MessageProperty> messageProperties = mospProperties.getMessageProperties();
		// 出力文字列作成
		StringBuffer sb = new StringBuffer();
		sb.append("var ");
		sb.append(name);
		sb.append(" = new Object();");
		sb.append(MospConst.LINE_SEPARATOR);
		for (Entry<String, MessageProperty> entry : messageProperties.entrySet()) {
			// メッセージ設定情報取得
			MessageProperty messageProperty = entry.getValue();
			// クライアント利用可否確認
			if (messageProperty.getClientAvailable() == false) {
				continue;
			}
			// 要素追加
			sb.append(name);
			sb.append("[\"");
			sb.append(messageProperty.getKey());
			sb.append("\"] = \"");
			sb.append(messageProperty.getMessageBody());
			sb.append("\";");
			sb.append(MospConst.LINE_SEPARATOR);
		}
		// ファイル出力
		outputFile(mospProperties, path, sb.toString());
	}
	
	/**
	 * プルダウン用配列から、コードに対応する名称を取得する。<br>
	 * @param code  対象コード
	 * @param array プルダウン用配列
	 * @return コード名称
	 */
	public static String getCodeName(String code, String[][] array) {
		// コード確認
		if (code == null || code.isEmpty()) {
			return "";
		}
		// プルダウンの内容を確認
		for (String[] element : array) {
			if (element[0].equals(code)) {
				return element[1];
			}
		}
		return code;
	}
	
	/**
	 * ファイルを出力する。
	 * @param mospProperties MosP設定情報
	 * @param path 出力ファイルパス
	 * @param body 出力内容
	 * @throws MospException ファイル出力に失敗した場合
	 */
	public static void outputFile(MospProperties mospProperties, String path, String body) throws MospException {
		FileOutputStream fos = null;
		OutputStreamWriter osw = null;
		try {
			fos = new FileOutputStream(path, false);
			osw = new OutputStreamWriter(fos, mospProperties.getApplicationProperty(MospConst.APP_CHARACTER_ENCODING));
			osw.write(body);
		} catch (FileNotFoundException e) {
			throw new MospException(e);
		} catch (UnsupportedEncodingException e) {
			throw new MospException(e);
		} catch (IOException e) {
			throw new MospException(e);
		} finally {
			try {
				if (osw != null) {
					osw.close();
				}
			} catch (IOException e) {
				throw new MospException(e);
			} finally {
				try {
					if (fos != null) {
						fos.close();
					}
				} catch (IOException e) {
					throw new MospException(e);
				}
			}
		}
	}
	
	/**
	 * 人名を取得する。<br>
	 * @param firstName 名
	 * @param lastName  姓
	 * @return 人名
	 */
	public static String getHumansName(String firstName, String lastName) {
		return lastName + STR_HUMANS_NAME_SEPARATOR + firstName;
	}
	
	/**
	 * 対象文字列を正規表現の区切りで分割する。<br>
	 * 前後に空白が存在した場合は、その空白を除く。<br>
	 * @param target 対象文字列
	 * @param regex  正規表現の区切り
	 * @return 文字列の配列
	 */
	public static String[] split(String target, String regex) {
		// 対象文字列が空の場合
		if (target.trim().isEmpty()) {
			return new String[0];
		}
		// 対象文字列を正規表現の区切りで分割
		String[] array = target.split(regex);
		// 空白除去
		for (int i = 0; i < array.length; i++) {
			array[i] = array[i].trim();
		}
		return array;
	}
	
	/**
	 * コマンドの末尾をワイルドカード化した文字列を取得する。<br>
	 * 既に末尾がワイルドカード化されている場合、
	 * ワイルドカードを除いてから処理を行う。<br>
	 * @param command コマンド
	 * @return コマンドの末尾をワイルドカード化した文字列
	 */
	public static String getWildCardCommand(String command) {
		// コマンドからワイルドカードを除去
		String wildCardCommand = command.replaceAll("\\*", "");
		// コマンド確認
		if (wildCardCommand.isEmpty()) {
			return wildCardCommand;
		}
		// コマンド末尾をワイルドカード化
		return wildCardCommand.substring(0, wildCardCommand.length() - 1) + WILD_CARD_COMMAND;
	}
	
	/**
	 * 配列(String)をリスト(String)に変換する。<br>
	 * @param array 対象配列(String)
	 * @return リスト(String)
	 */
	public static List<String> asList(String[] array) {
		return Arrays.asList(array);
	}
	
	/**
	 * リスト(String)を配列(String)に変換する。<br>
	 * @param list 対象リスト(String)
	 * @return 配列(String)
	 */
	public static String[] toArray(List<String> list) {
		return list.toArray(new String[1]);
	}
	
	/**
	 * 例外スタックトレースを取得する。<br>
	 * @param ex 例外オブジェクト
	 * @return 例外スタックトレース文字列
	 */
	public static String getStackTrace(Throwable ex) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		ex.printStackTrace(pw);
		String msg = sw.toString();
		msg = msg.replaceAll(MospConst.LINE_SEPARATOR, "");
		return msg;
	}
	
}
