/*
 * Copyright (c) 2009 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.hayabusa.resource;

import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.fukurou.util.StringUtil;

import java.util.Map;
import java.util.WeakHashMap ;
import java.util.Collections ;

/**
 * ロールモードは、画面オブジェクトやカラムオブジェクトのロール-モード制御の情報を
 * 管理するクラスです。
 * ROLES 情報は、AAA|BBB|CCC と 『|』で区切られた複数のロールを持っています。
 * 通常、ユーザーロールは画面やカラムの各オブジェクトに対してロール制御可能です。
 * ログインユーザーは、自分自身のロールを、画面やカラムが持っているかを判定します。
 * 画面に関しては、従来のデフォルトアクセスがなくなり、ロールを登録する場合は、
 * 必ず ユーザーロールとの比較が行われます。画面ロールを登録しない場合は、アクセス
 * 可能と判断されます。つまり、画面の場合は、なにも設定しなければ、アクセス可能と
 * 判断されます。
 * カラムロールも同様に、何も設定しなければフルアクセスできます。通常、ほとんどの
 * ケースでカラムロールが使われることはありません。
 * RWMODE 情報は、各ロールに対して、３つの項目で表しています。
 *   １："-" メニュー非表示   "m" メニュー表示  "p" メニュー表示(強制プルダウン表示)
 *   ２："-" アクセス拒否     "r" 読取許可      "w" 読取、書込許可
 *   ３："-" 未対応           "d" ファイル出力  "u" ファイル入力  "f" ファイル入出力
 *       … このd,u,f では、【出力方法設定】タブは表示されません。
 *       "o" 表示順編集のみ可  … この設定では、【表示項目設定】 タブで位置と表示順のみ変更できます。
 *       "e" 画面編集可        … この設定で、編集機能がフルに使えます。
 *       互換性の関係より、"" は、"e"  と同等とします。
 *       設定キーの関係より、"o" と "e" を設定すると、"f" が自動的に設定されます。
 *
 * この３項目を順次つないで、"--","-r","-w","mr","mw" などの設定を行います。
 * モードが設定されている場合は、共通モードとして、すべてのロールに同じモードを
 * 割り当てます。個別に割り当てる場合は、ROLES 情報の後ろに () 付きで追記します。
 * 例えば、AAA|BBB(-r)|CCC とすれば、BBB ロールの場合は、読取専用になります。
 * ロールをぶつける場合は、AND 演算になります。
 * 過去(Ver3)のモードとの互換性をとる場合、"rw" は "mw" へ、"r-" は"mr" へ変換
 * してください。
 *
 * @og.rev 4.0.0.0 (2004/01/31) 新規作成
 * @og.rev 4.3.3.0 (2008/10/01) pモード追加
 * @og.group リソース管理
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public final class RoleMode {
	private static final Map<String,RoleMode> roleMap
					= Collections.synchronizedMap(
						new WeakHashMap<String,RoleMode>( HybsSystem.BUFFER_SMALL )
					  );

	// 4.0.0 (2005/01/31) param属性追加
	// 4.3.3.0 (2008/10/01) pを追加するため、ビット表現を拡張
//	public static final byte FULL_MODE = (byte)0x1f;	// mwf = 11111 = 0x1f
//	public static final byte M_MODE    = (byte)0x10;	// m-- = 10000 = 0x10
//	public static final byte R_MODE    = (byte)0x04;	// -r- = 00100 = 0x04
//	public static final byte W_MODE    = (byte)0x0C;	// -w- = 01100 = 0x0C
//	public static final byte D_MODE    = (byte)0x01;	// --d = 00001 = 0x01
//	public static final byte U_MODE    = (byte)0x02;	// --u = 00010 = 0x02
//	public static final byte F_MODE    = (byte)0x03;	// --f = 00011 = 0x03

//	/** MODE 定義 ( mwf ) */
//	public static final byte FULL_MODE = (byte)0x3f;	// mwf = 111111 = 0x3f
//	/** MODE 定義 ( m-- ) */
//	public static final byte M_MODE    = (byte)0x30;	// m-- = 110000 = 0x30
//	/** MODE 定義 ( p-- ) */
//	public static final byte P_MODE    = (byte)0x10;	// p-- = 010000 = 0x10
//	/** MODE 定義 ( -r- ) */
//	public static final byte R_MODE    = (byte)0x04;	// -r- = 000100 = 0x04
//	/** MODE 定義 ( -w- ) */
//	public static final byte W_MODE    = (byte)0x0C;	// -w- = 001100 = 0x0C
//	/** MODE 定義 ( --d ) */
//	public static final byte D_MODE    = (byte)0x01;	// --d = 000001 = 0x01
//	/** MODE 定義 ( --u ) */
//	public static final byte U_MODE    = (byte)0x02;	// --u = 000010 = 0x02
//	/** MODE 定義 ( --f ) */
//	public static final byte F_MODE    = (byte)0x03;	// --f = 000011 = 0x03
//
//	public static final String DEFAULT_MODE = "mwf";

	// 5.4.2.0 (2011/12/01) eを追加するため、ビット表現を拡張
//	/** MODE 定義 ( mwf ) */
//	public static final byte FULL_MODE = (byte)0x3f;	// mwe = 1111111 = 0x7f
//	/** MODE 定義 ( m-- ) */
//	public static final byte M_MODE    = (byte)0x60;	// m-- = 1100000 = 0x60
//	/** MODE 定義 ( p-- ) */
//	public static final byte P_MODE    = (byte)0x20;	// p-- = 0100000 = 0x20
//	/** MODE 定義 ( -r- ) */
//	public static final byte R_MODE    = (byte)0x08;	// -r- = 0001000 = 0x08
//	/** MODE 定義 ( -w- ) */
//	public static final byte W_MODE    = (byte)0x18;	// -w- = 0011000 = 0x18
//	/** MODE 定義 ( --d ) */
//	public static final byte D_MODE    = (byte)0x02;	// --d = 0000010 = 0x02
//	/** MODE 定義 ( --u ) */
//	public static final byte U_MODE    = (byte)0x04;	// --u = 0000100 = 0x04
//	/** MODE 定義 ( --f ) */
//	public static final byte F_MODE    = (byte)0x06;	// --f = 0000110 = 0x06
//	/** MODE 定義 ( --f ) */
//	public static final byte E_MODE    = (byte)0x07;	// --e = 0000111 = 0x07
	
	
	// 5.5.5.2 (2012/08/10) oを追加するため、ビット表現を拡張
	// 5.7.4.3 (2014/03/28) publicをprivateに変更します。
	/** MODE 定義 全許可				( mwe ) */
	private static final byte FULL_MODE = (byte)0x7f;	// mwe = 01 11 11 11 = 0x7f
	/** MODE 定義 メニュー表示			( m-- ) */
	private static final byte M_MODE    = (byte)0xc0;	// m-- = 11 00 00 00 = 0xc0
	/** MODE 定義 強制プルダウン表示	( p-- ) */
	private static final byte P_MODE    = (byte)0x40;	// p-- = 01 00 00 00 = 0x40

	/** MODE 定義 読取許可				( -r- ) */
	private static final byte R_MODE    = (byte)0x10;	// -r- = 00 01 00 00 = 0x10
	/** MODE 定義 書込許可				( -w- ) */
	private static final byte W_MODE    = (byte)0x30;	// -w- = 00 11 00 00 = 0x30

	/** MODE 定義 ファイル出力			( --d ) */
	private static final byte D_MODE    = (byte)0x04;	// --d = 00 00 01 00 = 0x04
	/** MODE 定義 ファイル入力			( --u ) */
	private static final byte U_MODE    = (byte)0x08;	// --u = 00 00 10 00 = 0x08
	/** MODE 定義 ファイル入出力		( --f ) */
	private static final byte F_MODE    = (byte)0x0c;	// --f = 00 00 11 00 = 0x0c

	/** MODE 定義 表示順編集のみ可		( --o ) */
	private static final byte O_MODE    = (byte)0x0e;	// --o = 00 00 11 10 = 0x0e
														//                ~   ←【出力方法設定】タブの表示
														//                 ~  ←【表示項目設定】タブの表示順使用
	/** MODE 定義 画面編集可			( --e ) */
	private static final byte E_MODE    = (byte)0x0f;	// --e = 00 00 11 11 = 0x0f

	/** 初期のモード */
	public static final String DEFAULT_MODE = "mwe";

	private final String	roles ;			// ロールズ
	private final String	rwmode ;		// モード
	private final String[]	roleArray ;		// ロール配列
	private final byte[]	bitModes ;		// モードのビット版(-:00, p:01, m:11,
											//					-:00, r:01, w:11,
											//					-:000, d:010, u:100, f:110, o:111, e:111)
//	private final byte		comBitMode  ;
	private final boolean	fullAccessFlag;	// フルアクセス許可時のフラグ
//	private final boolean	oneModeFlag;	// １つのモードですべてのロールを表現する場合 true

	private static final RoleMode FULL_ACCESS_ROLE_MODE_OBJ = new RoleMode() ;

	/**
	 * フルアクセスの RoleMode を構築します。
	 * 内部からのみ構築できるように private コンストラクタにしておきます。
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 */
	private RoleMode() {
		roles			= "FullAccess";
		rwmode			= DEFAULT_MODE;
		roleArray		= null;
		bitModes		= new byte[] { FULL_MODE };		// mwf = 01111111 = 0x7f
//		comBitMode		= FULL_MODE;
		fullAccessFlag	= true;
//		oneModeFlag		= true;
	}

	/**
	 * ロールとモードを元に、RoleModeオブジェクトを構築します。
	 * このコンストラクタは、他のパッケージから呼び出せないように、
	 * パッケージプライベートにしておきます。
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 *
	 * @param	roles	"|"で区切られた ロール文字列
	 * @param	mode	"|"で区切られ、ロール文字列と対応付けられたモード文字列。唯一の場合は共通モードになる。
	 */
	private RoleMode( final String roles,final String mode ) {
		this.roles	= roles ;		// ロールズ
		this.rwmode	= mode ;		// モード

//		if( rwmode == null || ( rwmode.length() < 2 ) ) {
//			String errMsg = "RWMODE の桁数は、２桁以上必要です。"
//						+ " roles [" + roles + "]  Mode [" + rwmode + "]"
//						+ HybsSystem.CR + toString() ;
//			throw new HybsSystemException( errMsg );
//		}

//		roleArray = StringUtil.csv2Array( roles,HybsSystem.GUI_DELIMITER ) ;	// ロール配列

		// roles="root" または、roleArray がない場合は、フルアクセス
//		fullAccessFlag = "root".equals( roles ) || ( roleArray.length == 0 );
		fullAccessFlag = "root".equals( roles ) || ( roles == null ) || ( roles.length() == 0 );

		// modes が一つだけの場合は、ワンモード
//		String[] modes = StringUtil.csv2Array( mode,HybsSystem.GUI_DELIMITER ) ;	// モード
//		oneModeFlag = ( modes.length == 1 );

		roleArray = StringUtil.csv2Array( roles,HybsSystem.GUI_DELIMITER ) ;	// ロール配列

		// bitModes を求めます。最低１つは作成します。同時に、roleArray もセットします。
//		bitModes = makeBitMode( modes );
		bitModes = makeBitMode( roleArray,rwmode );
	}

	/**
	 * ロールとモードを元に、RoleModeオブジェクトを構築します。
	 * 条件が同じ RoleModeオブジェクト があれば、キャッシュから返します。
	 * キャッシュになければ、新規に作成します。
	 * このキャッシュは、完全な内部キャッシュなので、いつクリアされるか保障がありません。
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 *
	 * @param	roles	"|"で区切られた ロール文字列
	 *
	 * @return	RoleModeオブジェクト
	 */
	public static RoleMode newInstance( final String roles ) {
		if( roles == null || roles.length() == 0 ) {
			return FULL_ACCESS_ROLE_MODE_OBJ;
		}

		return newInstance( roles,DEFAULT_MODE );
	}

	/**
	 * ロールとモードを元に、RoleModeオブジェクトを構築します。
	 * 条件が同じ RoleModeオブジェクト があれば、キャッシュから返します。
	 * キャッシュになければ、新規に作成します。
	 * このキャッシュは、完全な内部キャッシュなので、いつクリアされるか保障がありません。
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 *
	 * @param	roles	"|"で区切られた ロール文字列
	 * @param	mode	"|"で区切られ、ロール文字列と対応付けられたモード文字列。唯一の場合は共通モードになる。
	 *
	 * @return	RoleModeオブジェクト
	 */
	public static RoleMode newInstance( final String roles,final String mode ) {
		if( mode == null || mode.length() < 2 ) {
			String errMsg = "RWMODE の桁数は、２桁以上必要です。"
						+ " roles [" + roles + "]  mode [" + mode + "]"
						+ HybsSystem.CR;
			throw new HybsSystemException( errMsg );
		}

		if( ( roles == null || roles.length() == 0 ) &&
			( "mw".equals( mode ) || DEFAULT_MODE.equals( mode ) ) ) {
				return FULL_ACCESS_ROLE_MODE_OBJ ;
		}

		String key = roles + mode ;
		RoleMode roleMode = roleMap.get( key );
		if( roleMode == null ) {
			roleMode = new RoleMode( roles,mode );
			roleMap.put( key,roleMode );
		}

		return roleMode;
	}

	/**
	 * フルアクセスできるRoleModeオブジェクトを返します。
	 * これは、カラムオブジェクトなど、ほとんどのケースでフルアクセスできる場合に、
	 * 同じオブジェクトを常に返すようにすることで、メモリの節約と以降の処理の共通化を
	 * 図る為の機能です。シングルトン対応のNULLオブジェクトパターンに近いです。
	 *
	 * @return RoleMode	フルアクセスできるRoleModeオブジェクト
	 */
//	static RoleMode getFullAccessRoleMode() {
//		return FULL_ACCESS_ROLE_MODE_OBJ ;
//	}

	/**
	 * ロールズを返します。
	 *
	 * @return ロールズ文字列
	 */
	public String getRoles() { return roles; }

	/**
	 * モード配列を返します。
	 *
	 * @return モード配列
	 */
	public String getMode() { return rwmode; }

	/**
	 * ユーザーロール配列と比較してアクセス可否を返します。
	 *
	 * @param	userRoles	ユーザーロール配列
	 *
	 * @return アクセスできる(true)/出来ない(false)
	 */
//	public boolean isAccess( final String[] userRoles ) {
//		if( fullAccessFlag ) { return ( bitModes[0] > 0 ); }
//
//		// ユーザーロールが無い場合は、アクセス不許可
//		if( userRoles == null || userRoles.length == 0 ) {
//			return false;
//		}
//
//		for( int g=0; g<roleArray.length; g++ ) {
////			byte bit = ( oneModeFlag ) ? bitModes[0] : bitModes[g] ;
//			byte bit = bitModes[g] ;
//			for( int u=0; u<userRoles.length; u++ ) {
//				// 4.0.0.0 (2007/11/29) 入れ子if の統合
//				if( bit > 0 && roleArray[g].equalsIgnoreCase( userRoles[u] ) ) {
//					return true;
//				}
//			}
//		}
//		return false;
//	}

	/**
	 * 指定のユーザーロールに対する最終的なアクセス条件を取得します。
	 * アクセス条件は、複数あるユーザーロールの中で、最大のアクセス条件を算出します。
	 * 例えば、AAA(-r)|BBB(-w)|CCC(mr) の３つのロール/モードが設定されている場合、
	 * ユーザーが、AAA だけの場合は、-r ですが、AAA|BBB を持っている場合は、-w になります。
	 * さらに、BBB|CCC と持っている場合は、(-w:書き込み許可)と(mr:メニューから読取許可)の
	 * 権限により、mw:メニューからの書き込み許可が与えられます。
	 * モード指定がある場合は、AND演算になります。
	 * 例えば、AAA(-r)|BBB(-w)|CCC(mr) と BBB|CCC(-r) の場合、(-r)+(-w)+(mr)*(-r)=-w に
	 * なります。ロールは、OR ですが、モードは、同一ロールでのAND になります。
	 * 実際には、メニュー表示の可否は、ポップアップ系によく用いられますので、上記のような
	 * 許可が実際にあるかどうかは不明ですが、すべてのモードのOR条件での結合になります。
	 *
	 * @param	userRoles	ユーザーロール配列
	 * @param	isRoot	ルートロールフラグ
	 *
	 * @return  ビットモード配列 "--:000","-r:001","-w:010","mr:101","mw:110" に対応した数字(0,1,2,5,6)
	 */
//	public byte getAccessBitMode( final String[] userRoles,final boolean isRoot ) {
//		if( fullAccessFlag ) { return bitModes[0]; }
//
//		byte bitMode = 0;
//		for( int g=0; g<roleArray.length; g++ ) {
////			byte bit = ( oneModeFlag ) ? bitModes[0] : bitModes[g] ;
//			byte bit = bitModes[g] ;
//			if( isRoot ) {
//				bitMode |= bit;
//			}
//			else {
//				String role = roleArray[g];
//				for( int u=0; u<userRoles.length; u++ ) {
//					if( role.equalsIgnoreCase( userRoles[u] ) ) {
//						bitMode |= bit;
//						break;					// 一致すれば、内側のループを抜ける。
//					}
//				}
//			}
//			if( bitMode >= 6 ) { break; }	// "mw:110" は最大なので、以後判定不要。
//		}
//
//		return bitMode;
//	}

	/**
	 * 指定のユーザーロールに対する最終的なアクセス条件を取得します。
	 * アクセス条件は、複数あるユーザーロールの中で、最大のアクセス条件を算出します。
	 * 例えば、AAA(-r)|BBB(-w)|CCC(mr) の３つのロール/モードが設定されている場合、
	 * ユーザーが、AAA だけの場合は、-r ですが、AAA|BBB を持っている場合は、-w になります。
	 * さらに、BBB|CCC と持っている場合は、(-w:書き込み許可)と(mr:メニューから読取許可)の
	 * 権限により、mw:メニューからの書き込み許可が与えられます。
	 * モード指定がある場合は、AND演算になります。
	 * 例えば、AAA(-r)|BBB(-w)|CCC(mr) と BBB|CCC(-r) の場合、(-r)+(-w)+(mr)*(-r)=-w に
	 * なります。ロールは、OR ですが、モードは、同一ロールでのAND になります。
	 * 実際には、メニュー表示の可否は、ポップアップ系によく用いられますので、上記のような
	 * 許可が実際にあるかどうかは不明ですが、すべてのモードのOR条件での結合になります。
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 *
	 * @param	other	ロールモード
	 *
	 * @return アクセスビット
	 */
	public byte getAccessBitMode( final RoleMode other ) {
		if( fullAccessFlag || other.fullAccessFlag ) {
			return (byte)(bitModes[0] & other.bitModes[0]) ;
		}

		String[] othRoleArray = other.roleArray ;		// ロール配列
		byte[]	 othBitModes  = other.bitModes ;		// モードのビット

		byte bitMode = 0;
		for( int i=0; i<roleArray.length; i++ ) {
			for( int j=0; j<othRoleArray.length; j++ ) {
				if( roleArray[i].equals( othRoleArray[j] ) ) {
					bitMode |= (byte)(bitModes[i] & othBitModes[j]) ;
					if( bitMode == FULL_MODE ) { return FULL_MODE; }	// 途中打ち切り
				}
			}
		}

		return bitMode;
	}

	/**
	 * ビットロールのメニュー表示可否を返します。
	 *
	 * ロールが、m## , p## の場合に、true になります。
	 * これは、メニューに表示されるかどうかの判定に使われます。
	 *
	 * @param	bitMode	ビットロール
	 *
	 * @return メニュー表示できる(true)/出来ない(false)
	 */
	public static boolean isMenu( final byte bitMode ) {
		return ( (bitMode & M_MODE) > 0 );
	}

	/**
	 * ビットロールのプルダウン化を返します。
	 *
	 * ロールが、p## の場合に、true になります。
	 * ボタンメニュー時でも強制的に従来のプルダウンにします。
	 * 今後は廃止の方向です。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) メソッド追加
	 * @param	bitMode	ビットロール
	 *
	 * @return true:プルダウン化
	 */
	public static boolean isPulldown( final byte bitMode ) {
		// M_MODEとの比較でP_MODEの場合は強制プルダウン化
		return ( (bitMode & M_MODE) == P_MODE );
	}

	/**
	 * ビットロールの読込アクセス可否を返します。
	 *
	 * ロールが、#r# , #w# の場合に、true になります。
	 * 読み取り属性がある場合、画面が利用可能になります。
	 * #-# の場合は、画面へのアクセスができないため、
	 * メニューアクセス許可を与える、m-# の設定は無意味です。
	 * この場合は、メニューにも表示されません。
	 *
	 * @param	bitMode	ビットロール
	 *
	 * @return 読込アクセスできる(true)/出来ない(false)
	 */
	public static boolean isRead( final byte bitMode ) {
		return ( (bitMode & R_MODE) > 0 );
	}

	/**
	 * ビットロールの書込アクセス可否を返します。
	 *
	 * ロールが、#w# の場合に、true になります。
	 *
	 * これは、読込、書込みの判断ではなく、書込みができるか
	 * どうかの判断をしています。
	 * 画面にアクセスできるかどうかの判断は、isAccess を使用してください。
	 *
	 * @param	bitMode	ビットロール
	 *
	 * @return 書込アクセスできる(true)/出来ない(false)
	 */
	public static boolean isWrite( final byte bitMode ) {
		// 注意：W_MODE は、R_MODE と合成されているので、> 0 で判断できない。
		return ( (bitMode & W_MODE) == W_MODE );
	}

	/**
	 * ビットロールの画面アクセス可否を返します。
	 *
	 * これは、画面にアクセスできるかどうかの判断です。
	 * ロールが、#r# , #w# の場合に、true になります。
	 * 現時点では、isRead(byte) と計算方法は異なりますが、同じ結果になっています。
	 * これは、たまたま、現時点のロールの種類がそうなっているだけで、将来的に
	 * 同じかどうかは、保障されていません。
	 * よって、読み取り許可と、画面アクセス許可は、分けて考えてください。
	 *
	 * @param	bitMode	ビットロール
	 *
	 * @return 画面アクセスできる(true)/出来ない(false)
	 */
	public static boolean isAccess( final byte bitMode ) {
		return ( (bitMode & W_MODE) > 0 );
	}

	/**
	 * ビットロールのファイル出力可否を返します。
	 *
	 * ロールが、##d , ##f , ##o , ##e(= ##) の場合に、true になります。
	 * ##u の場合に、false になります。
	 * ファイル出力の可否を判定します。
	 * ## は、互換性の関係で、##e と同じです。
	 *
	 * @param	bitMode	ビットロール
	 *
	 * @return ファイル出力できる(true)/出来ない(false)
	 */
	public static boolean isDownload( final byte bitMode ) {
		return ( (bitMode & D_MODE) > 0 );
	}

	/**
	 * ビットロールのファイル入力可否を返します。
	 *
	 * ロールが、##u , ##f , ##o , ##e(= ##) の場合に、true になります。
	 * ##d の場合に、false になります。
	 * ファイル入力の可否を判定します。
	 * ## は、互換性の関係で、##e と同じです。
	 * ダウンロードはさせないが、アップロードを行う場合に使います。
	 * ここでのアップロードとは、基本的にデータの取り込みになりますので、
	 * アップロードのみという扱いは、あまりありません。
	 *
	 * @param	bitMode	ビットロール
	 *
	 * @return ファイル入力できる(true)/出来ない(false)
	 */
	public static boolean isUpload( final byte bitMode ) {
		return ( (bitMode & U_MODE) > 0 );
	}

	/**
	 * ビットロールの画面編集可否を返します。
	 *
	 * ロールが、##o , ##e(= ##) の場合に、true になります。
	 * このビットロールだけ特殊で、フラグが ON の場合に、機能制限がかかります。
	 *
	 * @og.rev 5.4.2.0 (2011/12/01) 新規作成
	 * @og.rev 5.5.5.2 (2012/08/10) oモード追加に伴い変更
	 *
	 * @param	bitMode	ビットロール
	 *
	 * @return アクセスできる(true)/出来ない(false)
	 */
	public static boolean isEdit( final byte bitMode ) {
		// return ( (bitMode & E_MODE) == E_MODE );
		return ( (bitMode & O_MODE) == O_MODE );
	}
	
	/**
	 * ビットロールの画面編集のフルコントロール可否を返します。
	 *
	 * ロールが、##e(= ##) の場合に、true になります。
	 * これは、フルコントロールの状態を指します。
	 *
	 * @og.rev 5.5.5.2 (2012/08/10) 新規作成
	 *
	 * @param	bitMode	ビットロール
	 *
	 * @return アクセスできる(true)/出来ない(false)
	 */
	public static boolean isFullEdit( final byte bitMode ) {
		// return ( (bitMode & E_MODE) == E_MODE );
		return ( (bitMode & E_MODE) == E_MODE );
	}


	/**
	 * この画面のmode アクセス条件をビット化します。
	 *
	 * RWMODE 情報は、各ロールに対して、３つの項目で表しています。
	 *   １："-" メニュー非表示   "m" メニュー表示  "p" メニュー表示(強制プルダウン表示)
	 *   ２："-" アクセス拒否     "r" 読取許可      "w" 読取、書込許可
	 *   ３："-" 未対応           "d" ファイル出力  "u" ファイル入力  "f" ファイル入出力
	 *       … このd,u,f では、【出力方法設定】タブは表示されません。
	 *       "o" 表示順編集のみ可  … この設定では、【表示項目設定】 タブで位置と表示順のみ変更できます。
	 *       "e" 画面編集可        … この設定で、編集機能がフルに使えます。
	 *       互換性の関係より、"" は、"e"  と同等とします。
	 *
	 * 区切り文字『|』で同じ順序で指定します。
	 * roles がないか、modes が一つか、roles と modes の個数が異なる場合
	 * 唯一のモード(共通モード)として、modes[0] を割り当てます。
	 * 互換性のため、"rw" と "r-" も処理できるようにします。
	 * この３項目を順次つないで、"--","-r","-w","mr","mw" などの設定を行います。
	 * モードが設定されている場合は、共通モードとして、すべてのロールに同じモードを
	 * 割り当てます。個別に割り当てる場合は、ROLES 情報の後ろに () 付きで追記します。
	 * 例えば、AAA|BBB(-r)|CCC とすれば、BBB ロールの場合は、読取専用になります。
	 * ロールをぶつける場合は、AND 演算になります。
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 *
	 * @param	roles	画面ロール配列
	 * @param	mode	画面モード
	 *
	 * @return  ビットモード配列 "--:000","-r:001","-w:010","mr:101","mw:110" に対応した数字(0,1,2,5,6)
	 */
//	private byte[] makeBitMode( final String[] modes ) {
	private byte[] makeBitMode( final String[] roles,final String mode ) {
		byte[] bits = null;

		byte commnMode = bitMode( mode );		// 共通MODEの設定

		int size = roles.length ;
		if( size == 0 ) {
			bits = new byte[] { commnMode };
		}
		else {
			bits = new byte[size] ;
			for( int i=0; i<size; i++ ) {
				String roleMode = null;
				String role = roles[i];
				int adrs = ( role != null ) ? role.indexOf( '(' ) : -1 ;
				if( adrs >= 0 ) {
					roleMode = role.substring( adrs+1,role.length() -1 );
					// 注意：roleArray に書き戻しています。(副作用処理)
					roles[i] = role.substring( 0,adrs );
				}
				bits[i] = (byte)(commnMode & bitMode( roleMode )) ;
			}
		}

		return bits ;
	}

	/**
	 * モード文字列に対するビット変換を行います。
	 *
	 * RWMODE 情報は、３つの項目で表しています。
	 *   １："-" メニュー非表示   "m" メニュー表示
	 *   ２："-" アクセス拒否     "r" 読取許可      "w" 読取、書込許可
	 *   ３："-" 未対応           "d" ファイル出力  "u" ファイル入力  "f" ファイル入出力
	 *       … このd,u,f では、【出力方法設定】タブは表示されません。
	 *       "o" 表示順編集のみ可  … この設定では、【表示項目設定】 タブで位置と表示順のみ変更できます。
	 *       "e" 画面編集可        … この設定で、編集機能がフルに使えます。
	 *       互換性の関係より、"" は、"e"  と同等とします。
	 *
	 * それぞれのキーワードに対して、ビット制御を行います。
	 * このメソッドには、ロールモード(ロール単位に追加するモード)の判定も
	 * 行う事が出来るように、引数が null の場合は、FULL_MODE を返します。
	 *
	 *	 全許可					( mwe )  FULL_MODE
	 *	 メニュー表示			( m-- )  M_MODE
	 *	 強制プルダウン表示		( p-- )  P_MODE
	 *	 読取許可				( -r- )  R_MODE
	 *	 書込許可				( -w- )  W_MODE
	 *	 ファイル出力			( --d )  D_MODE
	 *	 ファイル入力			( --u )  U_MODE
	 *	 ファイル入出力			( --f )  F_MODE
	 *	 表示順編集のみ可		( --o )  O_MODE
	 *	 画面編集可				( --e )  E_MODE
	 *
	 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
	 * @og.rev 4.3.3.0 (2008/10/01) pモード対応(mと同じ扱い)
	 * @og.rev 5.4.2.0 (2011/12/01) eモード対応
	 * @og.rev 5.5.5.2 (2012/08/10) oモード対応
	 *
	 * @param	mode	モード文字列
	 *
	 * @return	ビットモード
	 */
	private byte bitMode( final String mode ) {
		byte bit = 0x00;

		if( mode == null ) {
			bit = FULL_MODE;
		}
		else {
			int len = mode.length();
			for( int i=0; i<len; i++ ) {
				switch( mode.charAt(i) ) {
					case 'm' : bit |= M_MODE; break;
					case 'p' : bit |= P_MODE; break; // 4.3.3.0 (2008/10/01) Pモード追加
					case 'r' : bit |= R_MODE; break;
					case 'w' : bit |= W_MODE; break;
					case 'd' : bit |= D_MODE; break;
					case 'u' : bit |= U_MODE; break;
					case 'f' : bit |= F_MODE; break;
					case 'e' : bit |= E_MODE; break; // 5.4.2.0 (2011/12/01) Eモード追加
					case 'o' : bit |= O_MODE; break; // 5.5.5.2 (2011/12/10) Oモード追加
					case '-' : break;
					default  :
						String errMsg = "RWMODE に不正な記号が使用されています。"
									+ " mrwdufe- のみ、使用可能です。"
									+ " roles [" + roles + "]  mode [" + mode + "]"
									+ HybsSystem.CR;
						throw new HybsSystemException( errMsg );
				}
			}
//			if( len < 3 ) { bit |= F_MODE; }	// 互換性暫定対応
			if( len < 3 ) { bit |= E_MODE; }	// 互換性暫定対応 // 5.4.2.0 (2011/12/01)

			// RWアクセスできない場合は、ファイルアクセスも禁止します。
			if( ( bit & W_MODE ) == 0 ) { bit = 0x00; }
		}

		return bit ;
	}

	/**
	 * オブジェクトの識別子として，詳細なユーザー情報を返します。
	 *
	 * @return  詳細な画面情報
	 */
	@Override
	public String toString() {
		StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
		rtn.append( "roles  : " ).append( roles  ).append( HybsSystem.CR );
		rtn.append( "rwmode : " ).append( rwmode ).append( HybsSystem.CR );
		return rtn.toString();
	}
}
