package br.mp.mprj.portal.portlet.gestaomensagens.util;

import java.awt.image.RenderedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;

import com.liferay.portal.NoSuchImageException;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.image.ImageBag;
import com.liferay.portal.kernel.image.ImageToolUtil;
import com.liferay.portal.kernel.repository.model.FileEntry;
import com.liferay.portal.kernel.repository.model.Folder;
import com.liferay.portal.kernel.upload.UploadPortletRequest;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.MimeTypesUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.service.ServiceContext;
import com.liferay.portal.service.ServiceContextFactory;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.portlet.documentlibrary.NoSuchFolderException;
import com.liferay.portlet.documentlibrary.model.DLFolder;
import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
import com.liferay.portlet.documentlibrary.util.DLUtil;
import com.liferay.util.portlet.PortletProps;

/**
 * Classe utilit&aacute;ria para auxiliar no tratamento das imagens enviadas pelo portlet.
 * @author Henrique Simoes
 *
 */
public class ImagemUtil {
	
	/**
	 * Express&atilde;o regular para ser utilizado na exclus&atilde;o da extens&atilde;o do nome do arquivo.
	 */
	public static final String EXPR_EXTENSAO = "(\\.*[\\w]*)$";
	
	private static final String MIME_APPLICATION = "application/octet-stream";
	
	/**
	 * Nome do atributo que cont&eacute;m o ID da pasta principal de imagem.
	 */
	public static final String ATRIBUTO_PASTA_PRINCIPAL_ID = "PORTLET_PASTA_PRINCIPAL_ID"; 
	
	/**
	 * Descri&ccedil;&atilde;o da pasta principal do portlet na galeria de imagens.
	 */
	public static final String DESCRICAO_PASTA_PRINCIPAL = GetterUtil.getString(PortletProps.get("descricao-pasta-principal-imagens"));
	
	/**
	 * Nome da pasta principal do portlet na galeria de imagens.
	 */
	public static final String PASTA_IMAGENS_PRINCIPAL = GetterUtil.getString(PortletProps.get("nome-pasta-principal-imagens"));
	
	/**
	 * URI para exibi&ccedil;&atilde;o das imagens do Documentos e Midias.
	 */
	public static final String URI_IMAGEM = GetterUtil.getString(PortletProps.get("url-imagem"));
	
	/**
	 * Lagura da imagem normal (visualiza&ccedil;&atilde;o na vers&atilde;o maior). 
	 */
	public static final int IMAGEM_LARGURA = GetterUtil.getInteger(PortletProps.get("imagem-largura"));
	
	/**
	 * Largura da imagem normal (visualiza&ccedil;&atilde;o da vers&atilde;o maior).
	 */
	public static final int IMAGEM_ALTURA = GetterUtil.getInteger(PortletProps.get("imagem-altura"));
	
	private final UploadPortletRequest upReq;
	private final ServiceContext serviceContext;
	private final long userId;
	private final long groupId;
	public final long idPastaPrincipal;
	private final PortletRequest request;
	
	public ImagemUtil(long groupId, long userId, PortletRequest req, UploadPortletRequest upReq) 
			throws SystemException, PortalException {
		this.upReq = upReq;
		this.userId = userId;
		this.groupId = groupId;
		this.serviceContext = getServiceContext(req);
		this.idPastaPrincipal = pesquisarPastaPrincipal(req.getPortletSession());
		this.request = req;
	}
	
	public ImagemUtil(long groupId, long userId, PortletRequest req)
			throws SystemException, PortalException {
		this.upReq = null;
		this.userId = userId;
		this.groupId = groupId;
		this.serviceContext = getServiceContext(req);
		this.idPastaPrincipal = pesquisarPastaPrincipal(req.getPortletSession());
		this.request = req;
	}
	
	private ServiceContext getServiceContext(PortletRequest req) 
			throws SystemException, PortalException {
		ServiceContext sc = ServiceContextFactory.getInstance(DLFolder.class.getName(), req);
		sc.setAddGroupPermissions(true);
		sc.setAddGuestPermissions(true);
		return sc;
	}	
	
	/**
	 * Criar uma imagem no Documentos e Mídias
	 * @param folderId - id da pasta
	 * @param nome - nome da imagem
	 * @param descricao - descri&ccedil;&atilde;o
	 * @param arquivo - objeto representando a imagem fisicamente no servidor
	 * @param nomeCampoUpload - nome do campo na página de upload
	 * @return IGFile
	 * @throws SystemException
	 * @throws PortalException
	 */
	public FileEntry criarImagem(long folderId, String nome, String descricao, File arquivo, String nomeCampoUpload)
			throws SystemException, PortalException {
		return DLAppLocalServiceUtil.addFileEntry(userId, 
				groupId, 
				folderId, 
				arquivo.getName(), 
				getContentTypeImage(upReq, arquivo, nomeCampoUpload), 
				nome, 
				descricao, 
				StringPool.BLANK, 
				arquivo, 
				serviceContext);
	}
	
	/**
	 * Criar uma imagem no Documentos e Mídias (redimensionado)
	 * @param folderId - id da pasta
	 * @param nome - nome da imagem
	 * @param descricao - descri&ccedil;&atilde;o
	 * @param arquivo - objeto representando a imagem fisicamente no servidor
	 * @param nomeCampoUpload - nome do campo na p&aacute;gina de upload
	 * @param altura - tamanho em pixels para a altura
	 * @param largura - tamanho em pixeis para a largura
	 * @return IGFile
	 * @throws SystemException
	 * @throws PortalException
	 */
	public FileEntry criarImagem(long folderId, String nome, String descricao, File arquivo, String nomeCampoUpload, int altura, int largura)
			throws SystemException, PortalException {
		String contentType = getContentTypeImage(upReq, arquivo, nomeCampoUpload); 
		return DLAppLocalServiceUtil.addFileEntry(userId, 
				groupId, 
				folderId, 
				arquivo.getName(), 
				getContentTypeImage(upReq, arquivo, nomeCampoUpload), 
				nome, 
				descricao, 
				StringPool.BLANK, 
				redimensionarImagem(arquivo, altura, largura, contentType), 
				serviceContext);	
	}
	
	/**
	 * Criar uma imagem no Documentos e Mídias com base em uma outra j&aacute; existe na galeria, criando uma vers&atilde;o com novas dimens&otilde;es.
	 * @param idImgOriginal
	 * @param sufixo - sufixo do novo arquivo.
	 * @param altura
	 * @param largura
	 * @return
	 * @throws SystemException
	 * @throws PortalException
	 * @throws IOException
	 */
	public FileEntry criarImagem(long idImgOriginal, String sufixo, int altura, int largura)
			throws SystemException, PortalException, IOException {
		return criarImagem(DLAppLocalServiceUtil.getFileEntry(idImgOriginal), sufixo, altura, largura);
	}
	
	/**
	 * Criar uma imagem no Documentos e Mídias com base em uma outra j&aacute; existe na galeria, criando uma vers&atilde;o com novas dimens&otilde;es.
	 * @param imgOriginal
	 * @param sufixo - sufixo do novo arquivo.
	 * @param altura
	 * @param largura
	 * @return
	 * @throws SystemException
	 * @throws PortalException
	 * @throws IOException
	 */
	public FileEntry criarImagem(FileEntry imgOriginal, String sufixo, int altura, int largura)
			throws SystemException, PortalException, IOException {
		//carregar a imagem original e gerar a nova resolução.
		InputStream isImage = imgOriginal.getLatestFileVersion().getContentStream(true);
		ImageBag bag = ImageToolUtil.read(isImage);
		RenderedImage ri = ImageToolUtil.scale(bag.getRenderedImage(), altura, largura);
		
		//utilizar expressao regulrar para substituir todo o texto e manter o conteúdo a partir do ponto,
		//para extrair a extensao.
		String extensao = StringPool.PERIOD.concat(imgOriginal.getExtension());
		
		String nome = imgOriginal.getTitle().replace(extensao, StringPool.BLANK).concat(sufixo).concat(extensao);
		
		try {
			isImage.close();
		}
		catch (IOException ex){}
		
		//criar a imagem na galeria de imagens do portal.
		return DLAppLocalServiceUtil.addFileEntry(userId, 
				groupId, 
				imgOriginal.getFolderId(), 
				nome, 
				MimeTypesUtil.getContentType(nome), 
				nome, 
				imgOriginal.getDescription(), 
				StringPool.BLANK, 
				ImageToolUtil.getBytes(ri, bag.getType()), 
				serviceContext);					
	}
	
	/**
	 * Criar uma imagem no Documentos e Mídias informando o contentType
	 * @param folderId - id da pasta
	 * @param nome - nome da imagem
	 * @param descricao - descri&ccedil;&atilde;o
	 * @param arquivo - objeto representando a imagem fisicamente no servidor
	 * @param contentType - tipo de conteudo do arquivo
	 * @return IGFile
	 * @throws SystemException
	 * @throws PortalException
	 */	
	public FileEntry criarImagemContentType(long folderId, String nome, String descricao, File arquivo, String contentType)
			throws SystemException, PortalException {
		return DLAppLocalServiceUtil.addFileEntry(userId, 
													groupId, 
													folderId, 
													arquivo.getName(), 
													contentType, 
													nome, 
													descricao, 
													StringPool.BLANK, 
													arquivo, 
													serviceContext);
	}
	
	
	/**
	 * Retornar o tipo de conte&uacute;do do arquivo.
	 * @param uploadRequest
	 * @param file
	 * @param nomeCampoFile
	 * @return
	 */
	private String getContentTypeImage(UploadPortletRequest uploadRequest, File file, String nomeCampoFile) {

		String contentType = GetterUtil.getString(uploadRequest.getContentType(nomeCampoFile));

		if (contentType.equals(MIME_APPLICATION)) {
			String ext = GetterUtil.getString(FileUtil.getExtension(file.getName())).toLowerCase();

			if (Validator.isNotNull(ext)) {
				contentType = MimeTypesUtil.getContentType(ext);
			}
		}

		return contentType;
	}
	
	/**
	 * Verifica se a pasta de imagens existe (pesquisando pelo nome na pasta principal informada), caso contr&aacute;rio, 
	 * ser&aacute; criada de acordo com as informa&ccedil;&otilde;es dos par&acirc;metros.
	 * @param groupId
	 * @param pastaPrincipalId - id da pasta principal (pai) onde ser&aacute; feita a pesquisa/cria&ccedil;&atilde;o
	 * @param nomePasta - nome da pasta a ser pesquisada/criada
	 * @param titulo - descri&ccedil;&atilde;o da pasta caso haja necessidade de ser criada
	 * @return Folder
	 * @throws PortalException
	 * @throws SystemException
	 */
	public Folder verificarPastaImagens(long pastaPrincipalId, String nomePasta, String titulo)
			throws PortalException, SystemException {
		return verificarPastaImagens(pastaPrincipalId, nomePasta, titulo, serviceContext);
	}
	
	/**
	 * Verifica se a pasta de imagens existe (pesquisando pelo nome na pasta principal informada), caso contr&aacute;rio, 
	 * ser&aacute; criada de acordo com as informa&ccedil;&otilde;es dos par&acirc;metros.
	 * @param groupId
	 * @param pastaPrincipalId - id da pasta principal (pai) onde ser&aacute; feita a pesquisa/cria&ccedil;&atilde;o
	 * @param nomePasta - nome da pasta a ser pesquisada/criada
	 * @param titulo - descri&ccedil;&atilde;o da pasta caso haja necessidade de ser criada
	 * @param serviceContext
	 * @return Folder
	 * @throws PortalException
	 * @throws SystemException
	 */
	public Folder verificarPastaImagens(long pastaPrincipalId, String nomePasta, String titulo, ServiceContext serviceContext)
			throws PortalException, SystemException {
		try {
			return DLAppLocalServiceUtil.getFolder(groupId, pastaPrincipalId, nomePasta);
		}
		catch (NoSuchFolderException ex) {
			//return FolderServiceUtil.addFolder(pastaPrincipalId, nomePasta, titulo, serviceContext);
			return DLAppLocalServiceUtil.addFolder(userId, groupId, pastaPrincipalId, nomePasta, titulo, serviceContext);
		}
	}	
	

	/**
	 * Pesquisar o ID da pasta principal das imagens do portlet no Documentos e Mídias.
	 * @return Folder
	 */
	private long pesquisarPastaPrincipal(PortletSession session) throws SystemException {
		try {
			Long idPasta = (Long)session.getAttribute(ATRIBUTO_PASTA_PRINCIPAL_ID, PortletSession.PORTLET_SCOPE);
			if (idPasta == null) {
				Folder pasta = null;
				try {
					pasta = DLAppLocalServiceUtil.getFolder(groupId, 0L, PASTA_IMAGENS_PRINCIPAL);
				}
				catch (NoSuchFolderException ex) {
					pasta = DLAppLocalServiceUtil.addFolder(userId, groupId, 0L, PASTA_IMAGENS_PRINCIPAL, DESCRICAO_PASTA_PRINCIPAL, serviceContext);
				}
				idPasta = pasta.getFolderId();
				session.setAttribute(ATRIBUTO_PASTA_PRINCIPAL_ID, idPasta, PortletSession.PORTLET_SCOPE);
			}
			return idPasta;
		}
		catch (PortalException ex) {
			throw new SystemException("Pasta principal das imagens não encontrada!", ex);
		}		
	}
	
	/**
	 * Redimensionar a imagem. Tipos suportados: GIF, JPG/JPEG, PNG.
	 * @param fileImg - arquivo contendo a imagem
	 * @param altura - altura m&aacute;xima em pixels
	 * @param largura - lagura m&aacute;xima em pixels
	 * @param contentType - tipo de conte&uacute;do do arquivo (JPG, GIF, etc)
	 * @return ByteArrayMaker
	 */
	public byte[] redimensionarImagem(File arqImg, int altura, int largura, String contentType) 
			throws SystemException {
		try {
			RenderedImage ri = ImageToolUtil.read(arqImg).getRenderedImage();
			RenderedImage riThumb = ImageToolUtil.scale(ri, altura, largura);
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			if (contentType.indexOf("jpg") != -1 ||
					 contentType.indexOf("jpeg") != -1) {
				ImageIO.write(riThumb, "jpeg", baos);
			}
			else if (contentType.indexOf("png") != -1) {
				ImageIO.write(riThumb, "png", baos);
			}
			
			return baos.toByteArray();
		}
		catch (Exception ex) {
			throw new SystemException(ex);
		}
	}
	
	/**
	 * Excluir a imagem da galeria de imagens do Liferay.
	 * @param imageId
	 * @throws SystemException
	 * @throws PortalException
	 */
	public void removerImagem(long imageId) throws SystemException, PortalException {
		try {
			DLAppLocalServiceUtil.deleteFileEntry(imageId);
		}
		catch (NoSuchImageException ex) {} //ignora a exception de imagem não encontrada
	}	
	
	/**
	 * Busca a imagem por nome no diret&oacute;rio especificado.
	 * @param groupId
	 * @param folderId
	 * @param nome - nome do arquivo a ser pesquisado no Documentos e Midias.
	 * @return FileEntry
	 * @throws SystemException
	 * @throws PortalException
	 */
	public FileEntry getArquivoPorNome(long groupId, long folderId, String nome) throws SystemException, PortalException {
		return DLAppLocalServiceUtil.getFileEntry(groupId, folderId, nome);
	}	
	
	/**
	 * Cria a URL para exibi&ccedil;&atilde;o da imagem na galeria de imagens do Liferay.
	 * @param imagem - objeto imagem a ser criada a URL.
	 * @param urlBaseImagem - url base para acessar a imagem
	 * @return String
	 */
	public String criarUrlImagem(FileEntry imagem, String urlBaseImagem) 
			throws SystemException, PortalException {
		ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
		return DLUtil.getPreviewURL(imagem, 
									imagem.getFileVersion(), 
									themeDisplay, 
									StringPool.BLANK, 
									false, 
									false);
	}
	
	/**
	 * Cria a URL para exibi&ccedil;&atilde;o da imagem na galeria de imagens do Liferay.
	 * Utilizando como URI base o valor definido na propriedade url-imagem do portlet.properties.
	 * @param imagem - objeto imagem a ser criada a URL.
	 * @return String
	 */
	public String criarUrlImagem(FileEntry imagem) 
			throws SystemException, PortalException {
		return criarUrlImagem(imagem, URI_IMAGEM);
	}
	
	/**
	 * Retorna o ID (folderId) da pasta principal de imagens do portlet no Documentos e M&iacute;dias.<br>
	 * Este ID &eacute; definido construtor desta classe utilit&aacute;ria.
	 * @return long - folderId
	 */
	public long getIdPastaPrincipal() {
		return idPastaPrincipal;
	}
	
	/**
	 * Retorna a URL da imagem de thumbnail do template. <br>
	 * Caso n&atilde;o encontre, retorna a URL padrao, verificando as prefer&ecirc;ncias do portlet e <br> 
	 * em seguida o arquivo portlet.properties.
	 * @param req - {@link PortletRequest} para obter as preferências do portlet.
	 * @param urlImagem - URL da imagem. Pode ser vazio ou nulo, neste caso tenta obter 
	 * a URL padr&atilde;o de acordo com as prefer&ecirc;ncias do portlet.
	 * @return String
	 */
	public static String getUrlThumbnailTemplate(PortletRequest req, String urlImagem) {
		if (Validator.isNotNull(urlImagem)) {
			return urlImagem;
		}
		PortletPreferences prefs = req.getPreferences();
		return req.getContextPath() + GetterUtil.getString(prefs.getValue("template.url.thumbnail-padrao", PortletProps.get("configuracao.template.url.thumbnail-padrao")));
	}

}
