package lu.tudor.santec.gecamed.esante.gui.worker;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

import javax.persistence.Transient;

import lu.tudor.santec.gecamed.core.gui.plugin.filehandler.FileOpener;
import lu.tudor.santec.gecamed.core.utils.FileUtils;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.esante.ejb.entity.beans.CdaDocument;
import lu.tudor.santec.gecamed.esante.ejb.entity.beans.Dsp;
import lu.tudor.santec.gecamed.esante.ejb.session.beans.CDAManagerBean;
import lu.tudor.santec.gecamed.esante.gui.utils.ESanteGuiUtils;
import lu.tudor.santec.gecamed.esante.gui.webservice.Security;
import lu.tudor.santec.gecamed.esante.gui.webservice.SoapSender;
import lu.tudor.santec.gecamed.esante.gui.webservice.XDS;
import lu.tudor.santec.gecamed.esante.utils.ESanteUtils;

import org.apache.log4j.Logger;
import org.apache.xml.security.Init;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.NodeList;

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * @version
 * <br>$Log: CdaUtils.java,v $
 */

public class CdaUtils
{
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(CdaUtils.class.getName());
	
	private static boolean		apacheXmlUtilsInitialized	= false;
	
	
	
	public static String getContent (CdaDocument document) throws Exception
	{
		if (document == null)
			return null;
		
		File	clientFile		= document.getClientFile();
		String	serverFileName	= document.getServerFileName();
		
		
		if (document.getContent() == null && (serverFileName != null || clientFile != null))
		{
			// load the file from the server
			byte[] data;
			if (clientFile != null)
			{
				data = FileUtils.readFile(clientFile);
			}
			else // if (serverFileName != null)
			{
				data = CDAManagerBean.getInstance().loadCDAFileContent(document);
			}
			
			if (data == null)
			{
				throw new Exception("Couldn't load the CDA content.");
			}
			
			document.setContent(new String(data, "UTF-8").replace("(\n)?\r(\n)?", "\n").trim());
			// This should have been done and stored before storing it into database
			extractCDAInfos(document, true);
		}
		
		return document.getContent();
	}
	
	
	@Transient
	public static boolean downloadContent (CdaDocument document, SoapSender sender, int downloadSite) throws Exception
	{
		String	title	= document.getTitle();
		String	content	= document.getContent();
		
		
		// download the content
		logger.debug("Downloading the CDA content " + 
				(title != null ? " of document \"" + title + "\"" : "") + " ...");
		
		if (content != null)
		{
			Dsp		dsp	= ESanteGuiUtils.getDspOfDocument(document);
			String	dspOid;
			if (dsp != null)
				dspOid	= dsp.getDspOid();
			else
				dspOid	= null;
			logger.debug("CDA document \"" + document.getDocumentUniqueId() 
					+ (dspOid == null ? "" : "\" of DSP \"" + dspOid) 
					+ "\" was already loaded.");
			
			return true;
		}
		
		// check if the CDA is cached
		if (ESanteUtils.getCdaDownloadSite() == ESanteUtils.CDA_DOWNLOAD_SITE_CLIENT)
		{
			document.setContent(DocumentWorker.getLocalCachedCda(document));
		}
		
		// if the content is still null, download it
		if (content == null)
		{
//			try
//			{
				content = new String(XDS.loadContentOfDocument(sender, document),"UTF-8");
//			}
//			catch (NotAuthorizedException e)
//			{
//				LoginDialog.incorrectLoginData();
//				return false;
//			}
			
			if (content.length() == 0)
			{
				return false;
			}
		}
		document.setContent(content);
		extractCDAInfos(document, false);
		
		if (downloadSite == ESanteUtils.CDA_DOWNLOAD_SITE_SERVER)
		{
			if (document.isPersistent())
			{
				CdaDocument update = CDAManagerBean.getInstance().updateCdaDocument(document, 
						ESanteUtils.getCdaDownloadSite() == ESanteUtils.CDA_DOWNLOAD_SITE_SERVER);
				update.update(document);
			}
		}
		else // if (downloadSite == ESanteProperty.CDA_DOWNLOAD_SITE_CLIENT)
		{
			document.setClientFile(FileOpener.createGECAMedTempFile("cda_", ".xml"));
			OutputStream os = null;
			try
			{
				os = new BufferedOutputStream(new FileOutputStream(document.getClientFile()));
				os.write(document.getContent().getBytes("UTF-8"));
			}
			finally
			{
				if (os != null)
					os.close();
			}
			DocumentWorker.putLocalCachedCdaFile(document, document.getClientFile().getName());
		}
		
		return true;
	}
	
	
	public static byte[] getBodyAsBytes (CdaDocument document) throws Exception
	{
		String	content			= getContent(document);
		File	clientFile		= document.getClientFile();
		String	serverFileName	= document.getServerFileName();
		Dsp		dsp				= document.getDsp();
		byte[]	bytes;
		String	data;
		
		if (content == null)
			return null;
		
		try
		{
//			base64Body	= SOAPUtilities.parseXPath("//*[local-name()='text']", content, Boolean.TRUE);
			
			data	= (String) ESanteUtils.parseXPath("//*[local-name()='component']/*[local-name()='nonXMLBody']/*[local-name()='text']/text()", content, Boolean.TRUE);
			
			if (!GECAMedUtils.isEmpty(data))
			{
				if ("B64".equals(ESanteUtils.parseXPath(
						"//*[local-name()='component']/*[local-name()='nonXMLBody']/*[local-name()='text']/@representation",
						content, Boolean.TRUE)))
					bytes	= Security.decodeBase64AsBytes(data);
				else
					bytes	= data.getBytes("UTF8");
			}
			else
			{
				NodeList nodes	= (NodeList) ESanteUtils.parseXPath(
						"//*[local-name()='component']/*[local-name()='structuredBody']/*[local-name()='component']", 
						content, Boolean.FALSE);
				if (nodes.getLength() > 0)
				{
					ByteArrayOutputStream	baos = new ByteArrayOutputStream();
					if (!apacheXmlUtilsInitialized)
					{
						Init.init();
						apacheXmlUtilsInitialized	= true;
					}
					XMLUtils.outputDOM(nodes.item(0), baos);
					bytes	= baos.toByteArray();
					data	= new String(bytes, "UTF8");
				}
				else
				{
					bytes = null;
				}
				
				if (bytes == null || bytes.length == 0)
					throw new Exception("Error while parsing CDA document \"" + 
							(serverFileName != null ? serverFileName : (clientFile != null ? clientFile.getName() : "<<no file available>>")) 
							+ "\"" + (dsp != null ? " of patient with ID " + dsp.getPatientId() : ""));
				
				// open structured context with the browser
				document.setMediaType("application/html");
			}
		}
		catch (Exception e)
		{
			if (serverFileName != null)
				logger.warn(e.getMessage(), e);
//						"Error while parsing CDA document \"" + serverFileName + "\"" 
//						+ (dsp != null ? " of patient with ID " + dsp.getPatientId() : ""), e);
			throw e;
		}
		
//		if (bytes == null)
//		{
//			logger.info("Error when downloading the CDA content " + (title != null ? " of document \"" + title + "\"" : "") + " ...");
//		}
		
		return bytes;
	}
	

	private static void extractCDAInfos (CdaDocument document, boolean unsavedOnly) throws Exception
	{
		String content	= document.getContent();
		
		
		try
		{
			document.setMediaType(ESanteUtils.parseXPath("//*[local-name()='text']/@mediaType", content, true).toString());
			document.setTitle(ESanteUtils.parseXPath("//*[local-name()='title']", content, true).toString());
			document.setEffectiveTime(ESanteUtils.parseDate(ESanteUtils.parseXPath("//*[local-name()='effectiveTime']/@value", content, true).toString()));
		}
		catch (Exception e)
		{
			if (document.getMediaType() == null)
				document.setMediaType("unknow");
			if (document.getTitle() == null)
				document.setTitle("unknow");
			
			throw e;
		}
	}
}
