package org.nybatis.core.db.datasource.driver;

import org.nybatis.core.exception.unchecked.DatabaseConfigurationException;
import org.nybatis.core.log.NLogger;
import org.nybatis.core.reflection.Reflector;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Map;

/**
 * Database attribute Manager
 *
 * @author nayasis@gmail.com
 * @since 2015-10-29
 */
public class DatabaseAttributeManager {

    private static Map<String, DatabaseAttribute> driverRepository = new Hashtable<>();

    public static void add( DatabaseAttribute databaseAttribute ) {
        driverRepository.put( databaseAttribute.getDatabase(), databaseAttribute );
    }

    public static DatabaseAttribute get( DataSource datasource ) throws DatabaseConfigurationException {

        Connection  connection = null;

        try {

            connection = datasource.getConnection();

            return get( connection );

        } catch( SQLException e ) {
            throw new DatabaseConfigurationException( e );
        } finally {
            if( connection != null ) {
                try {
                    connection.close();
                } catch( SQLException e ) {}
            }
        }

    }


    private static DatabaseAttribute get( Connection connection ) throws SQLException {

        Connection realConnection = Reflector.unwrapProxy( connection );

        String className = realConnection.getClass().getName();

        NLogger.trace( "---------------------------------------------------------------------" );
        NLogger.trace( "Connection class name : {}", className );
        NLogger.trace( "---------------------------------------------------------------------" );

        for( DatabaseAttribute attribute : driverRepository.values() ) {
            if( attribute.isMatched( className ) ) {
                NLogger.trace( attribute );
                return attribute.clone();
            }
        }

        if( ! driverRepository.containsKey( className ) ) {
            add( new DatabaseAttribute( className, className ) );
        }

        DatabaseAttribute databaseAttribute = driverRepository.get( className );

        NLogger.trace( databaseAttribute );

        return databaseAttribute.clone();

    }

    public static DatabaseAttribute get( String driverType ) {
        return driverRepository.get( driverType );
    }

    public static boolean contains( String driverType ) {
        return driverRepository.containsKey( driverType );
    }

    static {

        add( new DatabaseAttribute("oracle", "oracle\\.jdbc\\.driver" )
            .setPageSqlPre( "SELECT * FROM ( SELECT ROWNUM AS nybatis_page_rownum, NYBATIS_PAGE_VIEW.* FROM (\n" )
            .setPageSqlPost( "\n) NYBATIS_PAGE_VIEW WHERE rownum <= #{end} ) WHERE nybatis_page_rownum >= #{start}" )
            .setPingQuery( "SELECT 1 FROM DUAL" )
        );

        add( new DatabaseAttribute( "mysql",      "com\\.mysql\\.jdbc"          ) );
        add( new DatabaseAttribute( "maria",      "org\\.mariadb\\.jdbc"        ) );
        add( new DatabaseAttribute( "sqlite",     "org\\.sqlite\\."             ) );
        add( new DatabaseAttribute( "h2",         "org\\.h2\\.jdbc"             ) );

        //   Not Tested  !
        add( new DatabaseAttribute( "derby",      "org\\.apache\\.derby\\.jdbc" ) );
        add( new DatabaseAttribute( "hsqldb",     "org\\.hsqldb\\.jdbcDriver"   ) );
        add( new DatabaseAttribute( "mssql",      "com\\.microsoft\\.jdbc"      ) );
        add( new DatabaseAttribute( "postgresql", "postgresql\\.driver"         ) );
        add( new DatabaseAttribute( "sybase",     "com\\.sybase\\."             ) );
        add( new DatabaseAttribute( "db2",        "ibm\\.db2\\."                ) );
        add( new DatabaseAttribute( "odbc",       "sun\\.jdbc\\.odbc"           ) );

    }

}

@@ -3182,32 +3182,33 @@
            ) );%0A
+%0A
         add( new
@@ -3230,22 +3230,13 @@
 ute(
- 
 %22h2%22,
-        
  %22or
@@ -3242,32 +3242,34 @@
 rg%5C%5C.h2%5C%5C.jdbc%22 
+)%0A
             ) );
@@ -3256,33 +3256,112 @@
 %22 )%0A            
-)
+.setPageSqlPost( %22LIMIT (#%7Bend%7D - #%7Bstart%7D + 1) OFFSET (#%7Bstart%7D - 1)%22 )%0A       
  );%0A%0A        // 

fix h2 pagination sql ( limit #{count} offset #{startIndex} )