
//import it.inaf.ia2.aa.data.User;

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*; // ArrayList<String> Collection<>

import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;


import javax.servlet.http.HttpServletRequestWrapper;
import java.security.Principal;

@javax.servlet.annotation.MultipartConfig
public class MonitorFilter implements Filter
{
  private static final Logger LOGGER = Logger.getLogger(MonitorFilter.class.getName());
  private static final Settings settings = Settings.getInstance();


   @Override
   public void init(FilterConfig fc) throws ServletException {}

   @Override
   public void destroy() {}

   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
   {
      LOGGER.info("ENTER doFilter ====================================");

      HttpServletRequest  req  = (HttpServletRequest)  request;
      HttpServletResponse resp = (HttpServletResponse) response;

      boolean readBody = false;                
      //logServletEnv(req, resp, readBody);

      String servletPath = req.getServletPath();

      List<String> pubdidList = new ArrayList<String>();

      if(servletPath.equals("/vlkb_cutout"))
      {
         String pubdid = req.getParameter("ID");
         if(pubdid == null) pubdid = req.getParameter("pubdid");
         if(pubdid != null) pubdidList.add(pubdid);
         LOGGER.info("PARAM cut id: " + pubdid);
      }
      else if(servletPath.equals("/uws_merge") || servletPath.equals("/vlkb_merge"))
      {
         String pubdids = req.getParameter("pubdid");
         LOGGER.info("PARAM mrg pubdid: " + pubdids);
         String[] pubdidArr = pubdids.split(";");
         for(String pubdid : pubdidArr) 
            if(pubdid.length() > 0) pubdidList.add(pubdid);
      }
      else if(servletPath.equals("/uws_mcutout"))
      {
         final String METHOD = req.getMethod();
         if(METHOD.equals("POST"))
         {
            try
            {
               Part part = req.getPart("mcutout");
               if(part == null)
               {
                  LOGGER.info("part 'mcutout' is null");
               }
               else
               {
                  String body = getValue(part);
                  LOGGER.info("PARAM mct B[mcutout]: " + body);
                  String[] pubdidArr = JdlMCutout.pubdidsFromReqJson(body);
                  for(String pubdid : pubdidArr) 
                     if(pubdid.length() > 0) pubdidList.add(pubdid);
               }
            }
            catch(ServletException ex)
            {
               LOGGER.info("getPart(mcutout) ServeltException: " + ex.getMessage());
            }
            catch(IOException ex)
            {
               LOGGER.info("getPart(mcutout) IOException: " + ex.getMessage());
            }
            catch(Exception ex)
            {
               LOGGER.info("getPart(mcutout) Exception: " + ex.getMessage());
            }
         }
      }
      else
      {
         LOGGER.info("ServletPath not used: " + servletPath);

         LOGGER.info("CALL chain.doFilter");
         chain.doFilter(request, response);
         LOGGER.info("RETURN from chain.doFilter");

         LOGGER.info("EXIT doFilter *************************************");
         return;
      }



      int i = 0;
      for(String pubdid : pubdidList)
         LOGGER.info("pubdid[" + i++ + "]:" + pubdid);


      LOGGER.info("AuthZ start --------------------------------------");
      AuthPolicy auth = null;
      try
      {
         auth = new AuthPolicy(req.getUserPrincipal());
      }
      catch(IllegalArgumentException ex)
      {
         throw new IllegalArgumentException("Authorization : UserPrincipal is not of expected type");
      }
      String[] pubdidArr = pubdidList.toArray(new String[pubdidList.size()]);
      String[] authorized_pubdids;
      LOGGER.info("Action cutout: for filterrAuthorized.");
      authorized_pubdids = auth.filterAuthorized(pubdidArr, settings.dbConn.uri(), settings.dbConn.userName(), settings.dbConn.password());
      LOGGER.info("AuthZ end ---------------------------------------");

      i = 0;
      for(String pubdid : authorized_pubdids)
         LOGGER.info("authZpubdid[" + i++ + "]:" + pubdid);

      if(servletPath.equals("/vlkb_cutout") && (authorized_pubdids.length < 1))
      {
         LOGGER.info("FORBIDDEN Authorization error");
         resp.setContentType("text/plain");
         resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden");
      }
      else
      {
         LOGGER.info("CALL chain.doFilter");
         chain.doFilter(request, response);
         LOGGER.info("RETURN from chain.doFilter");
      }

      LOGGER.info("EXIT doFilter *************************************");

   }




   private static String getValue(Part part) throws IOException
   {
      BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), "UTF-8"));
      StringBuilder value = new StringBuilder();
      char[] buffer = new char[1024];
      for (int length = 0; (length = reader.read(buffer)) > 0;)
      {
         value.append(buffer, 0, length);
      }
      return value.toString();
   }





   private void logServletEnv(HttpServletRequest  req, HttpServletResponse resp, boolean readBody)
   {

      Principal princ = req.getUserPrincipal();
      LOGGER.info("getUserPrincipal available  : " + ((princ == null) ? "NO" : "YES"));
      String H_AUTH = req.getHeader("Authorization");
      if(H_AUTH == null )
         LOGGER.info("getHeader[Authorization][-] : null");
      else
         LOGGER.info("getHeader[Authorization][" + H_AUTH.length() +"] :" + H_AUTH.substring(0,10) + " ..." );

      /* Servlet.getServletConfig(), ServletConfig.getServletContext() */
      /* ServeltContext.getContextPath() ServletContext.getRealPath() if war-name differs from ContextPath */
      LOGGER.info("getContextPath    : " + req.getContextPath()); // usually the war-file name
      LOGGER.info("getServletPath    : " + req.getServletPath());
      LOGGER.info("getPathInfo       : " + req.getPathInfo()); // portion after context and before query-string
      LOGGER.info("getPathTranslated : " + req.getPathTranslated()); // extra path translated to local path
      LOGGER.info("getRequestURI     : " + req.getRequestURI());
      LOGGER.info("getRequestURL     : " + req.getRequestURL().toString());
      LOGGER.info("getQueryString    : " + req.getQueryString());
      LOGGER.info("getContentType    : " + req.getContentType());


      String METHOD = req.getMethod();
      LOGGER.info("getMethod     : " + METHOD);


      Map<String, String[]> map = req.getParameterMap();
      for (Map.Entry<String, String[]> entry : map.entrySet())
      {
         String[] strArr = entry.getValue();
         for(String str : strArr)
            LOGGER.info("PARAM: " + entry.getKey() + ":" + str);
      }


      /* MultipartConfig.maxFileSize(), MultipartConfig.maxRequestSize() */
      if(METHOD.equals("POST"))
      {
         try
         {
            /* for getParts() call to work in Tomcat the following config in context.xml is needed:
             * <Context allowCasualMultipartParsing="true"> ...
             */
            Collection<Part> parts = req.getParts();
            if(parts == null)
            {
               LOGGER.info("parts is null");
            }
            else
            {
               for(Part part : parts)
               {
                  LOGGER.info("part.getName              : " + part.getName());
                  LOGGER.info("part.getSize              : " + part.getSize());
                  LOGGER.info("part.getHeader            : " + part.getHeader(part.getName()));
                  LOGGER.info("part.getContentType       : " + part.getContentType());
                  LOGGER.info("part.getSubmittedFileName : " + part.getSubmittedFileName());

                  if (readBody && part.getName().equals("mcutout"))
                  {
                     String body = getValue(part);
                     LOGGER.info("BODY: " + body);
                  }

               }
            }
         }
         catch(ServletException ex)
         {
            LOGGER.info("getParts ServeltException: " + ex.getMessage());
         }
         catch(IOException ex)
         {
            LOGGER.info("getParts IOException: " + ex.getMessage());
         }
         catch(Exception ex)
         {
            LOGGER.info("getParts Exception: " + ex.getMessage());
         }
      }
   }


}

