package org.itscool.commons.dao;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.itscool.commons.bean.BeanUtil;
import org.itscool.commons.util.DateFormatUtil;

/**
 * FieldMapクラスはJavaBeanのプロパティとテーブルのフィールド情報をマッピングする
 * クラスです
 *
 * @author KANO
 * @since jdk1.4.1
 * @version 1.00A 2004/11/1
 */
public class FieldMap {
    public static final String FLD_LOCK_VERSION="LOCK_VERSION";
    public static final String FLD_UPDATE_DT="UPDATE_DT";
    public static final String FLD_DELETE_FG="DELETE_FG";
    public static final String FLD_DELETE_DT="DELETE_DT";
    
    public static final String NULL_STRING = "null";
    /** プライマリキー区分 */
    private boolean primaryKey = false;
    /** 外部参照キー区分 */
    private boolean forignKey = false;
    /** JavaBeansのプロパティ名 */
    private String propertyName;
    /** 外部参照キー名 */
    private String fkPropertyName;
    //** JavaBeansのプロパティの型 */
    private String type;
    /** テーブルのフィールド名 */
    private String columName;
    /** フィールドのサイズ */
    //private int size;
    /** このフィールドを構成するRecordMapインスタンスへの参照 */
    private RecordMap lnkRecordMap;
    
    /**
     * デフォルトコンストラクタの定義
     */
    public FieldMap(){
        
    }
    
    /**
     * FieldMapインスタンスを作成します
     * @param propertyName Beanのプロパティ名
     * @param name         テーブルのフィールド名
     * @param type         フィールドのタイプ
     * @param lnkRecordMap 外部参照レコード
     */
    public FieldMap(String propertyName, String name, String type, RecordMap lnkRecordMap){
        this.lnkRecordMap = lnkRecordMap;
        this.propertyName = propertyName;
        this.columName = name;
        this.type = type;
    }
    
    /**
     * プロパティタイプがプリミティブ型の場合<br>
     * [ ${Field.getType()} = ${Field.getValue()} ]を作成します<p>
     *
     * プロパティタイプがjava.lang.String型の場合<br>
     * [ ${Field.getType()} = '${Field.getValue()}' ]を作成します<p>
     *
     * プロパティタイプがjava.util.Date型の場合<br>
     * [ ${Field.getType()} = '${Field.getValue()}' ]を作成します<p>
     *
     * @param obj データ
     * @return　[ Field.getType() = Field.getValue() ]を返却します
     */
    public String cnvSqlValue(Object obj){
        String value = "";
        try{
            if(obj==null){
                return "null";
            }else{
                 value = obj.toString();
            }
            StringBuffer sb = new StringBuffer();
            if( getType().equals( String.class.getName() ) && value == NULL_STRING){
                sb.append(value);
            }else if( getType().equals( String.class.getName() )){
                sb.append("'");
                sb.append(convertDBText(value));
                sb.append("'");
            }else if( getType().equals( Date.class.getName()) && obj instanceof Date){
                try{
                    if(obj != null && !obj.toString().equals("null")){
                        Date date = (Date)obj;
                        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        value = sdf1.format(date);
                    }else{
                        return "null";
                    }
                    
                    sb.append("'");
                    sb.append(value);
                    sb.append("'");
                 }catch(Exception e){
                    throw new DaoRuntimeException(e.getMessage() + " value = " + obj);
                }
            }else if( getType().equals( Date.class.getName()) && obj instanceof String){
                try{
                    if(obj != null && !obj.toString().equals("null")){
                        Date date = DateFormatUtil.parse(obj.toString());
                        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        value = sdf1.format(date);
                    }else{
                        return "null";
                    }
                    
                    sb.append("'");
                    sb.append(value);
                    sb.append("'");
                }catch(Exception e){
                    throw new DaoRuntimeException(e.getMessage() + " value = " + obj);
                }
            }else if( getType().equals( boolean.class.getName()) || getType().equals("boolean")){
                boolean b = Boolean.valueOf(value).booleanValue();
                if(b){
                    sb.append(1);
                }else{
                    sb.append(0);
                }
            }else if( getType().equals( "int") ){
                try{
                    Integer.parseInt(value);
                }catch(NumberFormatException e){
                    value = "-1";
                }
                sb.append(value);
            }else{
                sb.append(value);
            }
            return sb.toString();
        }catch(Exception e){
            throw new DaoRuntimeException(e.getMessage() + ", type = " + type +" colum = " + columName + " value = " + obj);
        }
    }
    /**
     * プロパティをセットします
     * @param obj 永続化対象オブジェクト
     * @param value プロパティ値
     */
    public void setPropertyValue(Object obj, Object value){
        
        if( this.getType().equals(boolean.class.getName())){
            boolean bool = Boolean.parseBoolean((String)value);
            value = new Boolean(bool);
        }else if( this.getType().equals(Date.class.getName()) && value instanceof String){
            if( value != null ){
                SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try{
                    String str = value.toString();
                    Date date = sdf1.parse(str);
                    value = date;
                }catch(Exception e){
                    throw new DaoRuntimeException(e.getMessage());
                }
            }
        }
        BeanUtil.setProperty(obj,getPropertyName(),value);
    }
    
    /**
     *ＤＢのテキスト型文字変換関数(シングルクォート文字対応)
     *@param strData 変換対象文字列
     *@return 変換後の文字列を返す<BR>
     *        変換対象のコードが含まれていない場合は、<BR>
     *        引数で指定された文字列を返す<BR>
     *<table class=p border=1 cellspacing=0 cellpadding=2>
     *<tr bgcolor="#CCCCFF"><th>変換前の文字列</th><th>変更後の文字列</th><th>説明</th></tr>
     *<tr><th><b>A'B'c</b></th><th>A''B''c</th><td>｢'｣(シングルクォート)を｢''｣に変換する。</td></tr>
     *</table>
     *<BR>
     *@since 1.09
     */
    public static String convertDBText(String strData){
        int iLength = 0;
        int iCnt = 0;
        char chrC;
        String strC = "";
        String new_strData = "";
        
        try{
            //文字列の長さを取得する
            iLength = strData.length();
            
            //文字を取得する
            for(iCnt=0; iCnt<iLength; iCnt++){
                chrC = strData.charAt(iCnt);
                
                //「'」の判定（「'」の場合「''」に置き換える）
                if( chrC == 0x0027 ){
                    strC = "''";
                    new_strData = new_strData + strC ;
                } else if( chrC == 0x005C){
                    strC = String.valueOf(chrC)+String.valueOf(chrC);
                    new_strData = new_strData + strC ;
                } else{
                    new_strData = new_strData + chrC ;
                }
            }
            //文字列を返す
            strData = new_strData;
            return strData;
        }
        //例外処理
        catch(Exception e){
            return strData;
        }
    }
    
    /**
     * テーブル名、列名から”テーブル名.列名”を作成します
     * @param tblName テーブル名
     * @param columName 列名
     * @return ”テーブル名.列名”を返します
     */
    public static final String convColumWithTableName(String tblName, String columName){
        StringBuffer sb = new StringBuffer();
        sb.append( tblName );
        sb.append(".").append( columName );
        return sb.toString().toUpperCase();
        //return columName;
    }
    
    /**
     * テーブル名、列名から”テーブル名_列名”を作成します
     * @param tblName テーブル名
     * @param columName 列名
     * @return ”テーブル名_列名”を返します
     */
    public static final String convColumAsName(String tblName, String columName){
        StringBuffer sb = new StringBuffer();
        sb.append(tblName).append("_").append(columName);
        return sb.toString().toUpperCase();
    }
    
    /**
     * @return JavaBeansのプロパティ名
     */
    public String getType(){
        
        return type;
    }
    
    /**
     * フィールド名を取得します
     * @return name フィールド名
     */
    public String getColumName() {
        return columName;
    }
    
    /**
     * フィールド名をセットします
     * @param columName フィールド名
     */
    public void setColumnName(String columName){
        this.columName = columName;
    }
    
    /**
     * テーブル名.フィールド名を取得します
     * @return テーブル名.フィールド名
     */
    public String getColumWithTableName(){
        StringBuffer sb = new StringBuffer();
        sb.append( lnkRecordMap.getTableName());
        sb.append(".").append( columName );
        return sb.toString().toUpperCase();
        //return columName;
    }
    
    /**
     * AS句を作成します
     * @return フィールドの別名をテーブル名_フィールド名で返します
     */
    public String getColumAsName(){
        StringBuffer sb = new StringBuffer();
        sb.append(lnkRecordMap.getTableName()).append("_").append(columName);
        return sb.toString().toUpperCase();
    }
    
    /**
     * このFieldMapインスタンスが属しているRecordMapインスタンスのポインタを返します
     * @return FieldMapインスタンスが属しているRecordMapインスタンスを返します
     */
    public RecordMap getRecordMap() {
        return lnkRecordMap;
    }
    
    /**
     * このFieldMapインスタンスが属するRecordMapインスタンスをセットします
     * @param lnkRecordMap このFieldMapインスタンスが属しているRecordMapインスタンス
     */
    public void setRecordMap(RecordMap lnkRecordMap){
        this.lnkRecordMap = lnkRecordMap;
    }
    
    /**
     * Beanのプロパティ名を取得します
     * @return propertyName Beanのプロパティ名
     */
    public String getPropertyName() {
        return propertyName;
    }
    
    /**
     * Beanのプロパティ名をセットします
     * @param propertyName Beanのプロパティ名
     */
    public void setPropertyName(String propertyName ){
        this.propertyName = propertyName;
    }
    
    /**
     * @return lnkRecordMap を戻します。
     */
    public RecordMap getLnkRecordMap() {
        return lnkRecordMap;
    }
    /**
     * @param lnkRecordMap lnkRecordMap を設定。
     */
    public void setLnkRecordMap(RecordMap lnkRecordMap) {
        this.lnkRecordMap = lnkRecordMap;
    }
    /**
     * @param columName columName を設定。
     */
    public void setColumName(String columName) {
        this.columName = columName;
    }
    /**
     * @param type type を設定。
     */
    public void setType(String type) {
        this.type = type;
    }
//	/**
//	 * @return size フィールドサイズを取得します
//	 */
//	public int getSize() {
//		return size;
//	}
//	/**
//	 * @param size size を設定します。
//	 */
//	public void setSize(int size) {
//		this.size = size;
//	}
//
    
    /**
     * @return primaryKey を戻します。
     */
    public boolean isPrimaryKey() {
        return primaryKey;
    }
    
    /**
     * @param primaryKey primaryKey を設定。
     */
    public void setPrimaryKey(boolean primaryKey) {
        this.primaryKey = primaryKey;
    }
    
    /**
     * @return forignKey を戻します。
     */
    public boolean isForignKey() {
        return forignKey;
    }
    
    /**
     * @param forignKey forignKey を設定。
     */
    public void setForignKey(boolean forignKey) {
        this.forignKey = forignKey;
    }
    
    /**
     * @return fkPropertyName を戻します。
     */
    public String getFkPropertyName() {
        return fkPropertyName;
    }
    
    /**
     * @param fkPropertyName をセットします
     */
    public void setFkPropertyName(String fkPropertyName) {
        this.fkPropertyName = fkPropertyName;
    }
}
