
import java.util.logging.Logger;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.File;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.*; // ArrayList<String>

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletOutputStream; // for SOOA

// from vlkb_mergefiles.java - dir & file handling
import java.io.*;

import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*;

//import nom.tam.fits.*;// Fits - for regridding -- merge only

// config file
import java.util.Properties;


// for Logging/Accounting
import org.json.simple.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import java.security.Principal;



public class ServletMerge extends javax.servlet.http.HttpServlet
{
   private static final Logger   LOGGER   = Logger.getLogger(ServletMerge.class.getName());
   private static final Settings settings = Settings.getInstance();

   final String RESPONSE_ENCODING = "utf-8";
   final String DEFAULT_RESPONSEFORMAT = settings.defaults.responseFormat;
   final String DEFAULT_SKY_SYSTEM     = settings.defaults.skySystem;
   final String DEFAULT_SPEC_SYSTEM    = settings.defaults.specSystem;


   Datasets datasets = new DatasetsImpl(settings);



   public void init() throws ServletException
   {
      super.init();

      LOGGER.info("FITS : " + settings.fitsPaths.toString());
      LOGGER.info("AMQP : " + settings.amqpConn.toString());
      LOGGER.info("DB   : " + settings.dbConn.toString());
   }


   /* DALI allows GET and POST for sync services */

   protected void doGet(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException
      {
         processRequest(request, response);
      }

   protected void doPost(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException
      {
         processRequest(request, response);
      }



   protected void processRequest(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException
      {
         long startTime_msec = System.currentTimeMillis();
         boolean showDuration = true;

         ServletOutputStream  respOutputStream = response.getOutputStream();

         try
         {

            Map<SodaParam, String[]> params = collectSodaParams(request);
            SodaParser parser = new SodaParser(params);

            String id   = null;
            Pos    pos  = null;
            Band   band = null;
            Time   time = null;
            Pol    pol  = null;

            if(parser.sodaReq_hasSodaId())
            {
               id   = parser.sodaReq_getId();
               pos  = parser.sodaReq_getPosCirclePolygon();
               band = parser.sodaReq_getBand();
               time = parser.sodaReq_getTime();
               pol  = parser.sodaReq_getPol();
            }
            else
            {
               id   = parser.vlkbReq_getPubdid();
               pos  = parser.vlkbReq_getCircleRect();
               band = parser.vlkbReq_getVelocity();
            }

            String respFormat = DEFAULT_RESPONSEFORMAT;//sodaReq_getResponseFormat(request, DEFAULT_RESPONSEFORMAT);

            Coord coord = new Coord(DEFAULT_SKY_SYSTEM, pos, DEFAULT_SPEC_SYSTEM, band, time, pol);

            // FIXME should parse from params
            boolean countNullValues = false;
            String respContentType = DEFAULT_RESPONSEFORMAT;

            response.setContentType(respContentType);

            CutResult cutResult = datasets.doMerge(parseLegacyPubdidArr(id), coord, countNullValues);

            DataLink dlk = new DataLink(cutResult);

            String contentType = respContentType;
            String respEncoding = RESPONSE_ENCODING;

            if(contentType.equals("text/xml") || contentType.equals("application/xml"))
            {
               LOGGER.info("writing xml");
               PrintWriter writer = new PrintWriter(new OutputStreamWriter(respOutputStream, respEncoding));
               XmlSerializer.serializeToLegacyCutResults(writer, respEncoding, dlk, showDuration, startTime_msec);
               writer.close();
            }
            else if(contentType.equals("application/fits"))
            {
               LOGGER.info("streaming the file");

               File downloadFile = new File(dlk.absCutPathname);
               FileInputStream input = new FileInputStream(downloadFile);

               input.transferTo(respOutputStream);

               LOGGER.info("Deleting after download: " + downloadFile.getName() );
               downloadFile.delete();
            }
            else
            {
               throw new AssertionError("Unsupported contentType for output: " + contentType);
            }

            respOutputStream.close();
         }
         catch(IllegalArgumentException ex)
         {
            LOGGER.info("Illegal arg : " + ex.getMessage());

            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            response.setContentType("text/plain");
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(respOutputStream, RESPONSE_ENCODING));
            writer.println("UsageError : " + ex.getMessage());
            writer.close();
         }
         catch(Exception ex)
         {
            ex.printStackTrace();

            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.setContentType("text/plain");
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(respOutputStream, RESPONSE_ENCODING));
            writer.println("Error : " + ex.getMessage());
            writer.close();
         }

         LOGGER.info("processRequest normal exit");
      }


   private Map<SodaParam, String[]> collectSodaParams(HttpServletRequest req)
   {
      Map<SodaParam, String[]> params = new HashMap<SodaParam, String[]>();
      for(SodaParam paramToken : SodaParam.values())
      {
         String[] paramValue = req.getParameterValues(paramToken.toString());
         params.put(paramToken, paramValue);
      }
      return params;
   }


   /* semi-colon separated list of pudids convert to arra */
   private String[] parseLegacyPubdidArr(String pubdids)
   {   
      List<String> pubdidList = new ArrayList<String>();
      String[] pdArr = pubdids.split(";");
      for(String pd : pdArr)
         if(pd.length() > 0) pubdidList.add(pd);

      String[] pubdidArr = new String[pubdidList.size()];

      return pubdidList.toArray(pubdidArr);
   }   


}

