/*
 * 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.definition.FieldFactory;
import blanco.db.definition.TableField;
import blanco.db.definition.TableGateway;

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

    private List _resultList = new ArrayList();

    private FieldFactory _factory = new FieldFactory();

    private BlancoDbMetadata _metadata = null;

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

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

        collectTableNames();

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

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

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

    private Map getPrimaryKeyMap(final Table table) throws SQLException {
        Map result = null;
        if (table.hasKeyField()) {
            final 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(final Map keys, final ResultSet resultSet)
            throws SQLException {
        final TableField result = _factory.createTableField(resultSet);
        if (result != null && keys.containsKey(result.getName())) {
            final short sequence = ((Short) keys.get(result.getJdbcName()))
                    .shortValue();
            result.setPrimaryKeySeq(sequence);
        }
        return result;
    }

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

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

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

        final String tableName = table.getName();
        ResultSet rs = null;
        try {
            try {
                rs = getDatabaseMetaData().getColumns(catalog, null, tableName,
                        null);
            } catch (SQLException ex) {
                throw new IllegalArgumentException("単一表[" + tableName
                        + "]の情報を収集しているときに例外が発生しました。" + ex.toString());
            }

            try {
                for (; rs.next();) {
                    listColumns.add(createField(keys, rs));
                }
            } catch (SQLException ex) {
                final String columnName = rs.getString("COLUMN_NAME");
                final String typeName = rs.getString("TYPE_NAME");
                throw new IllegalArgumentException("単一表[" + tableName + "]の列["
                        + columnName + "]の情報を処理しているときにSQL例外が発生しました。"
                        + "TYPE_NAME(" + typeName + ")" + ex.toString());
            } catch (IllegalArgumentException ex) {
                final String columnName = rs.getString("COLUMN_NAME");
                final String typeName = rs.getString("TYPE_NAME");
                throw new IllegalArgumentException("単一表[" + tableName + "]の列["
                        + columnName + "]の情報を処理しているときに入力例外が発生しました。"
                        + "TYPE_NAME(" + typeName + ")" + ex.toString());
            }
        } finally {
            if (rs != null) {
                rs.close();
            }
        }
        return listColumns;
    }

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