package com.libreecm.input.auxiliars;

import com.libreecm.commonAPI.model.Repository;
import com.libreecm.commonAPI.model.objects.Uri;

import java.util.HashMap;
import java.util.List;

import com.libreecm.commonAPI.auxiliars.exceptions.NoneExistingRepositoryException;
import com.libreecm.commonAPI.auxiliars.exceptions.NotDefinedRepositoryTypeException;
import com.libreecm.commonAPI.auxiliars.exceptions.NotExistingRepositoryException;
import com.libreecm.commonAPI.auxiliars.exceptions.NotExistingRepositoryPathException;
import com.libreecm.commonAPI.configuration.ComponentConfig;
import com.libreecm.input.consumers.RepositoryConsumer;
import com.libreecm.input.repositoriesImpl.DBRepository;
import com.libreecm.input.repositoriesImpl.FSRepository;
import com.libreecm.input.repositoriesImpl.RepositoryImpl;
import com.libreecm.input.repositoriesImpl.RepositoryType;
import com.libreecm.input.repositoriesImpl.ZippedFSRepository;

public class RepositoryCreator {
	private static RepositoryCreator repositoryCreator = null;


	/**
	 * Cache of the repositories
	 */
	private HashMap<String, RepositoryImpl> repositories = new HashMap<String, RepositoryImpl>();
	
	private RepositoryConsumer consumer = new RepositoryConsumer();
	
	private RepositoryCreator() {

	}

	public static RepositoryCreator get() {
		if (repositoryCreator == null)
			repositoryCreator = new RepositoryCreator();
		return repositoryCreator;
	}
	
	/**
	 * Reads a repository from cache, if fails, return a repository
	 * with information from default 
	 * @param repository name
	 * @return
	 */
	public RepositoryImpl getRepository(String name){
		// If we have it cached, return it
		if (repositories.containsKey(name)) {
			return repositories.get(name);
		}
		else {
			// Maybe it's not cached yet, try recaching
			//This could be between server reinitializations
			readPersistenceRepositories();
			if (repositories.containsKey(name)) {
				return repositories.get(name);
			}
			
			//Finally it's first time we see it, create a new one is no possible
			// we don't have enough info to create
			throw new NotExistingRepositoryException(name);
		}
	}
	
	
	
	/**
	 * Reads repositories from persistence
	 * TODO Delete this cause not to be used
	 */
	private void readPersistenceRepositories() {
		//TODO Delete this cause not to be used
		List<Repository> repos = consumer.getRepositories(ComponentConfig.getConfig().getMainRepositoriesUrl());
		if (repos==null || repos.isEmpty())
			return;
		for (Repository repo: repos){
			RepositoryImpl repoImpl=null;
			//Testing if it exists, if not, set as not active
			try {
				// If not exists, launches exception
				repoImpl=RepositoryCreator.get().getRepository(repo);

				//Exists, let's cache it
				repositories.put(repoImpl.getName(), repoImpl);
			} catch (NotExistingRepositoryPathException e) {
				repoImpl.setAccessible(false);
				repoImpl.setActive(false);
				consumer.setRepository(repoImpl, ComponentConfig.getConfig().getMainRepositoryUrl());
			} catch (NoneExistingRepositoryException e) {
				//If there is any, continue
			}
		}
	}

	/**
	 * Reads a repository from cache, if fails, return a repository
	 * with information from default 
	 * @param repository uri
	 * @return
	 */
	public RepositoryImpl getRepository(Uri uri){
		RepositoryImpl result = null;
		// If we have it cached, return it
				if (repositories.containsKey(uri.getRepositoryName())) {
					return repositories.get(uri.getRepositoryName());
				}
				else {
					// Maybe it's not cached yet, try recaching
					//readPersistenceRepositories();
					//if (repositories.containsKey(uri.getRepositoryName())) {
					//	return repositories.get(uri.getRepositoryName());
					//}
					
					//Finally it's first time we see it, create a new one 
					//RepositoryImpl result;
					if (uri.getType().equals(RepositoryType.FSREPOSITORY.value())) {
						result = new FSRepository(uri);
					} else if (uri.getType().equals(RepositoryType.DBREPOSITORY.value()))
						result = new DBRepository(uri);
					else if (uri.getType().equals(RepositoryType.ZIPPEDFSREPOSITORY.value()))
						result = new ZippedFSRepository(uri);
					else
						throw new NotDefinedRepositoryTypeException(uri.getType());
					
					result.setAccessible(true);
					result.setActive(true);
					//consumer.setRepository(result, ComponentConfig.getConfig().getMainRepositoryUrl());
					repositories.put(result.getName(), result);

					return result;
				}
	}

	/**
	 * Returns a repository:
	 * It first sets defaults values, then 
	 * sets that are read from 
	 * information at Repository (overrides)
	 * @param name
	 * @return
	 */
	public RepositoryImpl getRepository(Repository repo) {
		
			RepositoryImpl result;
			if (repo.getTypeId().equals(RepositoryType.FSREPOSITORY.value())) {
				result = new FSRepository(repo);
			} else if (repo.getTypeId().equals(RepositoryType.DBREPOSITORY.value()))
				result = new DBRepository(repo);
			else if (repo.getTypeId().equals(RepositoryType.ZIPPEDFSREPOSITORY.value()))
				result = new ZippedFSRepository(repo);
			else
				throw new NotDefinedRepositoryTypeException(repo.getTypeId());
			repositories.put(repo.getName(), result);
			return result;
	}
}