package org.itscool.commons.dao;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import org.itscool.commons.bean.BeanFactory;
import org.itscool.commons.logging.AbstractLog;

/**
 * 永続化対象クラスの情報を保持するHashMapクラスです
 *
 * @author KANO
 * @since jdk1.4.1
 * @version 1.00A 2005/10/10
 */
public class EntityInfoMapping{
    public static final String DB_HSQL = "hsql";
    public static final String DB_MYSQL = "mysql";
    public static final String DB_PGSQL = "pgsql";
    public static final String DB_ORACLE = "oracle";
    
    private HashMap daoInfoMappings = new HashMap();
    private String dbType = DB_HSQL;
    
    /** 唯一のDaoInfoMappingインスタンス */
    private static EntityInfoMapping instance;
    protected static AbstractLog log;
    
    /**
     * 唯一のDaoInfoMappingインスタンスを取得します
     * @return DaoInfoMappingインスタンス
     */
    public static synchronized EntityInfoMapping getInstance(){
        if( instance == null ){
            instance = new EntityInfoMapping();
            BeanFactory factory = BeanFactory.getInstance();
            try{
                log = (AbstractLog)factory.getInstance("Log");
                if(!log.isInit()){
                    log = (AbstractLog)factory.createInstance("Log");
                }
            }catch(Exception ioe){
            }
        }
        return instance;
    }    

    public void put(Object key, Object data){
        getDaoInfoMappings().put(key, data);
    }
    
    public Set keySet(){
        return getDaoInfoMappings().keySet();
    }
    
    public Object get(Object key){
        return getDaoInfoMappings().get(key);
    }
    
    public void clear(){
        getDaoInfoMappings().clear();
    }
    
    /**
     * 永続化対象クラス情報を取得します
     * @param clazzName 永続化対象クラス名
     * @return 永続化対象クラス情報
     */
    public EntityInfo getDaoInfo(String clazzName){
        EntityInfo daoInfo = (EntityInfo)this.get(clazzName);
        return daoInfo;
    }
    
    /**
     * 永続化対象クラスのO/Rマッピング情報を取得します
     * @param clazzName 永続化対象クラス名
     * @return 永続化対象クラスのO/Rマッピング情報
     */
    public RecordMap getGRecordMap(String clazzName){
        EntityInfo daoInfo = getDaoInfo(clazzName);
        if( daoInfo == null){
            RecordMap gRecordMap = RecordMapFactory.createRecordMap(clazzName);
            HashMap fkRecordMaps = RecordMapFkFactory.createFkRecordMaps(clazzName);
            HashMap oneToManyRecordMaps = RecordMapOneToManyFactory.createOneToManyRecordMaps(clazzName);
            daoInfo = new EntityInfo();
            daoInfo.setGRecordMap(gRecordMap);
            daoInfo.setFkRecordMaps(fkRecordMaps);
            daoInfo.setOneToManyRecordMaps(oneToManyRecordMaps);
            
            this.daoInfoMappings.put( clazzName, daoInfo );
            return gRecordMap;
        }
        RecordMap recordMap = daoInfo.getGRecordMap();
        if( recordMap == null ){
            recordMap = RecordMapFactory.createRecordMap(clazzName);
        }
        return recordMap;
    }
    
    /**
     * 永続化対象クラスの外部参照となるO/Rマッピング情報のリストを取得します
     * @param clazzName 永続化対象クラス名
     * @return 永続化対象クラスの外部参照となるO/Rマッピング情報
     */
    public HashMap getFkRecordMaps(String clazzName){
        EntityInfo daoInfo = getDaoInfo(clazzName);
        if( daoInfo == null){
            RecordMap gRecordMap = RecordMapFactory.createRecordMap(clazzName);
            HashMap fkRecordMaps = RecordMapFkFactory.createFkRecordMaps(clazzName);
            HashMap oneToManyRecordMaps = RecordMapOneToManyFactory.createOneToManyRecordMaps(clazzName);
            daoInfo = new EntityInfo();
            daoInfo.setGRecordMap(gRecordMap);
            daoInfo.setFkRecordMaps(fkRecordMaps);
            daoInfo.setOneToManyRecordMaps(oneToManyRecordMaps);
            
            this.daoInfoMappings.put( clazzName, daoInfo );
            return fkRecordMaps;
        }
        HashMap fkMap = daoInfo.getFkRecordMaps();
        if( fkMap == null){
            fkMap = RecordMapFkFactory.createFkRecordMaps(clazzName);
        }
        return fkMap;
    }
    
    public HashMap getOneToManyRecordMaps(String clazzName){
        EntityInfo daoInfo = getDaoInfo(clazzName);
        if( daoInfo == null){
            RecordMap gRecordMap = RecordMapFactory.createRecordMap(clazzName);
            HashMap fkRecordMaps = RecordMapFkFactory.createFkRecordMaps(clazzName);
            HashMap oneToManyRecordMaps = RecordMapOneToManyFactory.createOneToManyRecordMaps(clazzName);
            daoInfo = new EntityInfo();
            daoInfo.setGRecordMap(gRecordMap);
            daoInfo.setFkRecordMaps(fkRecordMaps);
            daoInfo.setOneToManyRecordMaps(oneToManyRecordMaps);
            
            this.daoInfoMappings.put( clazzName, daoInfo );
            return oneToManyRecordMaps;
        }
        HashMap oneToManyMap = daoInfo.getOneToManyRecordMaps();
        if( oneToManyMap == null){
            oneToManyMap = RecordMapOneToManyFactory.createOneToManyRecordMaps(clazzName);
        }
        return oneToManyMap;
    }
    
    /**
     * 永続化対象クラスのO/Rマッピング情報を取得します
     * @param clazz 永続化対象クラス
     * @return 永続化対象クラスのO/Rマッピング情報
     */
    public RecordMap getGRecordMap(Class clazz){
        return getGRecordMap(clazz.getName());
    }
    
    /**
     * 永続化対象クラスの外部参照となるO/Rマッピング情報のリストを取得します
     * @param clazz 永続化対象クラス
     * @return 永続化対象クラスの外部参照となるO/Rマッピング情報
     */
    public HashMap getFkRecordMaps(Class clazz){
        return getFkRecordMaps(clazz.getName());
    }
    
    public HashMap getOneToManyRecordMaps(Class clazz){
        return getOneToManyRecordMaps(clazz.getName());
    }
    
    public HashMap getDaoInfoMappings() {
        return daoInfoMappings;
    }
    
    /**
     * 永続化対象クラスの外部参照となるO/Rマッピング情報を取得します
     * @param clazzName 永続化対象クラス名
     * @param fkPropertyName 永続化対象クラスが参照するプロパティ名
     * @return 永続化対象クラスの外部参照となるO/Rマッピング情報
     */
    public RecordMap getFkRecordMap(String clazzName, String fkPropertyName){
        HashMap fkMap = this.getFkRecordMaps(clazzName);
        RecordMap fkRecordMap = (RecordMap)fkMap.get(fkPropertyName);
        return fkRecordMap;
    }
    
    /**
     * 永続化対象クラスの外部参照となるO/Rマッピング情報を取得します
     * @param clazz 永続化対象クラス
     * @param fkPropertyName 永続化対象クラスが参照するプロパティ名
     * @return 永続化対象クラスの外部参照となるO/Rマッピング情報
     */
    public RecordMap getFkRecordMap(Class clazz, String fkPropertyName){
        return getFkRecordMap(clazz.getName(), fkPropertyName);
    }
    
    public RecordMap getOneToManyRecordMap(String clazzName, String oneToManyPropertyName){
        HashMap oneToManyMap = this.getOneToManyRecordMaps(clazzName);
        RecordMap oneToManyRecordMap = (RecordMap)oneToManyMap.get(oneToManyPropertyName);
        return oneToManyRecordMap;
    }
    
    public RecordMap getOneToManyRecordMap(Class clazz, String oneToManyPropertyName){
        return getOneToManyRecordMap(clazz.getName(), oneToManyPropertyName);
    }
    
    
    /**
     * 引数にセットされたクラス情報の一覧から、RecordMapインスタンスを
     * 作成します。<br>
     * @param daoInfoMappings 永続化対象クラスの一覧（EntityInfoオブジェクト)
     */
    public void setDaoInfoMappings(HashMap daoInfoMappings) {
        String entity = "";
        try{
            Set keySet = daoInfoMappings.keySet();
            Iterator it = keySet.iterator();
            while(it.hasNext()){
                entity = (String)it.next();
                RecordMap gRecordMap = RecordMapFactory.createRecordMap(entity);
                HashMap fkRecordMaps = RecordMapFkFactory.createFkRecordMaps(entity);
                HashMap oneToManyRecordMaps = RecordMapOneToManyFactory.createOneToManyRecordMaps(entity);
                EntityInfo daoInfo = new EntityInfo();
                daoInfo.setGRecordMap(gRecordMap);
                daoInfo.setFkRecordMaps(fkRecordMaps);
                daoInfo.setOneToManyRecordMaps(oneToManyRecordMaps);
                
                this.daoInfoMappings.put( entity, daoInfo );
            }
        }catch(Exception e){
            log.error(e.getMessage() + " class="+entity );
            log.error(e);
            throw new DaoRuntimeException(e.getMessage());
        }
    }

    public String getDbType() {
        return dbType;
    }

    public void setDbType(String dbType) {
        this.dbType = dbType;
    }
}
