
import java.util.logging.Logger;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.*;


import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;


import java.nio.charset.Charset;

import vo.parameter.*;


public class FormatResponseFilter implements Filter
{
   private static final Logger LOGGER = Logger.getLogger("FormatResponseFilter");
   private static final FormatResponseSettings settings = FormatResponseSettings.getInstance(
         "formatresponsefilter.properties");

   public void init(FilterConfig filterConfig) throws ServletException
   {
      LOGGER.config("Default charset: " + Charset.defaultCharset());
      LOGGER.config("DB: " + settings.dbConn.toString());
   }

   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException
   {
      LOGGER.fine("trace");
      LOGGER.fine("REQUEST START");

      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;
      final String DEFAULT_TIME_SYSTEM = "MJD_UTC"; // FIXME take from confif file


      FormatResponseWrapper responseWrapper = new FormatResponseWrapper((HttpServletResponse) response);

      try
      {
         long startTime_msec = System.currentTimeMillis();

         chain.doFilter(request, responseWrapper);

         String[] pubdidArr = responseWrapper.getPubdidArr();

         if ((pubdidArr != null) && (pubdidArr.length > 0))
         {
            PrintWriter responseWriter = ((HttpServletResponse)response).getWriter();

            Map<String, String[]> params = request.getParameterMap();
            Pos  pos  = Pos.parsePos(params, DEFAULT_SKY_SYSTEM);
            Band band = Band.parseBand(params, DEFAULT_SPEC_SYSTEM);

            DbPSearch.ObsCore[] obsCoreArr = queryObsCore(pubdidArr, pos, band);

            String respFormat;
            String respFormatReq[] = params.get("RESPONSEFORMAT");
            if(respFormatReq != null && (respFormatReq.length > 0) && !respFormatReq[0].isEmpty())
            {
               respFormat = respFormatReq[0];
               LOGGER.finest("responseFormat(from request): " + respFormat);
            }
            else
            {
               respFormat = settings.serviceUrls.responseFormat();
               LOGGER.finest("responseFormat(from settings): " + respFormat);
            }

            response.setCharacterEncoding(RESPONSE_ENCODING);

            if(respFormat.startsWith("application/x-votable+xml"))
            {
               response.setContentType("application/xml");
               boolean showDuration = false;

               XmlSerializer.serializeToVoTable(responseWriter, RESPONSE_ENCODING,
                     obsCoreArr,
                     settings.serviceUrls.cutoutUrl(),
                     settings.serviceUrls.mergeUrl(),
                     showDuration,startTime_msec);
            }
            else
            {
               final String errMsg = "Illegal response format request: " + respFormat;
               LOGGER.warning(errMsg);
               response.setContentType("text/plain");
               Response.doUsageError(errMsg, responseWriter);
               // FIXME set http err code 
            }

            responseWriter.close();
         }
         else
         {
            LOGGER.fine("SearchServlet returned no ID's.");
         }
      }
      catch(MultiValuedParamNotSupported ex)
      {
         LOGGER.warning("MultiValuedParamNotSupported: " + ex.getMessage());

         responseWrapper.setStatus(HttpServletResponse.SC_BAD_REQUEST);
         responseWrapper.setContentType("text/plain");

         PrintWriter writer = responseWrapper.getWriter();
         Response.doMultiValuedParamNotSupported(ex.getMessage(), writer);
         writer.close();
      }
      catch(IllegalArgumentException ex)
      {
         LOGGER.warning("IllegalArgumentException: " + ex.getMessage());

         responseWrapper.setStatus(HttpServletResponse.SC_BAD_REQUEST);
         responseWrapper.setContentType("text/plain");

         PrintWriter writer = responseWrapper.getWriter();
         Response.doUsageError(ex.getMessage(), writer);
         writer.close();
      }
      catch(Exception ex)
      {
         LOGGER.warning("Exception: " + ex.getMessage());
         ex.printStackTrace();

         responseWrapper.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
         responseWrapper.setContentType("text/plain");

         PrintWriter writer = responseWrapper.getWriter();
         Response.doError(ex.toString(), writer);
         writer.close();
      }

      LOGGER.fine("REQUEST END");
   }

   //@Override
   public void destroy()
   {
      LOGGER.fine("trace");
   }


   private DbPSearch.ObsCore[] queryObsCore(String[] pubdidArr, Pos pos, Band band)
         throws Exception
      {

         LOGGER.fine("trace");

         DbPSearch dbps;
         synchronized(DbPSearch.class)
         {
            dbps = new DbPSearch(settings.dbConn);
         }

         return dbps.queryOutputData(pubdidArr, pos, band);
      }

}

