package org.msh.tb.cases;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.core.Events;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.framework.Controller;
import org.jboss.seam.international.Messages;
import org.msh.tb.application.ViewService;
import org.msh.tb.cases.treatment.PrescribedMedicineHome;
import org.msh.tb.cases.treatment.PrescriptionTable;
import org.msh.tb.entities.TbCase;
import org.msh.tb.entities.Tbunit;
import org.msh.tb.entities.TreatmentHealthUnit;
import org.msh.tb.entities.enums.CaseState;
import org.msh.tb.tbunits.TBUnitSelection;
import org.msh.tb.tbunits.TBUnitSelection2;
import org.msh.tb.tbunits.TBUnitType;
import org.msh.utils.date.DateUtils;
import org.msh.utils.date.Period;

import javax.persistence.EntityManager;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;


/**
 * Handle the transfer of cases from one health unit to another health unit.
 * Actions available: Transfer out, Transfer in and Roll back transfer
 * @author Ricardo Memoria
 *
 */
@Name("caseMoveHome")
@Scope(ScopeType.CONVERSATION)
public class CaseMoveHome extends Controller {
    private static final long serialVersionUID = 5372648329946431824L;

    @In(required = true) CaseHome caseHome;
    @In EntityManager entityManager;
    @In FacesMessages facesMessages;
    @In(required = false) PrescriptionTable prescriptionTable;
    @In(create = true) PrescribedMedicineHome prescribedMedicineHome;

    private Date moveDate;
    private TBUnitSelection tbunitselection2;
    private TreatmentHealthUnit currentHealthUnit;


    /**
     * Called when the transfer out form is displayed to the user
     */
    public void initializeTransferOut() {
        // if it's an HTTP POST, ignore the initialize method
        if (ViewService.instance().isFormPost()) {
            return;
        }

        getTbunitselection2().setAdminUnit(null);
    }

    /**
     * Execute the transfer of a case to another health unit
     * @return
     */
    @Transactional
    public String transferOut() {
        if (!caseHome.isCanTransferOut())
            return "error";

        if (!validateTransferOut())
            return "error";

        TbCase tbcase = caseHome.getInstance();
        Tbunit tbunit = getTbunitselection2().getSelected();

        // create the period of treatment for the new health unit
        Period newPeriod = new Period(DateUtils.incDays(moveDate, 1), tbcase.getTreatmentPeriod().getEndDate());
        Period prevPeriod = new Period(currentHealthUnit.getPeriod().getIniDate(), moveDate);

        // create new treatment health unit
        TreatmentHealthUnit newhu = new TreatmentHealthUnit();
        newhu.setPeriod(newPeriod);
        newhu.setTbcase(caseHome.getInstance());
        newhu.setTransferring(true);
        tbcase.getHealthUnits().add(newhu);
        newhu.setTbunit(tbunit);

        currentHealthUnit.getPeriod().intersect(prevPeriod);

        prescribedMedicineHome.splitPeriod(newPeriod.getIniDate());

        tbcase.setState(CaseState.TRANSFERRING);

        caseHome.setDisplayMessage(false);
        caseHome.persist();

        if (prescriptionTable != null)
            prescriptionTable.refresh();

        Events.instance().raiseEvent("case.transferout");

        OwnerUnitChecker.checkOwnerId(tbcase);

        return "transferred-out";
    }


    /**
     * Validate the variables for the transfer out action
     * @return true if transfer out can be executed
     */
    protected boolean validateTransferOut() {
        Tbunit tbunit = getTbunitselection2().getSelected();
        if (tbunit == null)
            return false;

        // search for previous treatment health unit
        TreatmentHealthUnit prev = findTransferOutHealthUnit();
        if (prev == null)
            return false;

        // checks if date is before beginning treatment date
        if (!prev.getPeriod().isDateInside(moveDate)) {
            facesMessages.addFromResourceBundle("cases.move.errortreatdate");
            return false;
        }

        if (prev.getTbunit().equals(tbunit)) {
            facesMessages.addFromResourceBundle("cases.move.errorunit");
            return false;
        }

        currentHealthUnit = prev;
        return true;
    }


    /**
     * Roll back an on-going transfer from one unit to another, restoring the previous state before the transfer
     * @return
     */
    @Transactional
    public String rollbackTransferOut() {
        TbCase tbcase = caseHome.getInstance();
        if (tbcase.getHealthUnits().size() <= 1) {
            facesMessages.add("No unit to roll back transfer");
            return "error";
        }

        List<TreatmentHealthUnit> hus = tbcase.getSortedTreatmentHealthUnits();
        TreatmentHealthUnit tout = hus.get(hus.size() - 2);
        TreatmentHealthUnit tin = hus.get(hus.size() - 1);

        hus.remove(tin);
        entityManager.remove(tin);

        tout.getPeriod().setEndDate(tin.getPeriod().getEndDate());

        Date movdt = tin.getPeriod().getIniDate();

        Date iniContPhase = tbcase.getIniContinuousPhase();
        if ((iniContPhase != null) && (!iniContPhase.equals(movdt))) {
            prescribedMedicineHome.joinPeriods(movdt);
        }

        tbcase.setState(CaseState.ONTREATMENT);
        caseHome.persist();

        if (prescriptionTable != null) {
            prescriptionTable.refresh();
        }

        // information to be logged
        Contexts.getEventContext().set("transferdate", tin.getPeriod().getIniDate());
        Contexts.getEventContext().set("transferunit", tin.getTbunit());

        Events.instance().raiseEvent("case.transferout.rollback");

        OwnerUnitChecker.checkOwnerId(tbcase);

        return "success";
    }


    /**
     * Initialize the transfer in registration
     */
    public void initializeTransferIn() {
        // just initialize it if it's an HTTP GET
        if (ViewService.instance().isFormPost())
            return;

        if (!caseHome.isCanTransferIn())
            return;

        TreatmentHealthUnit hu = caseHome.getTransferInHealthUnit();
        moveDate = hu.getPeriod().getIniDate();
    }


    /**
     * Register the transfer in of the case
     * @return
     */
    @Transactional
    public String transferIn() {
        TreatmentHealthUnit prev = findTransferOutHealthUnit();

        if (prev == null)
            return "error";

        if (!moveDate.after(prev.getPeriod().getEndDate())) {
            facesMessages.addFromResourceBundle("cases.move.errordt-transferin");
            return "error";
        }

        TreatmentHealthUnit hu = caseHome.getTransferInHealthUnit();
        if (!moveDate.before(hu.getPeriod().getEndDate())) {
            facesMessages.addFromResourceBundle("cases.move.notreat", moveDate);
            return "error";
        }

        hu.getPeriod().setIniDate(moveDate);
        hu.setTransferring(false);
        entityManager.persist(hu);

        TbCase tbcase = caseHome.getInstance();

        tbcase.setState(CaseState.ONTREATMENT);

        caseHome.setDisplayMessage(false);
        caseHome.persist();

        Events.instance().raiseEvent("case.transferin");

        OwnerUnitChecker.checkOwnerId(tbcase);

        return "trasnferred-in";
    }


    /**
     * Returns the treatment health unit that is transferring out
     * @return
     */
    public TreatmentHealthUnit findTransferOutHealthUnit() {
        TbCase tbcase = caseHome.getInstance();

        Date dt = null;
        TreatmentHealthUnit aux = null;
        for (TreatmentHealthUnit hu: tbcase.getHealthUnits()) {
            if ((!hu.isTransferring()) &&
                    ((dt == null) || (hu.getPeriod().getIniDate().after(dt))))
            {
                dt = hu.getPeriod().getIniDate();
                aux = hu;
            }
        }

        return aux;
    }

    public Date getMoveDate() {
        return moveDate;
    }

    public void setMoveDate(Date moveDate) {
        this.moveDate = moveDate;
    }

    public TBUnitSelection getTbunitselection2() {
        if (tbunitselection2 == null) {
            tbunitselection2 = new TBUnitSelection("unitid", false, TBUnitType.HEALTH_UNITS);
        }
        return tbunitselection2;
    }

    /**
     * Return message to confirm roll back of the transfer out
     * @return
     */
    public String getConfirmMsgRollbackTransfer() {
        TreatmentHealthUnit tu = caseHome.getTransferInHealthUnit();
        if (tu == null)
            return null;

        String msg = Messages.instance().get("cases.move.cancel-confirm");
        msg = MessageFormat.format(msg, tu.getTbunit().getName().toString());
        return msg;
    }
}
