/*
 * Copyright (c) 2017 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.fukurou.fileexec;

//	import java.nio.file.Paths;							// 6.8.1.5 (2017/09/08)

import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.function.Supplier;						// 6.8.1.0 (2017/07/14)
import java.util.function.Function;						// 7.2.5.0 (2020/06/01)

/**
 * XLoggerは、Throwable を引数に取るwarningと、Level 600 の debug メソッドを
 * 持つ、Logger の拡張クラスです。
 * ここでは、継承するのではなく、委譲で、最低限のメソッドだけに対応しています。
 * (LogManager とか、色々とややこしそうなので、調査する暇が無い)
 *
 * WARNING(900) → INFO(800) → CONFIG(700) → XXXX(600) → FINE(500) → ALL(Integer.MIN_VALUE)
 * となっていますが、FINE では、多すぎ、INFO は、通常使用、間に、DEBUG的な、
 * ロギングが欲しい場合に使用します。
 * CONFIG を使いたいところですが、｢CONFIGは静的な構成メッセージのメッセージ・レベルです。｣と
 * JavaDocにわざわざ、書かれていることから、使用を避けます。
 *
 * @og.rev 7.0.0.0 (2017/07/07) 新規作成
 *
 * @version  7.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK1.8,
 */
public class XLogger {
	// 7.2.5.0 (2020/06/01) 各クラスで、class.getSimpleName() を渡すようにしたので短縮不要。
//	/** 初期設定されているリソースバンドルのbaseName {@value} */
//	public static final String OMIT_NAME = "org.opengion.fukurou." ;	// fileexec は残す

	/**
	 * デバッグレベルを新規に定義します。
	 *
	 * OFF:Integer.MAX_VALUE , SEVERE:1000 , WARNING:900 , INFO:800 , CONFIG:700 , FINE:500 , FINER:400 , FINEST:300 , ALL:Integer.MIN_VALUE
	 * LEVEL_DEBUG:600 で定義することで、INFO より細かいが、FINE より荒いログ出力が可能です。
	 * 他のアプリケーションで、INFO は許せても、FINE は許せない場合があるので、独自のログ出力が、可能です。
	 */
	private static final class LEVEL_DEBUG extends Level {
		private static final long serialVersionUID = 681020170714L ;		// 6.8.1.0 (2017/07/14)
		/**
		 * デバッグレベルのコンストラクター
		 */
		public LEVEL_DEBUG() { super( "DEBUG",600 ); }
	};

//	private static final Level DEBUG = new LEVEL_DEBUG();
	private static final Level L_DEBUG = new LEVEL_DEBUG();					// 6.9.7.0 (2018/05/14) PMD Field DEBUG has the same name as a method

	private final Logger LOGGER;

	/**
	 * 名前を指定して、XLoggerオブジェクトを作成します。
	 *
	 * @og.rev 6.8.1.5 (2017/09/08) logフォルダの存在チェックと作成
	 *
	 * @param	name	 ロガーの名前。通常は、クラス.class.getName() を渡せばよいです。
	 */
	private XLogger( final String name ) {
//		FileUtil.mkdirs( Paths.get( "log" ) );		// Logger の log フォルダが無ければ作成します。

		LOGGER = Logger.getLogger( name );
	}

	/**
	 * 名前を指定して、XLoggerオブジェクトを作成します。
	 *
	 * @og.rev 7.2.1.0 (2020/03/13) ロガーの名前から、共通部分を削除します。
	 * @og.rev 7.2.5.0 (2020/06/01) 各クラスで、class.getSimpleName() を渡すようにした。
	 *
	 * @param	name	 ロガーの名前。通常は、クラス.class.getName() を渡せばよいです。
	 * @return	XLoggerオブジェクト
	 */
	public static XLogger getLogger( final String name ) {
//		String key = name ;
//		if( key.startsWith( OMIT_NAME ) ) {
//			key = name.substring( OMIT_NAME.length() );
//		}

//		return new XLogger( name );		// 今は、個別に作成していますが、本来は、同じオブジェクトを返すようにすべき。
		return new XLogger( name );		// 各クラスで static で持つのでキャッシュしません。
	}

	/**
	 * INFO レベルのログをとります。
	 *
	 * @param	msgSupplier	呼び出されると、目的のログ・メッセージを生成する関数
	 * @see		Logger#info( Supplier )
	 */
	public void info( final Supplier<String> msgSupplier ) {
		LOGGER.info( msgSupplier );
	}

	/**
	 * WARNING レベルのログをとります。
	 *
	 * @param	msgSupplier	呼び出されると、目的のログ・メッセージを生成する関数
	 * @see		Logger#warning( Supplier )
	 */
	public void warning( final Supplier<String> msgSupplier ) {
		LOGGER.warning( msgSupplier );
	}

	/**
	 * WARNING レベルのログをとります。
	 *
	 * @og.rev 7.2.5.0 (2020/06/01) メソッド追加。
	 *
	 * @param id	リソースのキーとなるID。
	 * @param args	リソースを、MessageFormat.format で加工する場合の引数。
	 * @see		Logger#warning( Supplier )
	 */
	public void warning( final String id , final Object... args ) {
		LOGGER.warning( MsgUtil.errPrintln( id,args ) );
	}

	/**
	 * WARNING レベルのログをとります。
	 *
	 * これは、Throwable を引数に取る拡張されたメソッドです。
	 *
	 * @param	th	ログ・メッセージに関連したThrowable。
	 * @param	msgSupplier	呼び出されると、目的のログ・メッセージを生成する関数
	 * @see		Logger#log( Level,Throwable,Supplier )
	 */
	public void warning( final Throwable th , final Supplier<String> msgSupplier ) {
		LOGGER.log( Level.WARNING , th , msgSupplier );
	}

	/**
	 * WARNING レベルのログをとります。
	 *
	 * これは、Throwable を引数に取る拡張されたメソッドです。
	 *
	 * @og.rev 7.2.5.0 (2020/06/01) メソッド追加。
	 *
	 * @param th	発生元のThrowable( null値は許容されます )
	 * @param id	リソースのキーとなるID。
	 * @param args	リソースを、MessageFormat.format で加工する場合の引数。
	 * @see		Logger#log( Level,Throwable,Supplier )
	 */
	public void warning( final Throwable th , final String id , final Object... args ) {
		LOGGER.log( Level.WARNING , MsgUtil.errPrintln( id,args ) , th );			// 1.4.0 (2019/10/01) StackTraceの重複を避けるため
	}

	/**
	 * 600 レベルのログをとります。
	 *
	 * Supplierを引数に、Level = 600 のログをとります。
	 *
	 * @param	msgSupplier	呼び出されると、目的のログ・メッセージを生成する関数
	 * @see		Logger#log( Level,Supplier )
	 */
	public void debug( final Supplier<String> msgSupplier ) {
//		LOGGER.log( DEBUG , msgSupplier );
		LOGGER.log( L_DEBUG , msgSupplier );
	}

	/**
	 * 数値の変数を受け取って表示する、600 レベルのログをとります。
	 *
	 * Supplierを引数に、Level = 600 のログをとります。
	 * 関数型インタフェースは引数にfinal変数しか使えませんが、数値は大抵可変なので
	 * final化せずに、引数として渡すことが出来るようにします。
	 *
	 * @og.rev 7.2.5.0 (2020/06/01) メソッド追加。
	 *
	 * @param	num			数値引数
	 * @param	msgFunction	呼び出されると、目的のログ・メッセージを生成する関数
	 * @see		Logger#log( Level,Supplier )
	 */
	public void debug( final int num , final Function<Integer,String> msgFunction ) {
		LOGGER.log( L_DEBUG , () -> msgFunction.apply( num ) );
	}
}
