/**
 * Copyright (c) 2009-2012 EBM WebSourcing, 2012-2013 Linagora
 * 
 * This program/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.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see <http://www.gnu.org/licenses/>
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.bc.sql;

import java.sql.SQLException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.ow2.petals.component.framework.api.configuration.ConfigurationExtensions;
import org.ow2.petals.component.framework.api.exception.PEtALSCDKException;
import org.ow2.petals.component.framework.jbidescriptor.generated.Provides;

import com.ebmwebsourcing.easycommons.lang.StringHelper;

/**
 * @author Adrien LOUIS - EBM WebSourcing
 */
public class DataSources {

    private Logger logger;

    private Map<Provides, DataSource> dataSources;

    public DataSources(Logger logger) {
        this.logger = logger;
        dataSources = new ConcurrentHashMap<Provides, DataSource>();
    }

    /**
     * create a dataSource related to the information stored in the SU: <li>url,
     * </li> <li>driver(optional, resolve by jdbc url),</li> <li>user,</li> <li>
     * password,</li> <li>maxActive(optional),</li> <li>maxIdle(optional),</li>
     * <li>minIdle(optional),</li> <li>maxWait(optional),</li> <li>
     * timeBEviction(optional)</li>
     * 
     * @see http://commons.apache.org/dbcp/configuration.html
     * @param extensions
     */
    public DataSource createDataSourceForService(ConfigurationExtensions extensions) {

        final BasicDataSource jdbcDataSource = new BasicDataSource();

        // common properties
        final String url = extensions.get(Constants.DATABASE_URL);
        String driver = extensions.get(Constants.DATABASE_DRIVER);
        if (StringHelper.isNullOrEmpty(driver)) {
            driver = DriverResolver.resolveDriverClassname(url);
        }

        final String user = extensions.get(Constants.DATABASE_USER);
        final String password = extensions.get(Constants.DATABASE_PASSWORD);

        jdbcDataSource.setUrl(url);
        jdbcDataSource.setDriverClassName(driver);
        jdbcDataSource.setUsername(user);
        jdbcDataSource.setPassword(password);

        // pool properties
        final String maxActive = extensions.get(Constants.DATABASE_MAXACTIVE);
        final String maxIdle = extensions.get(Constants.DATABASE_MAXIDLE);
        final String minIdle = extensions.get(Constants.DATABASE_MINIDLE);
        final String maxWait = extensions.get(Constants.DATABASE_MAXWAIT);
        final String timeBEviction = extensions.get(Constants.DATABASE_TIMEBTWEVICTION);

        if (maxActive != null) {
            jdbcDataSource.setMaxActive(Integer.parseInt(maxActive));
        }
        if (maxIdle != null) {
            jdbcDataSource.setMaxIdle(Integer.parseInt(maxIdle));
        }
        if (minIdle != null) {
            jdbcDataSource.setMinIdle(Integer.parseInt(minIdle));
        }
        if (maxWait != null) {
            jdbcDataSource.setMaxWait(Integer.parseInt(maxWait));
        }
        if (timeBEviction != null) {
            jdbcDataSource.setTimeBetweenEvictionRunsMillis(Integer.parseInt(timeBEviction));
        }
        logger.finest("Create a dataSource with parameters :\n"
                + printDataSourceInfo(jdbcDataSource));
        return jdbcDataSource;
    }

    /**
     * add the dataSource in the Map<Endpoint,DataSource>
     * 
     * @param key
     * @param dataSource
     */
    public void addDataSource(Provides key, DataSource dataSource) {
        dataSources.put(key, dataSource);
    }

    /**
     * get the dataSource in the Map<Endpoint,DataSource>
     * 
     * @param key
     * @param dataSource
     */
    public DataSource getDataSource(Provides key) {
        return dataSources.get(key);
    }

    /**
     * Return all keys map of the created datasources.
     * 
     * @return
     */
    public Set<Provides> getDataSourceKeys() {
        return dataSources.keySet();
    }

    /**
     * remove the dataSource in the Map<Endpoint,DataSource>
     * 
     * @param key
     * @return
     * @throws PEtALSCDKException
     */
    public DataSource removeDataSource(Provides key) throws PEtALSCDKException {
        return this.dataSources.remove(key);
    }

    /**
     * Close the DataSource (assume this is a BasicDataSource)
     * 
     * @param dataSource
     */
    public final void closeDataSource(DataSource dataSource) {
        try {
            ((BasicDataSource) dataSource).close();
        } catch (SQLException e) {
            logger.log(Level.WARNING,
                    "The following JDBC DataSource has not been closed properly.\n"
                            + printDataSourceInfo(dataSource));
        }

    }

    /**
     * Print info for a BasicDataSource
     * 
     * @param dataSource
     * @return
     */
    public static final String printDataSourceInfo(DataSource dataSource) {
        StringBuilder info = new StringBuilder();
        BasicDataSource bds = (BasicDataSource) dataSource;
        info.append("url           :" + bds.getUrl());
        info.append("\n");
        info.append("driver        :" + bds.getDriverClassName());
        info.append("\n");
        info.append("user          :" + bds.getUsername());
        info.append("\n");
        info.append("password      :" + bds.getPassword());
        info.append("\n");
        info.append("maxActive     :" + bds.getMaxActive());
        info.append("\n");
        info.append("maxIdle       :" + bds.getMaxIdle());
        info.append("\n");
        info.append("minIdle       :" + bds.getMinIdle());
        info.append("\n");
        info.append("maxWait       :" + bds.getMaxWait());
        info.append("\n");
        info.append("timeBEviction :" + bds.getTimeBetweenEvictionRunsMillis());
        return info.toString();
    }
}
