package br.ufrgs.inf.prosoft.tigris.monitoring.storage;

import br.ufrgs.inf.prosoft.tigris.configuration.types.RepositoryType;
import br.ufrgs.inf.prosoft.tigris.exceptions.StorageException;
import br.ufrgs.inf.prosoft.tigris.monitoring.metadata.LogTrace;
import br.ufrgs.inf.prosoft.tigris.monitoring.storage.providers.AsyncFileRepository;
import br.ufrgs.inf.prosoft.tigris.monitoring.storage.providers.ConsoleRepository;
import br.ufrgs.inf.prosoft.tigris.monitoring.storage.providers.MemoryRepository;
import br.ufrgs.inf.prosoft.tigris.monitoring.storage.providers.MongoRepository;
import br.ufrgs.inf.prosoft.tigris.monitoring.storage.providers.RedisRepository;
import com.mongodb.MongoClient;
import com.mongodb.MongoTimeoutException;
import com.mongodb.client.MongoDatabase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.Properties;

/**
 * The type Repository factory.
 */
public class RepositoryFactory {

    /**
     * The Logger.
     */
    static Logger logger = LoggerFactory.getLogger(RepositoryFactory.class);

    /**
     * Gets repository.
     *
     * @param properties     the properties
     * @param repositoryType the repository type
     * @return the repository
     * @throws IOException the io exception
     */
    public static Repository getRepository(Properties properties, RepositoryType repositoryType) throws IOException {

        switch (repositoryType) {
            case MONGODB:
                try {
                    MongoClient mongo = new MongoClient(properties.getProperty("adaptivecaching.monitoring.db.address"), Integer.parseInt(properties.getProperty("adaptivecaching.monitoring.db.port")));
                    MongoDatabase database = mongo.getDatabase(properties.getProperty("adaptivecaching.monitoring.db.scheme"));
                    Repository repository = new MongoRepository<>(database.getCollection(properties.getProperty("adaptivecaching.monitoring.db.name")), LogTrace.class);
                    logger.debug("Repository created to MongoDB: " + repository.toString());
                    return repository;
                } catch (MongoTimeoutException e) {
                    throw new StorageException("Cannot connect with MongoDB with the defined properties.", e);
                }
            case REDIS:
                //TODO decouple it from redis and get of properties
                logger.debug("Repository is configured to Redis.");
                return new RedisRepository<LogTrace>();
            case TEXTFILE:
                //TODO decouple it from redis and get of properties
                AsyncFileRepository as = new AsyncFileRepository(new File("traces.txt"));
                as.open();
                logger.debug("Repository is configured to save logs in textfile.");
                return as;
            case MEMORY:
                //TODO decouple it from redis and get of properties
                //TODO log a warning because memory can take too much from the application...
                logger.warn("Repository is configured to save logs in Memory, which is not recommended because it can take too much from the application.");
                return new MemoryRepository<LogTrace>();
            case CONSOLE:
                //TODO decouple it from redis and get of properties
                logger.warn("Repository is configured to just show logs in console. Nothing will be recorded");
                return new ConsoleRepository<LogTrace>();
            default:
                throw new StorageException("The specified repository type [" + repositoryType +"] does not have an available implementation.");
        }
    }
}
