package pt.utl.ist.scripts.process.updateData;

import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import net.sourceforge.fenixedu.domain.Attends;
import net.sourceforge.fenixedu.domain.Enrolment;
import net.sourceforge.fenixedu.domain.EnrolmentEvaluation;
import net.sourceforge.fenixedu.domain.ExecutionSemester;
import net.sourceforge.fenixedu.domain.curriculum.EnrolmentEvaluationType;
import net.sourceforge.fenixedu.util.EnrolmentEvaluationState;

import org.joda.time.DateTime;

import pt.utl.ist.scripts.commons.AtomicScript;

public class SetImprovementEnrolmentEvaluationExecutionPeriodFromAplica extends AtomicScript {

    @Override
    protected void run() throws Exception {

        Set<ExecutionSemester> executionPeriodsToEvaluate = new HashSet<ExecutionSemester>();
        if (true) {
            throw new Error("no longer supported");
//        executionPeriodsToEvaluate.add(rootDomainObject.readExecutionSemesterByOID(65));
//        executionPeriodsToEvaluate.add(rootDomainObject.readExecutionSemesterByOID(19));
//        executionPeriodsToEvaluate.add(rootDomainObject.readExecutionSemesterByOID(45));
        }

        for (ExecutionSemester executionPeriod : executionPeriodsToEvaluate) {
            doAction(new ProcessExecutionPeriod(executionPeriod));
        }

    }

    private static class ProcessExecutionPeriod extends AtomicAction {
        private ExecutionSemester executionPeriod;
        private SortedSet<ExecutionSemester> sortedExecutionPeriods = new TreeSet<ExecutionSemester>();

        public ProcessExecutionPeriod(ExecutionSemester executionPeriod) {
            this.executionPeriod = executionPeriod;
            sortedExecutionPeriods.addAll(rootDomainObject.getExecutionPeriodsSet());
        }

        @Override
        public void doIt() {
            logger.info("ExecutionPerdio -> " + executionPeriod.getQualifiedName());
            processEnrolments(executionPeriod.getEnrolmentsSet());
        }

        private void processEnrolments(Set<Enrolment> enrolmentsSet) {
            for (Enrolment enrolment : enrolmentsSet) {
                if (enrolment.hasImprovement()) {
                    try {
                        processEnrolment(enrolment);
                    } catch (Exception e) {
                        logger.info(e.getMessage());
                    }
                }
            }

        }

        private void processEnrolment(Enrolment enrolment) throws Exception {
            ExecutionSemester improvementExecutionPeriod = getImprovementExecutionPeriod(enrolment);
            if (improvementExecutionPeriod == null) {
                improvementExecutionPeriod = getImprovementExecutionPeriodByCreationDate(enrolment);
            }
            // if(improvementExecutionPeriod != null) {
            for (EnrolmentEvaluation enrolmentEvaluation : enrolment.getEvaluationsSet()) {
                if (enrolmentEvaluation.getEnrolmentEvaluationType() == EnrolmentEvaluationType.IMPROVEMENT) {
                    if (!enrolmentEvaluation.hasExecutionPeriod()) {
                        enrolmentEvaluation.setExecutionPeriod(improvementExecutionPeriod);
                    }
                }
            }
            // }
        }

        private ExecutionSemester getImprovementExecutionPeriodByCreationDate(Enrolment enrolment) throws Exception {
            for (EnrolmentEvaluation enrolmentEvaluation : enrolment.getEvaluationsSet()) {
                if (enrolmentEvaluation.getEnrolmentEvaluationType() == EnrolmentEvaluationType.IMPROVEMENT
                        && (enrolmentEvaluation.getEnrolmentEvaluationState().equals(EnrolmentEvaluationState.RECTIFICATION_OBJ)
                                || enrolmentEvaluation.getEnrolmentEvaluationState().equals(EnrolmentEvaluationState.FINAL_OBJ) || enrolmentEvaluation
                                .getEnrolmentEvaluationState().equals(EnrolmentEvaluationState.RECTIFIED_OBJ))) {
                    if (enrolmentEvaluation.getExamDateYearMonthDay() == null) {
                        return getNextYearExecutionYear(enrolment);
                    }
                    ExecutionSemester period =
                            getExecutionPeriodByDateTime(enrolmentEvaluation.getExamDateYearMonthDay().toDateTimeAtMidnight());
                    // ExecutionSemester period =
                    // ExecutionSemester.readByDateTime(enrolmentEvaluation.getExamDateYearMonthDay().toDateTimeAtMidnight());
                    if (period == null) {
                        throw new Exception("EnrolmentEvaluation " + enrolmentEvaluation.getExternalId() + " exam date "
                                + enrolmentEvaluation.getExamDateYearMonthDay().toString() + " doesn't have execution period");
                    }
                    return validateExecutionPeriod(enrolment, period);
                }
            }
            /*
             * for (EnrolmentEvaluation enrolmentEvaluation :
             * enrolment.getEvaluationsSet()) {
             * if(enrolmentEvaluation.getEnrolmentEvaluationType() ==
             * EnrolmentEvaluationType.IMPROVEMENT &&
             * enrolmentEvaluation.getEnrolmentEvaluationState().equals(EnrolmentEvaluationState.TEMPORARY_OBJ)) {
             * if(enrolmentEvaluation.getWhenDateTime() == null) { throw new
             * Exception("EnrolmentEvaluation " +
             * enrolmentEvaluation.getIdInternal() + " doesn't have when date"); }
             * 
             * ExecutionSemester period =
             * ExecutionSemester.readByDateTime(enrolmentEvaluation.getWhenDateTime());
             * if(period == null) { throw new Exception("EnrolmentEvaluation " +
             * enrolmentEvaluation.getIdInternal() + " when date " +
             * enrolmentEvaluation.getWhenDateTime().toString() + " doesn't have
             * execution period"); } return validateExecutionPeriod(enrolment,
             * period); } }
             */

            return getNextYearExecutionYear(enrolment);
        }

        private ExecutionSemester getNextYearExecutionYear(Enrolment enrolment) {
            if (enrolment.getExecutionPeriod().getNextExecutionPeriod() == null) {
                return enrolment.getExecutionPeriod();
            }
            if (enrolment.getExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod() == null) {
                return enrolment.getExecutionPeriod().getNextExecutionPeriod();
            } else {
                return enrolment.getExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod();
            }
        }

        private ExecutionSemester getExecutionPeriodByDateTime(DateTime dateTime) {
            for (ExecutionSemester executionPeriod : sortedExecutionPeriods) {
                if (executionPeriod.getBeginDateYearMonthDay().toDateTimeAtMidnight().isAfter(dateTime)) {
                    return executionPeriod.getPreviousExecutionPeriod();
                }
            }
            return null;
        }

        private ExecutionSemester validateExecutionPeriod(Enrolment enrolment, ExecutionSemester period) throws Exception {
            if (enrolment.getExecutionPeriod().isAfter(period)) {
                throw new Exception("Enrolment " + enrolment + " improvement execution period " + period.getQualifiedName()
                        + " is invalid");
            }

            if (enrolment.getExecutionPeriod() == null || enrolment.getExecutionPeriod().equals(period)) {
                return period;
            }

            if (enrolment.getExecutionPeriod().getNextExecutionPeriod() == null
                    || enrolment.getExecutionPeriod().getNextExecutionPeriod().equals(period)) {
                return period;
            }

            if (enrolment.getExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod() == null
                    || enrolment.getExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod().equals(period)) {
                return period;
            }

            if (enrolment.getExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod() == null
                    || enrolment.getExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod()
                            .equals(period)) {
                return period;
            }

            logger.info("Enrolment "
                    + enrolment.getExternalId()
                    + " from "
                    + period.getQualifiedName()
                    + " to "
                    + enrolment.getExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod()
                            .getQualifiedName());
            return enrolment.getExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod().getNextExecutionPeriod();
        }

        private ExecutionSemester getImprovementExecutionPeriod(Enrolment enrolment) throws Exception {
            if (enrolment.getAttendsSet().size() > 2) {
                SortedSet<ExecutionSemester> attendsEP = new TreeSet<ExecutionSemester>();
                for (Attends attends : enrolment.getAttendsSet()) {
                    attendsEP.add(attends.getExecutionPeriod());
                }
                if (attendsEP.size() > 2) {
                    throw new Exception("Enrolment " + enrolment.getExternalId() + " has " + enrolment.getAttendsSet().size()
                            + " attends 2");
                }

                return attendsEP.last();
            }

            for (Attends attends : enrolment.getAttendsSet()) {
                if (attends.getExecutionPeriod().isAfter(enrolment.getExecutionPeriod())) {
                    return attends.getExecutionPeriod();
                }
            }
            return null;
        }

    }

    public static void main(String[] args) {
        processWriteTransaction(new SetImprovementEnrolmentEvaluationExecutionPeriodFromAplica());
        System.exit(0);
    }

}
