package com.libreecm.controllers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.libreecm.commonAPI.auxiliars.exceptions.AlreadyExistingNewTypeSettableAttributesException;
import com.libreecm.commonAPI.auxiliars.exceptions.AlreadyExistingRepositoryException;
import com.libreecm.commonAPI.auxiliars.exceptions.NoneExistingRepositoryException;
import com.libreecm.commonAPI.auxiliars.exceptions.NotAccessibleRepositoryException;
import com.libreecm.commonAPI.auxiliars.exceptions.RepositoryNotWrittableException;
import com.libreecm.commonAPI.configuration.ComponentConfig;
import com.libreecm.commonAPI.model.NewTypeSettableAttributes;
import com.libreecm.commonAPI.model.Repository;
import com.libreecm.commonAPI.model.objects.ObjectType;
import com.libreecm.commonAPI.model.objects.Uri;
import com.libreecm.commonAPI.model.objects.properties.PropertyDefinition;
import com.libreecm.consumers.RepositoryConsumer;

@RestController
public class RepositoryController extends BaseController {

	private RepositoryConsumer consumer = new RepositoryConsumer();

	private HashMap<String, Repository> repositories = new HashMap<>();
	
	public RepositoryController(){

		//Reading default repositories from config.xml
		 ArrayList<String> repositories=ComponentConfig.getConfig().getRepositories();
		 for (String repoUri: repositories){
			 Uri uri= Uri.parse(repoUri);
			
			Repository repository = new Repository(uri);
			saveRepository(repository);this.saveRepository(repository);
		 }
	}
	

	@RequestMapping(value = "/repository", method = RequestMethod.POST)
	/**
	 * A class that saves a Repository to the DDBB First checks if the
	 * repository exists and is accessible If it yet exists, it's overridden and
	 * saved to persistence
	 * 
	 * @param repository
	 * @return
	 */
	public @ResponseBody Repository saveRepository(@RequestBody Repository repository) {
		// validateUser();
		if (repository.getName().length() == 0 || repository.getTypeId().length() == 0)
			throw new RepositoryNotWrittableException(repository.getName());

		// Checking if it's accessible or throw exception
		// System.out.println("form ecm repository controller, setting to input
		// "+repository.getName());
		try {
			repository = consumer.setRepository(repository, ComponentConfig.getConfig().getInputRepositoryUrl());
		} catch (Exception e) {
			this.repositories.remove(repository.getName());
			e.printStackTrace();
			throw new NotAccessibleRepositoryException(repository.getName());
		}
		repository.setAccessible(true);
		repository.setActive(true);

		// If exists, return it
		if (repositories.containsKey(repository.getName())) {
			return repositories.get(repository.getName());
		}

		// Saving data to persistence
		// EventHandler.getHandler().preEvent(repository);
		repository = consumer.setRepository(repository, ComponentConfig.getConfig().getDbRepositoryUrl());
		repositories.put(repository.getName(), repository);
		return repository;
		// EventHandler.getHandler().postEvent(repository);
		// throw new AddRepositoryOkException(repository.getId());
	}

	/**
	 * A class that returns a Repository from the DDBB and checks if it's
	 * accessible and readable
	 * 
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/repository", method = RequestMethod.GET)
	public @ResponseBody Repository getRepository(@RequestParam(value = "name", required = true) String name) {
		// validateUser();

		Repository repository = null;
		if (repositories.containsKey(name)) {
			return repositories.get(name);
		}
		repository = consumer.getRepository(name, ComponentConfig.getConfig().getDbRepositoryUrl());

		// Testing repository validation
		if (repository.getName().isEmpty() || repository.getId().isEmpty() || repository.getTypeId().isEmpty() ) {
			throw new NotAccessibleRepositoryException(name);
		}

		// Checking if it's accessible or throw exception. If accessible add to
		// cache and return it
		try {
			repository = consumer.getRepository(repository, ComponentConfig.getConfig().getInputRepositoryUrl());
		} catch (Exception e) {
			this.repositories.remove(repository.getName());
			throw new NotAccessibleRepositoryException(repository.getName());
		}
		this.repositories.put(repository.getName(), repository);
		return repository;
	}
	

	/**
	 * A class that returns a Repository from the DDBB and checks if it's
	 * accessible and readable
	 * 
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/repositorybyid", method = RequestMethod.GET)
	public @ResponseBody Repository getRepositoryById(@RequestParam(value = "id", required = true) String id) {
		// validateUser();

		Repository repository = null;
		for (Repository rep: repositories.values()){
			if (rep.getId().equals(id)){
				return rep;
			}
		}
		repository = consumer.getRepositoryById(id, ComponentConfig.getConfig().getDbRepositoryByIdUrl());

		// Testing repository validation
		if (repository.getName().isEmpty() || repository.getId().isEmpty() || repository.getTypeId().isEmpty() ) {
			throw new NotAccessibleRepositoryException("with id "+id);
		}

		// Checking if it's accessible or throw exception. If accessible add to
		// cache and return it
		try {
			repository = consumer.getRepository(repository, ComponentConfig.getConfig().getInputRepositoryUrl());
		} catch (Exception e) {
			this.repositories.remove(repository.getName());
			throw new NotAccessibleRepositoryException(repository.getName());
		}
		this.repositories.put(repository.getName(), repository);
		return repository;
	}

	@RequestMapping(value = "/repositories", method = RequestMethod.GET)
	public @ResponseBody Collection<Repository> getRepositories() {
		// validateUser();
		List<Repository> result = consumer.getRepositories(ComponentConfig.getConfig().getDbRepositoriesUrl());
		for (Repository repo : result) {
			repositories.put(repo.getName(), repo);
		}

		if (result == null || result.size() == 0) {
			return new ArrayList<Repository>();
		}
		return result;
	}

	@RequestMapping(value = "/newTypeSettableAttributes", method = RequestMethod.GET)
	/**
	 * A class that gets a NewTypeSettableAttributes from the DDBB
	 * 
	 * @param id
	 * @return
	 */
	public @ResponseBody NewTypeSettableAttributes getNewTypeSettableAttributes(@RequestParam String id) {
		// validateUser();

		// EventHandler.getHandler().preEvent(repository);
		return consumer.getNewTypeSettableAttributes(id,
				ComponentConfig.getConfig().getDbNewTypeSettableAttributesUrl());

		// EventHandler.getHandler().postEvent(repository);
		// throw new AddNewTypeSettableAttributesOkException(newType.getId());
	}

	@RequestMapping(value = "/newTypeSettableAttributes", method = RequestMethod.POST)
	/**
	 * A class that saves a NewTypeSettableAttributes to the DDBB
	 * 
	 * @param creatablePropertyTypes
	 * @return
	 */
	public @ResponseBody NewTypeSettableAttributes newTypeSettableAttributes(
			@RequestParam(value = "repositoryid", required = true) String repositoryId,
			//Passes as @RequestBody for complexity param
			@RequestBody NewTypeSettableAttributes newTypeSettableAttributes)
					throws AlreadyExistingNewTypeSettableAttributesException {
		// validateUser();

		// EventHandler.getHandler().preEvent(repository);
		return newTypeSettableAttributes = consumer.setNewTypeSettableAttributes(newTypeSettableAttributes,
				ComponentConfig.getConfig().getDbNewTypeSettableAttributesUrl());

		// EventHandler.getHandler().postEvent(repository);
		// throw new AddNewTypeSettableAttributesOkException(newType.getId());
	}

	@RequestMapping(value = "/typechildren", method = RequestMethod.GET)
	public @ResponseBody Collection<ObjectType> getTypeChildren(
			@RequestParam(value = "repositoryName", required = true) String repositoryName,
			@RequestParam(value = "typeid", required = true) String typeId) {
		// validateUser();
		List<ObjectType> result = consumer.getTypeChildren(repositoryName, typeId,
				ComponentConfig.getConfig().getDbTypeChildrenUrl());
		return result;
	}

	@RequestMapping(value = "/propertydefinition", method = RequestMethod.GET)
	public @ResponseBody <T> PropertyDefinition<T> getPropertyDefinition(
			@RequestParam(value = "id", required = true) String id) {
		PropertyDefinition<T> result = null;
		result = consumer.getPropertyDefinition(id, ComponentConfig.getConfig().getDbPropertyDefinitionUrl());
		return result;

	}
}
