package com.libreecm.opencmis.consumers;

import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.libreecm.commonAPI.auxiliars.exceptions.ErrorConsumingRESTException;
import com.libreecm.commonAPI.auxiliars.exceptions.ErrorReadingStreamException;
import com.libreecm.commonAPI.auxiliars.exceptions.ErrorWrittingStreamException;
import com.libreecm.commonAPI.model.objects.LibreECMDataObject;
import com.libreecm.commonAPI.model.objects.ObjectType;
 
public class ObjectConsumer {

	RestTemplate restTemplate = new RestTemplate();
	ObjectMapper mapper = new ObjectMapper();

	HashMap<String, LibreECMDataObject> cache = new HashMap<>();

	public ObjectConsumer() {
	}

	/**
	 * A class that returns a Object from the Repository from it's URI as id
	 * 
	 * @param id
	 * 
	 * @return
	 */
	public LibreECMDataObject getObject(String objectId, String filter, Boolean includeAllowableActions,
			com.libreecm.commonAPI.model.enums.IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
			Boolean includeAcl, //ExtensionDataImpl extension, 
			String url) {

		LibreECMDataObject object = null;
		if (cache.containsKey(objectId))
			return cache.get(objectId);
		try {

			object = restTemplate
					.getForObject(
							url + "?id=" + objectId + "&filter=" + filter + "&includeAllowableActions="
									+ includeAllowableActions + "&includeRelationships=" + includeRelationships
									+ "&renditionFilter=" + renditionFilter + "&includePolicyIds=" + includePolicyIds
									+ "&includeAcl=" + includeAcl,
									//TODO Bug here, it cannot be passed to JSON
									//+ "&extension=" + extension,
							LibreECMDataObject.class);

			cache.put(objectId, (object));
		} catch (HttpClientErrorException e) {
			throw new ErrorConsumingRESTException(url);
		}
		return (object);
	}

	public LibreECMDataObject setObject(String repositoryId, LibreECMDataObject object, String filter,
			Boolean includeAllowableActions, com.libreecm.commonAPI.model.enums.IncludeRelationships includeRelationships, String renditionFilter,
			Boolean includePolicyIds, Boolean includeAcl, //ExtensionDataImpl extension, 
			String url) {
		LibreECMDataObject result = null;
		try {
			result = restTemplate.postForObject(
					url + "?id=" + object.getId() + "&repositoryId=" + repositoryId + "&filter=" + filter
							+ "&includeAllowableActions=" + includeAllowableActions
							+ "&includeRelationships=" + includeRelationships + "&renditionFilter=" + renditionFilter
							+ "&includePolicyIds=" + includePolicyIds + "&includeAcl="
							+ includeAcl,
							//TODO Bug here, it cannot be passed to JSON
							//+ "&extension=" + extension, + "&extension=" + extension,
					object, LibreECMDataObject.class);
			cache.put(object.getId(), object);
		} catch (HttpClientErrorException e) {
			throw new ErrorConsumingRESTException(url);
		}
		return result;
	}

	public ObjectType getObjectType(String id, String repositoryName, String url) {
		ObjectType result = null;
		try {
			result = restTemplate.getForObject(url + "?id=" + id + "&repositoryname=" + repositoryName,
					ObjectType.class);
		} catch (HttpClientErrorException e) {
			throw new ErrorConsumingRESTException(url);
		}
		return result;
	}
	
	
	public boolean doUpload(String documentUri, MultipartFile file, String url) {
		if (file == null) {
			throw new ErrorReadingStreamException(" error reading file: " + documentUri);
		}
		try {
			// It's necessary for sending multiparfile to add
			// formhttpmessageconverter to resttemplate
			FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
			formConverter.setCharset(Charset.forName("UTF8"));
			restTemplate.getMessageConverters().add(formConverter);
			restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

			restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

			HttpHeaders httpHeaders = new HttpHeaders();
			httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType("application/json")));

			return restTemplate.postForObject(url + "?documenturi=" + documentUri, file, Boolean.class);
		} catch (Exception e) {
			throw new ErrorWrittingStreamException(" error reading file: " + documentUri);
		}

	}

	public List<LibreECMDataObject> getChildrenObjects(String folderId, String filter,
			String orderBy, Boolean includeAllowableActions, com.libreecm.commonAPI.model.enums.IncludeRelationships includeRelationships,
			String renditionFilter, Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount,
			//ExtensionDataImpl extensions, 
			String url) {

		List<LibreECMDataObject> result = null;
		
		try {
			result = restTemplate
					.getForObject(
							url + "?id=" + folderId + "&filter=" + filter+ "&orderby=" + orderBy + "&includeAllowableActions="
									+ includeAllowableActions + "&includeRelationships=" + includeRelationships
									+ "&renditionFilter=" + renditionFilter 
									+"&includepathsegment="+includePathSegment+"&maxitems="+maxItems+"&skipcount="+skipCount
									//TODO Bug here, it cannot be passed to JSON
									//+ "&extension=" + extension,+ "&extension=" + extensions
									, List.class);
			List<LibreECMDataObject> pojos = mapper.convertValue(result, new TypeReference<ArrayList<LibreECMDataObject>>() { });
			
			for (LibreECMDataObject object: pojos) {
				cache.put(object.getId(), (object));
			}
			return pojos;
		} catch (HttpClientErrorException e) {
			throw new ErrorConsumingRESTException(url);
		}
	}	
	
	public ByteArrayResource doDownload(String documentUri, Integer offset,
            Integer length, String url) {

		ByteArrayResource result = null;
		try {

			// Prepare acceptable media type
			HttpHeaders httpHeaders = new HttpHeaders();
			
			httpHeaders.setAccept(Collections.singletonList((MediaType.ALL)));
		   // Send the request as GET
			result = restTemplate.getForObject(url + "?documenturi=" + documentUri+ 
												"&offset="+offset+"&length="+length
												, ByteArrayResource.class);
		} catch (Exception e) {
			throw new ErrorConsumingRESTException(url);
		}
		return result;
	}
	
}