// record実装.
//

////////////////////////////////////////////////////////////////////////////////
// データベースタイプ.
////////////////////////////////////////////////////////////////////////////////
SqlType = {
    typeOf: function( type ) {
        if( isNumeric( type ) == false ) {
            return "unknown" ;
        }
        switch( type ) {
            case java.sql.Types.BOOLEAN :// Boolean.
            case java.sql.Types.BIT :
            case java.sql.Types.TINYINT :
            case java.sql.Types.CHAR :
                return "boolean" ;
            case java.sql.Types.SMALLINT :// Integer.
            case java.sql.Types.INTEGER :
                return "integer" ;
            case java.sql.Types.BIGINT :// Long.
                return "long" ;
            case java.sql.Types.DOUBLE :// Double.
                return "double" ;
            case java.sql.Types.FLOAT :// Float.
            case java.sql.Types.REAL :// Float.
                return "float" ;
            case java.sql.Types.VARCHAR :// String.
            case java.sql.Types.LONGVARCHAR :
            case java.sql.Types.DATALINK :// URL.
                return "string" ;
            case java.sql.Types.DATE :// java.sql.Date.
                return "date" ;
            case java.sql.Types.TIME :// java.sql.Time.
                return "time" ;
            case java.sql.Types.TIMESTAMP :// java.sql.Timestamp.
                return "timestamp" ;
            case java.sql.Types.BINARY :// byte[].
            case java.sql.Types.VARBINARY :
            case java.sql.Types.LONGVARBINARY :
            case java.sql.Types.BLOB :
                return "binary" ;
        }
        return "unknown" ;
    },
    toType: function( str ) {
        if( useString( str ) == false ) {
            return -1 ;
        }
        str = trim( str ).toLowerCase() ;
        if( str = "boolean" ) {
            return java.sql.Types.BOOLEAN ;
        }
        if( str = "integer" ) {
            return java.sql.Types.INTEGER ;
        }
        if( str = "long" ) {
            return java.sql.Types.BIGINT ;
        }
        if( str = "double" ) {
            return java.sql.Types.DOUBLE ;
        }
        if( str = "float" ) {
            return java.sql.Types.FLOAT ;
        }
        if( str = "string" ) {
            return java.sql.Types.VARCHAR ;
        }
        if( str = "date" ) {
            return java.sql.Types.DATE ;
        }
        if( str = "time" ) {
            return java.sql.Types.TIME ;
        }
        if( str = "timestamp" ) {
            return java.sql.Types.TIMESTAMP ;
        }
        if( str = "binary" ) {
            return java.sql.Types.BINARY ;
        }
        return -1 ;
    }
} ;

////////////////////////////////////////////////////////////////////////////////
// Record系.
////////////////////////////////////////////////////////////////////////////////

// モデル情報を取得.
script_model = function() {
    return _$script$base_model ;
} ;

// BaseModel生成用.
create_base_model = function() {
    // dummy-baseModelの場合は、生成されたことにする.
    if( script_model().isType() == false ) {
        return true ;
    }
    if( isNull( _$$maachang_comet_manager.get( "DBMS_POOL" ) ) ) {
        return false ;
    }
    if( script_model().isCreate() == false ) {
        script_model().create(
            (__$type$script != "console" ),
            _$script$context,
            _$$maachang_comet_manager.get( "DBMS_POOL" ).getRecord() ) ;
    }
    return true ;
} ;

// データベースコミット.
commit = function() {
    if( script_model().isCreate() == true ) {
        script_model().commit() ;
    }
} ;

// データベースロールバック.
rollback = function() {
    if( script_model().isCreate() == true ) {
        script_model().rollback() ;
    }
} ;

// SQL文を実行.
// ※利用不可API.
// 理由として
// ・レプリケーション対応した場合の問題.
// ・あまり利用することがない.
// 等の理由から、このAPIは利用できないようにする.
//sql = function( sql ) {
//    if( create_base_model() == false ) {
//        return null ;
//    }
//    if( script_model().isCreate() == true ) {
//        var ret = script_model().sql( sql ) ;
//        if( isNull( ret ) ) {
//            return null ;
//        }
//        else if( ret instanceof java.lang.Integer ) {
//            return convertString( ret ) ;
//        }
//        else if( ret instanceof java.lang.String ) {
//            return convertString( ret ) ;
//        }
//        return SubModel.convertResultByJList( ret ) ;
//    }
//    return null ;
//} ;

////////////////////////////////////////////////////////////////////////////////
// Model-Sub定義.
////////////////////////////////////////////////////////////////////////////////

// サブModelメソッド群用オブジェクト.
SubModel = function() {} ;

// 予約カラム名.
SubModel.COLUMN_ID = convertString( org.maachang.dao.dbms.DbUtil.convertDBNameByJavaName(
    false,org.maachang.dao.ExecutionDao.SEQ_COLUMN ) ) ;
SubModel.COLUMN_CREATE_TIME = convertString( org.maachang.dao.dbms.DbUtil.convertDBNameByJavaName(
    false,org.maachang.dao.ExecutionDao.CREATE_TIME ) ) ;
SubModel.COLUMN_UPDATE_TIME = convertString( org.maachang.dao.dbms.DbUtil.convertDBNameByJavaName(
    false,org.maachang.dao.ExecutionDao.UPDATE_TIME ) ) ;
SubModel.COLUMN_OPTIMISTIC_LOCK = convertString( org.maachang.dao.dbms.DbUtil.convertDBNameByJavaName(
    false,org.maachang.dao.ExecutionDao.OPTIMISTIC_LOCK_COLUMN ) ) ;

// 楽観的ロックエラーパラメータ格納名.
SubModel.ERROR_OPTIMISTIC_LOCK = "~error_optimisticLock" ;

// 日付カラムタイプを示すオブジェクト.
//SubModel.OUTPUT_DATE_TYPE = "new Date:" ;

// dbmap.
SubModel.dbmap = function(map) {
    if( isNull( map ) || ( map instanceof java.util.Map ) == false ) {
        return null ;
    }
    return new JSAdapter({
        __get__ : function(name) {
            if( name == "__getJSAdapterType" ) {
                return "map" ;
            }
            else if( "core" == name ) {
                return map ;
            }
            else if( "empty" == name ) {
                return ( map.size() <= 0 ) ;
            }
            else if (map.containsKey(name)) {
                var ret = map.get(name);
                return parseValue( ret ) ;
            }
            else if( name == "toString" ) {
                var ret = new StrBuf().ad( "{" ) ;
                var it = map.keySet().iterator() ;
                var cnt = 0 ;
                while( it.hasNext() ) {
                    if( cnt != 0 ) {
                        ret.ad( " ," ) ;
                    }
                    var x = it.next() ;
                    var v = map.get( x ) ;
                    if( isNull( v ) == false ) {
                        var clz = className( v ) ;
                        if( clz == "JSAdapter" || clz == "NativeArray" || clz == "NativeObject" ) {
                            ret.ad( x ).ad( ": " ).ad( "\"" ).ad( v.toString ).ad( "\"" ) ;
                        }
                        else if( clz == "NativeDate" ) {
                            ret.ad( x ).ad( ": " ).ad( "\"" ).ad( formatDateByCustomString( v," " ) ).ad( "\"" ) ;
                        }
                        else {
                            ret.ad( x ).ad( ": " ).ad( "\"" ).ad( v ).ad( "\"" ) ;
                        }
                    }
                    else {
                        ret.ad( x ).ad( ": \"\"" ) ;
                    }
                    cnt ++ ;
                }
                ret.ad( "}" ) ;
                return ret.ts() ;
            }
            else {
                return null ;
            }
        },
        __has__ :  function(name) {
            if( name == "toString" || name == "__getJSAdapterType" || name == "core" || name == "empty" ) {
                return true ;
            }
            return map.containsKey(name);
        },
        __delete__ : function (name) {
            if (map.containsKey(name)) {
                map.remove(name) ;
            }
        },
        __put__ : function(name, value) {
            if( name == "toString" || name == "__getJSAdapterType" || name == "core" || name == "empty" ) {
                return false ;
            }
            map.put(name,value);
            return true ;
        },
        __getIds__ : function() {
            var ret = [] ;
            var o = map.keySet().iterator() ;
            while( o.hasNext() ) {
                ret[ ret.length ] = o.next() ;
            }
            return ret ;
        },
        toString: function() {
            var ret = new StrBuf().ad( "{" ) ;
            var it = map.keySet().iterator() ;
            var cnt = 0 ;
            while( it.hasNext() ) {
                if( cnt != 0 ) {
                    ret.ad( " ," ) ;
                }
                var x = it.next() ;
                var v = map.get( x ) ;
                if( isNull( v ) == false ) {
                    var clz = className( v ) ;
                    if( clz == "JSAdapter" || clz == "NativeArray" || clz == "NativeObject" ) {
                        ret.ad( x ).ad( ": " ).ad( "\"" ).ad( v.toString ).ad( "\"" ) ;
                    }
                    else if( clz == "NativeDate" ) {
                        ret.ad( x ).ad( ": " ).ad( "\"" ).ad( formatDateByCustomString( v," " ) ).ad( "\"" ) ;
                    }
                    else {
                        ret.ad( x ).ad( ": " ).ad( "\"" ).ad( v ).ad( "\"" ) ;
                    }
                }
                else {
                    ret.ad( x ).ad( ": \"\"" ) ;
                }
                cnt ++ ;
            }
            ret.ad( "}" ) ;
            return ret.ts() ;
        },
        __getJSAdapterType: function() {
            return "map" ;
        },
        core: function() {
            return map ;
        },
        empty: function() {
            return ( map.size() <= 0 ) ;
        }
    });
} ;

// read戻りオブジェクト.
SubModel.resultLine = function() {}
SubModel.resultLine.prototype = {
    res : null,
    create : function( res ) {
        this.res = res ;
    },
    clear : function() {
        if( this.res != null ) {
            this.res.clear() ;
        }
        this.res = null ;
    },
    next : function() {
        if( this.res == null ) {
            return null ;
        }
        var ret = this.res.next() ;
        if( ret == null ) {
            return null ;
        }
        return SubModel.convertResultByJMap( ret ) ;
    },
    count : function() {
        if( this.res == null ) {
            return -1 ;
        }
        return this.res.count() ;
    },
    name : function() {
        if( this.res == null ) {
            return null ;
        }
        return this.res.getModelName() ;
    }
}


// パラメータをHashMapに変換.
SubModel.convertParamByMap = function(params) {
    if( isNull( params ) ) {
        return null ;
    }
    var ret = new java.util.HashMap() ;
    for( var k in params ) {
        if( k == SubModel.ERROR_OPTIMISTIC_LOCK ) {
            continue ;
        }
        ret.put( k,SubModel.convertOneParam( params[k] ) ) ;
    }
    return ret ;
}

// 指定リストをArrayListに変換.
SubModel.convertParamByList = function( params ) {
    if( isNull( params ) || params.length <= 0 ) {
        return null ;
    }
    var ret = new java.util.ArrayList() ;
    var len = params.length ;
    for( var i = 0 ; i < len ; i ++ ) {
        ret.add( SubModel.convertOneParam( params[ i ] ) ) ;
    }
    return ret ;
}

// 指定条件を変換.
SubModel.convertOneParam = function( x ) {
    if( isNull( x ) == false ) {
        var type = valueof( x ) ;
        if( type == "date" ) {
            x = org.maachang.comet.httpd.engine.script.dao.DaoUtil.convertTimeByDateObject( x.getTime() ) ;
        }
        else if( type == "array" ) {
            x = SubModel.convertParamByList( x ) ;
        }
        else if( type == "map" ) {
            x = SubModel.convertParamByMap( x ) ;
        }
    }
    return x ;
}

// 戻りオブジェクトをjlistに変換.
SubModel.convertResultByJList = function(res) {
    /*
    if( isNull( res ) || ( res instanceof java.util.List ) == false ) {
        return [] ;
    }
    var ret = [] ;
    var len = res.size() ;
    for( var i = 0 ; i < len ; i ++ ) {
        ret[ ret.length ] = SubModel.convertResultByJMap( res.get( i ) ) ;
    }
    res.clear() ;
    return ret ;
    */
    if( isNull( res ) || ( res instanceof java.util.List ) == false ) {
        return jlist() ;
    }
    var len = res.size() ;
    if( len > 0 ) {
        var lst = new java.util.ArrayList() ;
        for( var i = 0 ; i < len ; i ++ ) {
            var d = res.get( i ) ;
            lst.add( SubModel.convertResultByJMap( d ) ) ;
        }
        var ret = jlist( lst ) ;
        return ret ;
    }
    return jlist() ;
}

// 戻りオブジェクトをjmapに変換.
SubModel.convertResultByJMap = function(map) {
    if( isNull( map ) || ( map instanceof java.util.Map ) == false ) {
        return null ;
    }
    var o = map.keySet().iterator() ;
    /*
    var ret = {} ;
    while( o.hasNext() ) {
        var one = o.next() ;
        var val = map.get( one ) ;
        if( isNull( val ) ) {
            ret[ one ] = "" ;
        }
        else if( val instanceof java.util.Date ) {
            ret[ one ] = new Date( val.getTime() ) ;
        }
        else if( val instanceof java.util.Map ) {// 1件のjoin.
            ret[ one ] = SubModel.convertResultByJMap( val ) ;
        }
        else if( val instanceof java.util.List ) {// join.
            ret[ one ] = SubModel.convertResultByJList( val ) ;
        }
        else {
            ret[ one ] = val ;
        }
    }
    map.clear() ;
    return ret ;
    */
    while( o.hasNext() ) {
        var one = o.next() ;
        var val = map.get( one ) ;
        if( isNull( val ) ) {
            map.put( one,null ) ;
            continue ;
        }
        else if( val instanceof java.util.Date ) {
            map.put( one,new Date( val.getTime() ) ) ;
        }
        else if( val instanceof java.util.Map ) {// 1件のjoin.
            if( val.size() <= 0 ) {
                map.put( one,SubModel.dbmap() ) ;
            }
            else {
                map.put( one,SubModel.convertResultByJMap( val ) ) ;
            }
        }
        else if( val instanceof java.util.List ) {// join.
            if( val.size() <= 0 ) {
                map.put( one,jlist() ) ;
            }
            else {
                map.put( one,SubModel.convertResultByJList( val ) ) ;
            }
        }
    }
    return SubModel.dbmap( map ) ;
}

// joinキー群を取得.
SubModel.getModelByJoinKeys = function( map ) {
    if( isNull( map ) ) {
        return null ;
    }
    var join = map.get( "join" ) ;
    if( isNull( join ) || valueof( join ) != "map" ) {
        return null ;
    }
    var ret = new java.util.HashMap() ;
    for( var k in join ) {
        ret.put( k,join[k] ) ;
    }
    if( ret.size() <= 0 ) {
        return null ;
    }
    return ret ;
}

// ImageJoin群を取得.
SubModel.getModelByImageJoin = function( map ) {
    if( isNull( map ) ) {
        return null ;
    }
    var join = map.get( "imageJoin" ) ;
    if( isNull( join ) || valueof( join ) != "array" ) {
        return null ;
    }
    var ret = new java.util.ArrayList() ;
    var len = join.length ;
    for( var i = 0 ; i < len ; i ++ ) {
        ret.add( join[ i ] ) ;
    }
    if( ret.size() <= 0 ) {
        return null ;
    }
    return ret ;
}

// 対象テーブルのSrcJoinキー群を取得.
SubModel.getModelBySrcJoinKeys = function( thisModel,map ) {
    var cnt = 0 ;
    var tables = map.get( "srcJoin" ) ;
    if( isNull( tables ) == false && tables.length > 0 ) {
        var len = tables.length ;
        var ret = new java.util.HashMap() ;
        var bindings = context.getBindings(
            javax.script.ScriptContext.ENGINE_SCOPE ) ;
        for( var i = 0 ; i < len ; i ++ ) {
            var addList = null ;
            var name = tables[i] ;
            var model = bindings.get( name ) ;
            if( isNull( model ) ) {
                continue ;
            }
            var join = model.join ;
            if( isNull( join ) == false ) {
                for( var k in join ) {
                    if( join[k] == thisModel ) {
                        if( isNull( addList ) ) {
                            addList = new java.util.ArrayList() ;
                            ret.put( name,addList ) ;
                        }
                        addList.add( k ) ;
                        cnt ++ ;
                    }
                }
            }
        }
    }
    if( cnt <= 0 ) {
        return null ;
    }
    return ret ;
}

// １対他の外部結合条件を削除.
// findManyなどで取得された、データには、結合を示すカラム名($結合テーブル名)となります。
// これらは、saveや、remove時には必要ないので、その内容を省いた形で利用しなければ
// する必要があり、このメソッドで、その処理を実施させます.
SubModel.removeManyColumn = function( map ) {
    if( isNull( map ) ) {
        return ;
    }
    if( map instanceof java.util.Map ) {
        if( map.size() <= 0 ) {
            return ;
        }
        var o = map.keySet().iterator() ;
        while( o.hasNext() ) {
            var one = o.next() ;
            if( startsWith( one,"$" ) ) {
                map.remove( one ) ;
            }
        }
    }
    else {
        for( var k in map ) {
            if( startsWith( k,"$" ) ) {
                delete map[k] ;
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// record補助.
////////////////////////////////////////////////////////////////////////////////

// １つのデータ行を、Mapにコピーする.
copyRecord = function( map,recordBean ) {
    if( isNull( map ) || isNull( recordBean ) || valueof( recordBean ) != "map" ) {
        return false ;
    }
    for( var key in recordBean ) {
        var val = recordBean[ key ] ;
        if( isNull( val ) ) {
            map[ key ] = null ;
        }
        else if( key != SubModel.COLUMN_CREATE_TIME &&
            key != SubModel.COLUMN_UPDATE_TIME &&
            valueof( val ) == "date" ) {
            convertDateByMap( map,key,val ) ;
            map[ key ] = val ;
        }
        else {
            map[ key ] = val ;
        }
    }
    return true ;
}

// プーリングRDBMS最大値.
MSys.getDbMax = function(){
    return org.maachang.comet.MSystem.getDbMax() ;
}
// プーリングRDBMSアクティブ値.
MSys.getDbActives = function(){
    return org.maachang.comet.MSystem.getDbActives() ;
}
// プーリングRDBMSアイドル値.
MSys.getDbIdle = function(){
    return org.maachang.comet.MSystem.getDbIdle() ;
}
