/*
 * This file is part of DebGen Biobank Software developed by ASTRID Research.
 * All rights reserved. Reproduction, modification, use or disclosure
 * to third parties without express authority is forbidden.
 *
 * Copyright ASTRID Research Inc., Hungary, 2009-2011.
 *
 * ASTRID Research
 * Headquaters: Csapo utca 42. Debrecen H-4029 HUNGARY
 * Phone: +36-52-533-173        Fax: +36-52-533-174
 * Web: http://www.astrid.hu    E-mail: info@astrid.hu
 *
 * Project name: DebGen Biobank Software project.
 * URLS:
 * Developers: Istvan Zoltan Nagy (istvan.nagy@astrid.hu)
 */
package hu.astrid.debgen.patientmanagement.servlet;

import elements.Functions;
import hu.astrid.debgen.authentication.exception.AccessDeniedException;
import hu.astrid.debgen.exception.ServerSideException;
import hu.astrid.debgen.exception.ValidationFailedException;
import hu.astrid.debgen.patientmanagement.facade.PatientManagerFacade;
import hu.astrid.debgen.server.requestprocessor.ActionParameter;
import hu.astrid.debgen.server.requestprocessor.RequestTokenizer;
import hu.astrid.debgen.server.requestprocessor.facade.RequestProcessorFacade;
import hu.astrid.debgen.patientmanagement.domain.AnonymousData;
import hu.astrid.debgen.authentication.domain.DebGenUser;
import hu.astrid.debgen.patientmanagement.domain.Patient;
import hu.astrid.debgen.patientmanagement.domain.PersonalIdentity;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.hibernate.exception.ConstraintViolationException;

/**
 * Handles the operations with patients
 * @author inagy
 */
public class PatientManagerServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    static Logger logger = Logger.getLogger(PatientManagerServlet.class);

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.debug("doPost() called.");
        ActionParameter actionParameter = ActionParameter.getActionParameter(request);
        logger.debug(actionParameter);
        logger.debug(RequestTokenizer.getRequestData(request));
        String action = actionParameter.getAction();
        try {
            DebGenUser user = RequestProcessorFacade.getDebGenUser(request);
            if (!user.isDataRecorder() && !user.isResearcher()) {
                throw new AccessDeniedException();
            }
            if (action.equals("listpatients")) {
                loadPatients(request, response);
            } else if (action.equals("findpatient")) {
                findPatient(request, response);
            } else if (action.equals("searchpatient")) {
                searchPatient(request, response);
            } else if (action.equals("createpatient")) {
                createPatient(request, response);
            } else if (action.equals("savepatient")) {
                savePatient(request, response);
            } else if (action.equals("showpatient")) {
                showPatient(request, response);
            } else if (action.equals("deletepatient")) {
                deletePatient(request, response);
            } else {
                request.setAttribute("answer", true);
                request.getRequestDispatcher("index.jsp").forward(request, response);
            }
        } catch (AccessDeniedException ex) {
            request.setAttribute("answer", true);
            request.setAttribute("globalexception", new ServerSideException("Nincs jogosultsága a kérés befejezéséhez."));
            request.getRequestDispatcher("index.jsp").forward(request, response);
        } catch (Exception ex) {
            request.setAttribute("answer", true);
            request.setAttribute("globalexception", new ServerSideException("A kért erőforrás nem található, vagy a hivatkozás hibás."));
            request.getRequestDispatcher("index.jsp").forward(request, response);
        }

    }

    // <editor-fold defaultstate="collapsed" desc="Patient">
    /**
     * Tries to load an existing analysis object from the DB if necessary, or does nothing
     * @param request
     * @param response
     * @throws Exception When DB fails or other failure occures
     */
    private void createPatient(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("createPatient() called.");
        PatientManagerFacade facade = new PatientManagerFacade();
        try {
            Long id = new Long(request.getParameter("patient"));
            Patient patient = facade.loadPatient(id);
            request.setAttribute("patient", patient);
        } catch (Exception ex) {
            request.setAttribute("patientCode", facade.getPatientCode());
        }
        request.setAttribute("answer", true);
        request.getRequestDispatcher("index.jsp").forward(request, response);

    }

    /**
     * Deletes a analysis from the DB if possible
     * @param request
     * @param response
     * @throws Exception When DB fails or other failure occures
     */
    private void deletePatient(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("deletePatient() called.");
        try {
            Long id = new Long(request.getParameter("patient"));
            PatientManagerFacade patientManagerFacade = new PatientManagerFacade();
            patientManagerFacade.deletePatient(id);
            response.sendRedirect("listpatients.html");
        } catch (Exception ex) {
            logger.error(ex);
            throw ex;
        }
    }

    /**
     * Loads a page of analysis objects from the DB if possible
     * @param request
     * @param response
     * @throws Exception When DB fails or other failure occures
     */
    private void loadPatients(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("loadPatients() called.");
        List<Patient> patients = null;
        try {
            int page = 0;
            int size = 25;
            try {
                page = Integer.parseInt(request.getParameter("page"));
                size = Integer.parseInt(request.getParameter("size"));
            } catch (Exception ex) {
                //IGNORED, parameters can be empty
                logger.debug("No page size or page number found, using default.");
            }
            String order = Functions.encodeString(request.getParameter("orderBy"));
            if (order.equals("")) {
                order = "patientCode";
            }
            boolean asc = !Functions.encodeString(request.getParameter("asc")).equals("false");
            DebGenUser user = RequestProcessorFacade.getDebGenUser(request);
            PatientManagerFacade patientManagerFacade = new PatientManagerFacade();
            int maxpage = 0;
            if (user.isDataRecorder()) {
                patients = patientManagerFacade.listAllPatients(order, page, size, asc);
                maxpage = patientManagerFacade.getNumberOfListPages(size, true);
            } else {
                patients = patientManagerFacade.listPatients(order, page, size, asc);
                maxpage = patientManagerFacade.getNumberOfListPages(size, false);
            }
            request.setAttribute("current", page);
            request.setAttribute("order", order);
            request.setAttribute("asc", ""+asc);
            request.setAttribute("size", size);
            request.setAttribute("maxpage", maxpage);
            request.setAttribute("site", "listpatients.html");
            request.setAttribute("patients", patients);
            request.setAttribute("answer", true);
            request.getRequestDispatcher("index.jsp").forward(request, response);
        } catch (Exception ex) {
            logger.error(ex);
            throw ex;
        }
    }

    /**
     * Searches for patients
     * @param request
     * @param response
     * @throws Exception When DB fails or other failure occures
     */
    private void searchPatient(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("searchPatients() called.");
        List<Patient> patients = null;
        HttpSession session = request.getSession();
        Patient patient = (Patient) session.getAttribute("pattern");
        try {
            int page = 0;
            int size = 25;
            try {
                page = Integer.parseInt(request.getParameter("page"));
                size = Integer.parseInt(request.getParameter("size"));
            } catch (Exception ex) {
                //IGNORED, parameters can be empty
                logger.debug("No page size or page number found, using default.");
            }
            String order = Functions.encodeString(request.getParameter("orderBy"));
            if (order.equals("")) {
                order = "patientCode";
            }
            boolean asc = !Functions.encodeString(request.getParameter("asc")).equals("false");
            if (request.getParameter("refind") == null) {
                session.removeAttribute("pattern");
                patient = new Patient();
                patient.setPatientType(3);
                patient.setPatientCode(Functions.encodeString(request.getParameter("patientCode")));
                PersonalIdentity personalIdentity = new PersonalIdentity();
                personalIdentity.setPatientName(Functions.encodeString(request.getParameter("patientName")));
                personalIdentity.setTajNumber(Functions.encodeString(request.getParameter("tajNumber")));
                patient.setIdentity(personalIdentity);
                session.setAttribute("pattern", patient);
            }
            DebGenUser user = RequestProcessorFacade.getDebGenUser(request);
            PatientManagerFacade patientManagerFacade = new PatientManagerFacade();
            int maxpage = 0;
            if (user.isDataRecorder()) {
                patients = patientManagerFacade.findAllPatients(patient, order, page, size, asc);
                maxpage = patientManagerFacade.getNumberOfSearchPages(patient, size, true);
            } else {
                patients = patientManagerFacade.findPatients(patient, order, page, size, asc);
                maxpage = patientManagerFacade.getNumberOfSearchPages(patient, size, false);
            }
            if (maxpage == 0 && patients.size() == 1) {
                request.setAttribute("patient", patients.get(0));
                request.setAttribute("answer", true);
                request.setAttribute("onlyshow", true);
                request.getRequestDispatcher("index.jsp").forward(request, response);
            } else {
                request.setAttribute("refind", "&refind=true");
                request.setAttribute("order", order);
                request.setAttribute("asc", ""+asc);
                request.setAttribute("current", page);
                request.setAttribute("size", size);
                request.setAttribute("maxpage", maxpage);
                request.setAttribute("site", "searchpatient.html");
                request.setAttribute("patients", patients);
                request.setAttribute("answer", true);
                request.getRequestDispatcher("index.jsp").forward(request, response);
            }
        } catch (Exception ex) {
            logger.error(ex);
            throw ex;
        }
    }

    /**
     * Does nothing as I know (only forward)
     * @param request
     * @param response
     * @throws Exception When DB fails or other failure occures
     */
    private void findPatient(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("findPatients() called.");
        request.setAttribute("answer", true);
        request.getRequestDispatcher("index.jsp").forward(request, response);
    }

    /**
     * Saves a analysis object to the DB if possible
     * @param request
     * @param response
     * @throws Exception When DB fails or other failure occures
     */
    private void savePatient(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("savePatient() called.");
        request.setAttribute("answer", true);
        request.setAttribute("patientCode", Functions.encodeString(request.getParameter("patientCodeOld")));
        try {
            Long id = 0L;
            Patient patient = null;
            PatientManagerFacade patientManagerFacade = new PatientManagerFacade();
            try {
                id = new Long(request.getParameter("id"));
                patient = patientManagerFacade.loadPatient(id);
            } catch (Exception ex) {
                //IGNORED, parameters can be empty
                logger.debug("New patient found, no problem!");
            }
            AnonymousData oldAnonymousData = null;
            PersonalIdentity oldIdentity = null;
            boolean newPatient = (patient == null);
            if (patient == null) {
                patient = new Patient();
            }
            patient.convert(request);
            if (patient.isAnonymous()) {
                AnonymousData anonymousData = null;
                if (patient.getAnonymousData() == null) {
                    anonymousData = new AnonymousData();
                } else {
                    anonymousData = patient.getAnonymousData();
                }
                anonymousData.convert(request);
                patient.setAnonymousData(anonymousData);
            } else {
                oldAnonymousData = patient.getAnonymousData();
                patient.setAnonymousData(null);
            }
            if (patient.isNamed()) {
                PersonalIdentity identity = null;
                if (patient.getIdentity() == null) {
                    identity = new PersonalIdentity();
                } else {
                    identity = patient.getIdentity();
                }
                identity.convert(request);
                patient.setIdentity(identity);
            } else {
                oldIdentity = patient.getIdentity();
                patient.setIdentity(null);
            }
            if (patient.isNamedAndAnonymous()) {
                AnonymousData anonymousData = patient.getAnonymousData();
                anonymousData.generateMonogram(patient.getIdentity().getPatientName());
            }
            try {
                patient.setDateOfBirth(new SimpleDateFormat("yyyy. MM. dd.").parse(Functions.encodeString(request.getParameter("dateOfBirth"))));
            } catch (Exception e) {
                //IGNORED
                logger.debug("Unknown date format found! The datepicker is not set correctly, or the field is empty? " + request.getParameter("dateOfBirth"));
            }
//            try {
//                analysis.setStartOfTherapy(new SimpleDateFormat("yyyy. MM. dd.").parse(Functions.encodeString(request.getParameter("startOfTherapy"))));
//            } catch (Exception e) {
//                //IGNORED
//                logger.debug("Unknown date format found! The datepicker is not set correctly, or the field is empty? " + request.getParameter("dateOfBirth"));
//            }
            request.setAttribute("patient", patient);
            patient.validate();
            patientManagerFacade.createOrModifyPatient(patient, oldIdentity, oldAnonymousData);
            if (newPatient) {
                response.sendRedirect("createrequest.html?patient=" + patient.getId());
            } else {
                response.sendRedirect("showpatient.html?patient=" + patient.getId());
            }
        } catch (ValidationFailedException ex) {
            logger.error(ex);
            request.setAttribute("exception", new ServerSideException(ex));
            request.getRequestDispatcher("index.jsp").forward(request, response);
        } catch (ConstraintViolationException ex) {
            logger.error(ex);
            request.setAttribute("exception", new ServerSideException("Nem mentheti a beteget ezzel az azonosítóval, mert az azonosító már foglalt. Kérem válasszon másikat."));
            request.getRequestDispatcher("index.jsp").forward(request, response);
        } catch (Exception ex) {
            logger.error(ex);
            throw ex;
        }
    }

    /**
     * Loads a analysis object from the DB if possible
     * @param request
     * @param response
     * @throws Exception When DB fails or other failure occures
     */
    private void showPatient(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.debug("showPatient() called.");
        try {
            Long id = new Long(request.getParameter("patient"));
            Patient patient = new PatientManagerFacade().loadPatient(id);
            request.setAttribute("patient", patient);
            request.setAttribute("answer", true);
            request.getRequestDispatcher("index.jsp").forward(request, response);
        } catch (Exception ex) {
            logger.error(ex);
            throw ex;
        }
    }// </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

}
