package com.libreecm.input.controllers;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.MediaType;
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.model.objects.Document;
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;
import com.libreecm.commonAPI.auxiliars.exceptions.ErrorConsumingRESTException;
import com.libreecm.commonAPI.auxiliars.exceptions.ErrorWrittingStreamException;
import com.libreecm.commonAPI.auxiliars.exceptions.NotExistingObjectStreamException;
import com.libreecm.commonAPI.model.enums.BaseTypeId;
import com.libreecm.input.auxiliars.Mapper;
import com.libreecm.input.auxiliars.RepositoryCreator;
import com.libreecm.input.repositoriesImpl.RepositoryImpl;

@RestController
public class ObjectController extends BaseController {

	@RequestMapping(value = "/object", method = RequestMethod.POST)
	/**
	 * A class that saves an Object to the repository
	 * 
	 * @param object
	 * @return
	 */
	public void addObject(@RequestBody LibreECMDataObject object,
			@RequestParam(value = "path", required = true) String path,
			@RequestParam(value = "filter", required = false) String filter,
			@RequestParam(value = "includeAllowableActions", required = false) boolean includeAllowableActions,
			@RequestParam(value = "includeRelationships", required = false) IncludeRelationships includeRelationships,
			@RequestParam(value = "renditionFilter", required = false) String renditionFilter,
			@RequestParam(value = "includePolicyIds", required = false) boolean includePolicyIds,
			@RequestParam(value = "includeAcl", required = false) boolean includeAcl
	// @RequestParam(value = "extension", required = false) ExtensionDataImpl
	// extension
	) {
		// validateUser();
		// TODO: AddExtension
		Uri objectUri = Uri.parse(path);
		// EventHandler.getHandler().preEvent(object);

		// EventHandler.getHandler().postEvent(obj);
		RepositoryCreator.get().getRepository(objectUri.getRepositoryName()).setObject(object, objectUri);
		// throw new AddObjectOkException(objectId);
	}

	/**
	 * A class that returns a Object from the Repository from it's URI as id
	 * 
	 * @param id
	 * 
	 * @return
	 */
	@RequestMapping(value = "/object", method = RequestMethod.GET)
	public @ResponseBody LibreECMDataObject getObject(@RequestParam(value = "id", required = true) String objectPath,
			@RequestParam(value = "filter", required = false) String filter,
			@RequestParam(value = "includeAllowableActions", required = false) boolean includeAllowableActions,
			@RequestParam(value = "includeRelationships", required = false) IncludeRelationships relationships,
			@RequestParam(value = "renditionFilter", required = false) String renditionFilter,
			@RequestParam(value = "includePolicyIds", required = false) boolean includePolicyIds,
			@RequestParam(value = "includeAcl", required = false) boolean includeAcl
	// @RequestParam(value = "extension", required = false) ExtensionDataImpl
	// extension
	) {
		// validateUser();
		Uri path = Uri.parse(objectPath);

		// TODO: Add Extensions
		
		RepositoryImpl repository = RepositoryCreator.get().getRepository(path.getRepositoryName());
		LibreECMDataObject object = repository.getObject(path);

		if (!includeAllowableActions)
			object.setAllowableActions(null);

		object.setRelationships(Mapper.filterRelationships(object.getRelationships(), relationships, object.getId()));

		object.setRenditions(Mapper.filterRenditions(object.getRenditions(), renditionFilter, object.getId()));

		if (!includePolicyIds)
			object.setPolicyIds(null);

		if (!includeAcl)
			object.setAcl(null);
		return object;
	}

	@RequestMapping(value = "/downloadcontent", method = RequestMethod.GET, produces = MediaType.ALL_VALUE)
	public ByteArrayResource doDownload(@RequestParam("documenturi") String documentUri,
			@RequestParam("offset") Integer offset, @RequestParam("length") Integer length) throws IOException {

		Uri uri = Uri.parse(documentUri);

		RepositoryImpl repository = RepositoryCreator.get().getRepository((uri.getRepositoryName()));
		Document object = repository.getDocument(uri);

		File file = new File(object.getPath());
		byte[] bytes = new byte[length];
		FileInputStream stream;
		try{
			stream = new FileInputStream(file);
			
			stream.read(bytes, offset, length);
		
		} catch (Exception e) {
			throw new ErrorConsumingRESTException(documentUri);
		}

		stream.close();
		return new ByteArrayResource(bytes);
	}

	@RequestMapping(method = RequestMethod.POST, value = "/uploadcontent")
	public String upload(@RequestParam("documenturi") String documentUri,
			@RequestParam("offset") BigInteger offset, @RequestParam("length") BigInteger length,
			@RequestBody ByteArrayResource bytes) {
		Uri uri = Uri.parse(documentUri);
		RepositoryImpl repository = RepositoryCreator.get().getRepository(uri.getRepositoryName());

		Document document = repository.getDocument(uri);

		if (!document.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT.value())) {
			throw new NotExistingObjectStreamException(documentUri);
		}
		File file  = new File(document.getPath());
		FileOutputStream stream=null;
		try {
			 stream = new FileOutputStream(file);
			 if ((offset != null && offset.longValue() > 0) || length != null) {
			       stream.write(bytes.getByteArray(), offset.intValueExact(), length.intValueExact());
			 }  else {
			      stream.write(bytes.getByteArray());
			 }   
		} catch (Exception e) {
			throw new ErrorWrittingStreamException("Error writting file: " + documentUri);
		}
		finally
		{
			try {
				stream.close();
			} catch (IOException e) {
			}
		}
			
		return "redirect:/";

	}

	@RequestMapping(value = "/objecttype", method = RequestMethod.GET)
	/**
	 * A class that gets a object type from the repository
	 * 
	 * @param object
	 *            type
	 * @param id
	 * @return
	 */
	public @ResponseBody ObjectType getObjectType(@RequestParam(value = "id", required = true) String id,
			@RequestParam(value = "repositoryname", required = true) String repositoryName) {
		// validateUser();
		RepositoryImpl repository = RepositoryCreator.get().getRepository(repositoryName);
		return repository.getObjectType(id);
	}

	/**
	 * Returns a list of object children from a folder. It admits some filters
	 * 
	 * @param folderId
	 * @param filter
	 * @param orderBy
	 * @param includeAllowableActions
	 * @param includeRelationships
	 * @param renditionFilter
	 * @param includePathSegment
	 * @param maxItems
	 * @param skipCount
	 * @param extension
	 * @return
	 */
	@RequestMapping(value = "/objectsinfolder", method = RequestMethod.GET)
	public @ResponseBody Collection<LibreECMDataObject> getObjectsInFolder(
			@RequestParam(value = "id", required = true) String folderId,
			@RequestParam(value = "filter", required = false) String filter,
			@RequestParam(value = "orderby", required = false) String orderBy,
			@RequestParam(value = "includeAllowableActions", required = false) Boolean includeAllowableActions,
			@RequestParam(value = "includeRelationships", required = false) IncludeRelationships includeRelationships,
			@RequestParam(value = "renditionFilter", required = false) String renditionFilter,
			@RequestParam(value = "includepathsegment", required = false) Boolean includePathSegment,
			@RequestParam(value = "maxitems", required = false) BigInteger maxItems,
			@RequestParam(value = "skipcount", required = false) BigInteger skipCount
	// @RequestParam(value = "extension", required = false)ExtensionDataImpl
	// extension
	) {
		// validateUser();
		List<LibreECMDataObject> result = new ArrayList<>();
		Uri uri = Uri.parse(folderId);
		RepositoryImpl repository = RepositoryCreator.get().getRepository(uri.getRepositoryName());

		result = repository.getChildren(folderId);
		if (result == null || result.size() == 0) {
			return new ArrayList<LibreECMDataObject>();
		}
		return result;
	}

}