/**
 * Copyright © 2012-2023 by Data Virtuality GmbH
 */
package org.teiid.translator.jdbc;

import com.datavirtuality.dv.core.interfaces.DVCaller;
import org.teiid.metadata.MetadataFactory;
import org.teiid.translator.TranslatorException;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author Allan Vital
 * @date 2023.07.31
 */
public class JDBCMulticatalogProcessor extends JDBCMetadataProcessor {

    protected boolean loadAllCatalogsWhenCatalogIsNull = false;

    @Override
    public Map<String, JDBCMetadataProcessor.TableInfo> getTables(MetadataFactory metadataFactory,
                                                                  DatabaseMetaData metadata, Connection conn, String[] tableTypes) throws SQLException, TranslatorException {

        String cleanCatalogParameter = metadataFactory.getCatalog(false);
        String rawCatalogParameter = metadataFactory.getCatalog(true);
        if (rawCatalogParameter == null || rawCatalogParameter.isEmpty()) {
            rawCatalogParameter = cleanCatalogParameter;
        }
        Boolean isCatalogSingleValueAndDoesNotContainPattern = System.getProperty("dv.embedded") == null ? (Boolean) DVCaller.call(233, rawCatalogParameter) : true;
        if (Boolean.TRUE.equals(isCatalogSingleValueAndDoesNotContainPattern) && (getCatalog() == null && !loadAllCatalogsWhenCatalogIsNull)) {
            return super.getTables(metadataFactory, metadata, conn, tableTypes);
        }
        String runtimeCatalog = this.getCatalog();
        try {
            ResultSet catalogs = metadata.getCatalogs();
            Map<String, JDBCMetadataProcessor.TableInfo> returnMap = new HashMap<>();
            Set<String> mappedFullNames = new HashSet<>();
            while (catalogs.next()) {
                String catalogName = catalogs.getString("TABLE_CAT");
                String catalogToMatch = rawCatalogParameter == null ? getCatalog() : rawCatalogParameter;
                if (catalogToMatch == null && loadAllCatalogsWhenCatalogIsNull) {
                    catalogToMatch = "%";
                }
                Boolean matchPattern = (Boolean) DVCaller.call(234, catalogName, catalogToMatch);
                if (Boolean.TRUE.equals(matchPattern)) {
                    this.setCatalog(catalogName);
                    Map<String, TableInfo> tables = super.getTables(metadataFactory, metadata, conn, tableTypes, mappedFullNames);
                    for (Map.Entry<String, TableInfo> entry : tables.entrySet()) {
                        TableInfo table = entry.getValue();
                        String fullName = getFullyQualifiedName(table.catalog, table.schema, table.name, executionFactory != null && executionFactory.forceQuotedIdentifiers());
                        mappedFullNames.add(fullName);
                    }
                    returnMap.putAll(tables);
                }
                    this.setCatalog(runtimeCatalog);
            }
            return returnMap;
        } finally {
            this.setCatalog(runtimeCatalog);
        }
    }

    public void getProcedures(MetadataFactory metadataFactory, DatabaseMetaData metadata, Connection conn) throws SQLException {
        String cleanCatalog = this.getCatalog();
        Boolean isCatalogSingleValueAndDoesNotContainPattern = System.getProperty("dv.embedded") == null ? (Boolean) DVCaller.call(233, cleanCatalog) : true;
        if (Boolean.TRUE.equals(isCatalogSingleValueAndDoesNotContainPattern)) {
            super.getProcedures(metadataFactory, metadata, conn);
            if (cleanCatalog != null) {
                conn.setCatalog(cleanCatalog);
            }
            return;
        }
        try {
            ResultSet catalogs = metadata.getCatalogs();
            while (catalogs.next()) {
                String catalogName = catalogs.getString("TABLE_CAT");
                Boolean matchPattern = (Boolean) DVCaller.call(234, catalogName, cleanCatalog);
                if (Boolean.TRUE.equals(matchPattern)) {
                    this.setCatalog(catalogName);
                    super.getProcedures(metadataFactory, metadata, conn);
                }
            }
        } finally {
            this.setCatalog(cleanCatalog);
        }
    }

}