/**
 *
 */
package org.gcube.portlets.user.gisviewer.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.nio.file.Files;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.gcube.portlets.user.gisviewer.client.Constants;
import org.gcube.portlets.user.gisviewer.client.commons.beans.LayerItem;
import org.gcube.portlets.user.gisviewer.server.datafeature.wfs.WFSExporter;
import org.gcube.portlets.user.gisviewer.server.datafeature.wfs.WFSExporter.WFS_TO;
import org.gcube.portlets.user.gisviewer.server.util.CSVWriter;
import org.gcube.portlets.user.gisviewer.server.util.URLParserUtil;
import org.gcube.portlets.user.gisviewer.shared.CSVFile;
import org.gcube.portlets.user.gisviewer.shared.CSVRow;

// TODO: Auto-generated Javadoc
/**
 * The Class DownloadWFSFeaturesServlet.
 *
 * @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy)
 * Apr 24, 2020
 */
public class DownloadWFSFeaturesServlet extends HttpServlet{
	/**
	 * 
	 */
	private static final long serialVersionUID = -2850877529278199613L;

	
	
	private static Logger LOG = Logger.getLogger(DownloadWFSFeaturesServlet.class);

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void init() throws ServletException {
		super.init();
		LOG.debug(DownloadWFSFeaturesServlet.class.getSimpleName() +" is ready");
	}

	/**
	 * Do get.
	 *
	 * @param req the req
	 * @param resp the resp
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		LOG.info("doGet "+ DownloadWFSFeaturesServlet.class.getSimpleName() +" called");
		String wfsRequestURL = req.getParameter(Constants.PARAMETER_WFS_REQUEST);
		InputStream inputStream = null;
		OutputStream respOutStream = null;
		CSVWriter csvWriter = null;
		
		
		if(wfsRequestURL==null)
			sendError(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad Request: parameter "+Constants.PARAMETER_WFS_REQUEST+" is null");
		try{
			LOG.info("Read param: "+Constants.PARAMETER_WFS_REQUEST +" "+wfsRequestURL);
			String layerName = URLParserUtil.extractValueOfParameterFromURL("TYPENAME", wfsRequestURL);
			String geoserverURL = wfsRequestURL.substring(0,wfsRequestURL.indexOf("?"));
			String bbox = URLParserUtil.extractValueOfParameterFromURL("BBOX", wfsRequestURL);
			String cqlFilter = URLParserUtil.extractValueOfParameterFromURL("CQL_FILTER", wfsRequestURL);

			LayerItem layerItem = new LayerItem();
			layerItem.setLayer(layerName);
			layerItem.setGeoserverUrl(geoserverURL);
			layerItem.setName(layerName);
			layerItem.setCqlFilter(cqlFilter);
			LOG.info("From WFS request got: "+layerItem);
			LOG.info("layerName: "+layerItem.getName());
			LOG.info("wfs service URL: "+layerItem.getGeoserverUrl());
			
			try {
			
				WFSExporter exporter = new WFSExporter();
				CSVFile table = exporter.getTableFromJsonToExport(layerItem, bbox, Constants.MAX_WFS_FEATURES, WFS_TO.EXPORT);
				
				File tempFile = createTempFile("wfs-export", ".csv.tmp");
				csvWriter = new CSVWriter(tempFile);
				
				//adding table/csv headers
				LOG.info("Adding to file header row: "+table.getHeaderRow().getListValues());
				csvWriter = addValuesToCVSLine(csvWriter, table.getHeaderRow().getListValues());
				
				for (CSVRow row : table.getValueRows()) {
					//adding csv row
					LOG.info("Adding to file row: "+row.getListValues());
					csvWriter = addValuesToCVSLine(csvWriter, row.getListValues());
				}
			}catch (Exception e) {
				LOG.error("Error on exporting the WFS features",e);
				sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error on exporting the WFS features. Please contact the support");
			}finally {
				
				if(csvWriter!=null) {
					try {
						csvWriter.closeWriter();
					} catch (Exception e) {
						LOG.warn("Error occurred on closing the csv writed",e);
					}
				}
			}
			
			String contentDisposition = "attachment";
			String fileName = layerName + ".csv";
			resp.setHeader("Content-Disposition", contentDisposition+"; filename=\"" + fileName + "\"" );
			
			LOG.info("The size is: "+csvWriter.getTempFile().length());
			resp = setContentLength(resp, csvWriter.getTempFile().length());
			resp.setContentType("text/csv");
			respOutStream = resp.getOutputStream();
			inputStream = new FileInputStream(csvWriter.getTempFile());
			IOUtils.copy(inputStream, respOutStream);
			return;
		} catch (Exception e) {
			LOG.error("Error on exporting the WFS features",e);
			sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error on creating the CSV file. Please contact the support");
			return;
		}finally {
			
			silentClose(inputStream);
			
			if(csvWriter!=null) {
				try {
					csvWriter.getTempFile().delete();
				} catch (Exception e) {
					LOG.warn("Error occurred on closing the csv writed",e);
				}
			}
		}
	}
	
	
	/**
	 * Silent close.
	 *
	 * @param stream the stream
	 */
	private void silentClose(InputStream stream) {
		if (stream != null) {
			try {
				stream.close();
			} catch (Exception e) {
				LOG.warn("Error on closing the stream");
			}
		}
	}
	

	/**
	 * Adds the values to CVS line.
	 *
	 * @param csvWriter the csv writer
	 * @param values the values
	 * @return the CSV writer
	 */
	private static CSVWriter addValuesToCVSLine(CSVWriter csvWriter, List<String> values) {
		String newline = "";
		for (String value : values) {
			newline += String.format("%s%s", value,CSVWriter.DEFAULT_SEPARATOR);
		}
		newline = newline.substring(0, newline.length()-1); //removing last separator
		csvWriter.writeCSVLine(newline);
		return csvWriter;
	}

	/**
	 * Method to manage HttpServletResponse content length also to big data.
	 *
	 * @param resp the resp
	 * @param length the length
	 * @return the http servlet response
	 */
	protected HttpServletResponse setContentLength(HttpServletResponse resp, long length){
		try{
		    if (length <= Integer.MAX_VALUE)
		    	resp.setContentLength((int)length);
		    else
		    	resp.addHeader("Content-Length", Long.toString(length));
		}catch(Exception e){
			//silent
		}
		return resp;
	}

	/**
	 * Send error.
	 *
	 * @param response the response
	 * @param status the status
	 * @param message the message
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	protected void sendError(HttpServletResponse response, int status, String message) throws IOException
	{
		response.setStatus(status);
		//HandlerResultMessage resultMessage = HandlerResultMessage.errorResult(message);
		LOG.trace("error message: "+message);
		LOG.trace("writing response...");
		StringReader sr = new StringReader(message.toString());
		IOUtils.copy(sr, response.getOutputStream());

		LOG.trace("response writed");
		response.flushBuffer();
	}
	

    /**
     * Creates the temp file.
     *
     * @param fileName the file name
     * @param extension the extension
     * @return the file
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static File createTempFile(String fileName, String extension) throws IOException {
        // Since Java 1.7 Files and Path API simplify operations on files
    	java.nio.file.Path path = Files.createTempFile(fileName, extension);
        File file = path.toFile();
        // writing sample data
        //Files.write(path, data);
        LOG.info("Created the Temp File: "+file.getAbsolutePath());
        return file;
    }
    
}
