package com.libreecm.consumers;

import java.io.InputStream;
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 javax.servlet.http.HttpServletResponse;

import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.xstream.XStreamMarshaller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
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.CmisExtensionElement;
import com.libreecm.commonAPI.model.Repository;
import com.libreecm.commonAPI.model.objects.ExtensionDataImpl;
import com.libreecm.commonAPI.model.objects.ExtensionsData;
import com.libreecm.commonAPI.model.enums.IncludeRelationships;
import com.libreecm.commonAPI.model.objects.LibreECMDataObject;
import com.libreecm.commonAPI.model.objects.ObjectType;
import com.libreecm.commonAPI.model.objects.Uri;

@SuppressWarnings("unused")
public class ObjectConsumer {

	RestTemplate restTemplate ;
	ObjectMapper mapper ;
	HashMap<String,LibreECMDataObject> cache;

	public ObjectConsumer() {
		restTemplate= new RestTemplate();
		mapper=new ObjectMapper();
		cache=new HashMap<>();
	}

	/**
	 * Reads an object from the Repository
	 * 
	 * @param id
	 * @param url
	 * @return object read
	 */
	public LibreECMDataObject getObject(String objectPath, String filter, Boolean includeAllowableActions,
			IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
			Boolean includeAcl, //ExtensionDataImpl extension, 
			String url) {

		LibreECMDataObject object = null;
		try {
			object = restTemplate
					.getForObject(
							url + "?id=" + objectPath + "&filter=" + filter + "&includeAllowableActions="
									+ includeAllowableActions + "&includeRelationships=" + includeRelationships
									+ "&renditionFilter=" + renditionFilter + "&includePolicyIds=" + includePolicyIds
									+ "&includeAcl=" + includeAcl,
									//TODO Bug here, cannot convert to Json
									// + "&extension=" + extension,
							LibreECMDataObject.class);
				
		} catch (Exception e) {
			throw new ErrorConsumingRESTException(url + "?id=" + objectPath + "&filter=" + filter + "&includeAllowableActions="
					+ includeAllowableActions + "&includeRelationships=" + includeRelationships
					+ "&renditionFilter=" + renditionFilter + "&includePolicyIds=" + includePolicyIds
					+ "&includeAcl=" + includeAcl
					// + "&extension=" + extension
					);
		}

		return object;
	}

	public LibreECMDataObject setObject(LibreECMDataObject object, String filter, Boolean includeAllowableActions,
			IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
			Boolean includeAcl, //ExtensionDataImpl extension, 
			String url) {
		try {
			return restTemplate.postForObject(url + "?id=" + object.getId() +
			"&filter=" + filter + "&includeAllowableActions=" + includeAllowableActions.compareTo(false)
					+ "&includeRelationships=" + includeRelationships.toString() + "&renditionFilter=" + renditionFilter
					+ "&includePolicyIds=" + includePolicyIds.compareTo(false) + "&includeAcl="
					+ includeAcl.compareTo(false),
					//TODO Bug here, cannot convert to Json
					//  + "&extension=" + extension,
					object, LibreECMDataObject.class);
		} catch (HttpClientErrorException e) {
			throw new ErrorConsumingRESTException(url);
		}
	}

	public ObjectType getObjecType(String id, String repositoryName, String url) {
		try {
			return restTemplate.getForObject(url+"?id="+id+"&repositoryname="+repositoryName, ObjectType.class);
		} catch (HttpClientErrorException e){
			throw new ErrorConsumingRESTException(url+"?id="+id+"&repositoryname="+repositoryName);
		}
	}

	public List<LibreECMDataObject> getChildrenObjects(String folderId, String filter,
			String orderBy, Boolean includeAllowableActions, 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
									+ "&extension=",
									//TODO Bug here, cannot convert to Json
									//  + 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;
	}

	public String doUpload(String documentUri, ByteArrayResource bytes,
			BigInteger offset, BigInteger length, String url) {
		
		try {	

			// Prepare acceptable media type
			HttpHeaders httpHeaders = new HttpHeaders();
			
			httpHeaders.setAccept(Collections.singletonList((MediaType.ALL)));
		   // Send the request as POST
			String result = restTemplate.postForObject(url + "?documenturi=" + documentUri+ 
												"&offset="+offset+"&length="+length, bytes,
												String.class);
			return result;
		} catch (Exception e) {
			throw new ErrorWrittingStreamException(" error reading file: " + documentUri);
		}
	}

}
