package org.itscool.commons.dao;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import org.itscool.commons.bean.BeanUtil;

/**
 * 外部参照用RecordsMp作成クラス<P>
 *
 * JavaBeansのアノテーションを読み取り、テーブルマッピングクラス（RecordMap)
 * を生成するユーティリティクラスです<P>
 *
 * JavaBeansには以下のクラス情報が含まれている必要があります<P>
 *
 * public static final FK_TABLE_プロパティ名で定義されたテーブル名
 * （省略された場合は、クラス名が外部参照先のテーブル名となります）とプロパティ名
 * に対応するオブジェクトの宣言<BR>
 *
 * public static final FK_COLUM_プロパティ名_外部参照キー名で定義されたフィールド名
 * （省略された場合は,テーブルにマッピングされません）とFK_TABLE_プロパティ名で
 * 指定した外部参照テーブルに対応するプロパティの宣言（このプロパティはForgine Keyに
 * 該当します）<BR>
 * メンバ名は、JavaBeansで定義されているプロパティ名と同じ名前を使用する必要が
 * あります。
 * @author KANO
 * @since jdk1.4.1
 * @version 1.00A 2004/11/1
 */
public class RecordMapFkFactory extends RecordMapFactory{
    /**
     * COLUMマッピング定義宣言
     */
    public static final String FK_COLUM = "FK_COLUM_";
    
    /**
     * TABLEマッピング定義宣言
     */
    public static final String FK_TABLE = "FK_TABLE_";
    
    /**
     * JavaBeansのクラス情報を元にRecordMapインスタンスを生成します
     * @param className 永続化対象となるJavaBeansのクラス情報
     * @return RecordMapインスタンスを取得します
     */
    public static HashMap createFkRecordMaps( String className){
        try{
            Class entity = Class.forName(className);
            return createFkRecordMaps( entity );
        }catch(ClassNotFoundException e){
            e.printStackTrace();
            return null;
        }
    }
    
    public static HashMap createFkRecordMaps( Class entity ){
        //Object obj = BeanUtil.createInstance(entity.getName());
        HashMap fkRecordMaps = new HashMap();
        
        fkRecordMaps = createFkRecordMaps( entity, fkRecordMaps );
        return fkRecordMaps;
    }
    
    public static HashMap createFkRecordMaps( Class entity, HashMap fkRecordMaps ){
        //親クラスのメンバから走査
        Class superClazz = entity.getSuperclass();
        if( superClazz != null ){
            fkRecordMaps = createFkRecordMaps( superClazz, fkRecordMaps );
        }
        String clazzName = entity.getName();
        //-------------------------------------------------------
        //RecordMapが保有する各FieldMapインスタンスに対して
        //対応するカラム情報をセットしていきます。
        //カラムをセットする変数は"COLUM_プロパティ名"である必要があります
        //-------------------------------------------------------
        Field[] fields = entity.getDeclaredFields();
        for( int i=0; i<fields.length; i++){
            //JavaBeansに定義されたフィールド情報を取得します
            Field field = fields[i];
            //フィールドのModifier情報を取得します
            int modifier = field.getModifiers();
            try{
                String staticName = field.getName();
                int index = staticName.indexOf(FK_TABLE);
                if( modifier == (Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL)
                && index == 0){
                    //String tableName = (String)field.get(obj);
                    String propertyName = staticName.substring((FK_TABLE).length(), staticName.length());
                    String propertyType = getPropertyType(entity, propertyName);
                    
                    RecordMap recordMap = RecordMapFactory.createRecordMap(propertyType);
                    setForignKey( recordMap, entity, FK_TABLE+propertyName, FK_COLUM+propertyName+"_" );
                    
//            	    RecordMap recordMap = create( entity, FK_TABLE+propertyName, FK_COLUM+propertyName+"_" );
                    if( propertyType != null ){
                        recordMap.setClassName(propertyType);
                        fkRecordMaps.put(propertyName, recordMap);
//	            	    fkRecordMaps.put(tableName, recordMap);
//	            	    System.out.println("property:" + propertyName + ", fk_table:" + tableName );
//	            	    System.out.println(recordMap.toString());
                    }
                }
                
            }catch(Exception e){}
            
        }
        return fkRecordMaps;
    }
    private static void setForignKey(RecordMap recordMap, Class entity, String tableHeaderName, String columHeaderName){
        Object obj = BeanUtil.createInstance(entity.getName());
        String tableName = getTableName(entity, obj, tableHeaderName);
        //RecordMap recordMap = new RecordMap(entity.getName(), tableName);
        recordMap.setClassName(entity.getName());
        recordMap.setTableName(tableName);
        
        //-------------------------------------------------------
        //RecordMapが保有する各FieldMapインスタンスに対して
        //対応するカラム情報をセットしていきます。
        //カラムをセットする変数は"COLUM_プロパティ名"である必要があります
        //-------------------------------------------------------
        Field[] fields = entity.getDeclaredFields();
        for( int i=0; i<fields.length; i++){
            //JavaBeansに定義されたフィールド情報を取得します
            Field field = fields[i];
            //フィールドのModifier情報を取得します
            int modifier = field.getModifiers();
            //FieldMapインスタンスを作成します
            try{
                String staticName = field.getName();
                int index = staticName.indexOf(columHeaderName);
                if( modifier == (Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL)
                && index == 0){
                    //FieldMap fieldMap = new FieldMap();
                    String fieldName = (String)field.get(obj);
                    String propertyName = staticName.substring((columHeaderName).length(), staticName.length());
                    //fieldMap.setColumName(fieldName);
                    //fieldMap.setPropertyName(propertyName);
                    //fieldMap.setRecordMap(recordMap);
                    //recordMap.addField(fieldMap);
                    FieldMap fieldMap = recordMap.getFieldByFieldName(fieldName);
                    fieldMap.setFkPropertyName(propertyName);
                    fieldMap.setForignKey(true);
                    
                }
                
            }catch(IllegalAccessException e){
                String err = "[" + obj.getClass().getName() + ":" + tableName + "]" +
                    "setForignKey() failed(" + RecordMapFkFactory.class.getName() + ") (" +
                    e.getMessage() + ")";
                throw new DaoRuntimeException(err);
            }
            
        }
        //-----------------------------------------------------------
        //"COLUM_メンバ名"に対応するプロパティ名をJavaBeansクラス情報から
        //取得します
        //-----------------------------------------------------------
        HashMap records = recordMap.getFields();
        Set keySet = records.keySet();
        Iterator iterator = keySet.iterator();
        while( iterator.hasNext() ){
            try{
                Object key = iterator.next();
                FieldMap fieldMap = (FieldMap)records.get(key);
                String propertyName = fieldMap.getPropertyName();
                //Field field = entity.getDeclaredField(propertyName);
                Field field = BeanUtil.getField(entity, propertyName);
                if(field == null){
                    continue;
                }
                String type = field.getType().getName();
                
                fieldMap.setType(type);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
//        return recordMap;
    }
    
//    private static RecordMap create(Class entity, String tableHeaderName, String columHeaderName){
//        Object obj = BeanUtil.createInstance(entity.getName());
//        String tableName = getTableName(entity, obj, tableHeaderName);
//        RecordMap recordMap = new RecordMap(entity.getName(), tableName);
//
//        //-------------------------------------------------------
//        //RecordMapが保有する各FieldMapインスタンスに対して
//        //対応するカラム情報をセットしていきます。
//        //カラムをセットする変数は"COLUM_プロパティ名"である必要があります
//        //-------------------------------------------------------
//        Field[] fields = entity.getDeclaredFields();
//        for( int i=0; i<fields.length; i++){
//            //JavaBeansに定義されたフィールド情報を取得します
//            Field field = fields[i];
//            //フィールドのModifier情報を取得します
//            int modifier = field.getModifiers();
//            //FieldMapインスタンスを作成します
//            try{
//                String staticName = field.getName();
//                int index = staticName.indexOf(columHeaderName);
//            	if( modifier == (Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL)
//            	        && index == 0){
//            	    FieldMap fieldMap = new FieldMap();
//            	    String fieldName = (String)field.get(obj);
//            	    String propertyName = staticName.substring((columHeaderName).length(), staticName.length());
//	                fieldMap.setColumName(fieldName);
//	                fieldMap.setPropertyName(propertyName);
//	                fieldMap.setRecordMap(recordMap);
//	                recordMap.addField(fieldMap);
//	            }
//
//            }catch(Exception e){}
//
//        }
//        //-----------------------------------------------------------
//        //"COLUM_メンバ名"に対応するプロパティ名をJavaBeansクラス情報から
//        //取得します
//        //-----------------------------------------------------------
//        HashMap records = recordMap.getFields();
//        Set keySet = records.keySet();
//        Iterator iterator = keySet.iterator();
//        while( iterator.hasNext() ){
//            try{
//	            Object key = iterator.next();
//	            FieldMap fieldMap = (FieldMap)records.get(key);
//	            //Field field = entity.getDeclaredField(fieldMap.getPropertyName());
//	            Field field = BeanUtil.getField(entity, fieldMap.getPropertyName());
//	            String type = field.getType().getName();
//
//	            fieldMap.setType(type);
//            }catch(Exception e){
//                e.printStackTrace();
//            }
//        }
//        return recordMap;
//    }
    /**
     * JavaBeansクラス定義からプロパティ名で指定したプロパティの型を取得します
     * @param entity JavaBeansクラス定義情報
     * @param propertyName プロパティ名
     * @return TABEL名を取得します
     */
    protected static String getPropertyType(Class entity, String propertyName){
        String propertyType = null;
        try{
            //Field field = entity.getDeclaredField(propertyName);
            Field field = BeanUtil.getField(entity, propertyName);
            if( field != null ){
                propertyType = field.getType().getName();
            }
        }catch(Exception e){}
        return propertyType;
    }
}

