/*
 * blancoDb
 * Copyright (C) 2004-2005 Yasuo Nakanishi
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.db.collector;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import blanco.db.conf.BlancoDbMetadata;
import blanco.db.conf.Table;
import blanco.db.conf.TableGenerate;
import blanco.db.definition.FieldFactory;
import blanco.db.definition.TableField;
import blanco.db.definition.TableGateway;
import blanco.db.mapping.BlancoDbMappingUtil;
import blanco.ig.tool.ConsolePrinter;

/**
 * @author Yasuo Nakanishi
 */
public class GatewayCollector {
    private DatabaseService _databaseService = null;

    private List _resultList = new ArrayList();

    private FieldFactory _factory = new FieldFactory();

    private ConsolePrinter _printer = ConsolePrinter.get();

    private BlancoDbMetadata _metadata = null;

    public GatewayCollector(DatabaseService databaseService) {
        _databaseService = databaseService;
    }

    public List collect(BlancoDbMetadata metadata) throws SQLException {
        _metadata = metadata;

        if (_metadata.getTableGenerate() == TableGenerate.DATABASE) {
            collectTableNames();
        }

        for (int i = 0; i < _metadata.getTableCount(); i++) {
            collectTableFields(_metadata.getTable(i));
        }
        return _resultList;
    }

    private void collectTableFields(Table table) throws SQLException {
        TableGateway tableGateway = new TableGateway(table.getName());
        ArrayList fields = getTableFields(table);

        for (int j = 0; j < fields.size(); j++) {
            tableGateway.addField((TableField) fields.get(j));
        }
        _resultList.add(tableGateway);
    }

    private Map getPrimaryKeyMap(Table table) throws SQLException {
        Map result = null;
        if (table.hasKeyField()) {
            Iterator iterator = table.getKeyFieldItrator();
            result = new Hashtable();
            String key = "";
            for (short i = 0; iterator.hasNext(); i++) {
                key = (String) iterator.next();
                result.put(key, new Short(i));
            }
        } else {
            result = _databaseService.getPrimaryKeyMap(table.getName());
        }
        return result;
    }

    private TableField createField(Map keys, ResultSet resultSet)
            throws SQLException {
        TableField result = null;
        result = _factory.createTableField(resultSet);
        short sequence = 0;
        if (result != null && keys.containsKey(result.getName())) {
            sequence = ((Short) keys.get(result.getJdbcName())).shortValue();
            result.setPrimaryKeySeq(sequence);
        }
        return result;
    }

    private DatabaseMetaData getDatabaseMetaData() throws SQLException {
        return _databaseService.getDatabaseMetaData();
    }

    public ArrayList getTableFields(Table table) throws SQLException {
        ResultSet rs = null;
        String catalog = _databaseService.getCatalog();

        ArrayList listColumns = new ArrayList();
        Map keys = getPrimaryKeyMap(table);

        String tableName = table.getName();
        try {
            rs = getDatabaseMetaData().getColumns(catalog, null, tableName,
                    null);
            for (; rs.next();) {
                if (_factory.isSupportedDatabaseType(rs)) {
                    listColumns.add(createField(keys, rs));
                } else {
                    _printer.printWarning(createMessage(rs));
                }
            }
        } finally {
            if (rs != null) {
                rs.close();
            }
        }
        return listColumns;
    }

    private void collectTableNames() throws SQLException {
        List tables = _databaseService.getTableNameList();
        for (int i = 0; i < tables.size(); i++) {
            _metadata.addTable(new Table((String) tables.get(i)));
        }
    }

    private String createMessage(ResultSet resultSet) throws SQLException {
        StringBuffer sb = new StringBuffer();
        sb.append("サポート外のタイプ カラム名:");
        sb.append(resultSet.getString("COLUMN_NAME"));
        int type = resultSet.getInt("DATA_TYPE");
        sb.append(", " + BlancoDbMappingUtil.convertJdbcTypeToString(type));
        return sb.toString();
    }

}