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

import java.io.FileOutputStream;
import java.util.Set;

import net.sourceforge.fenixedu.domain.Enrolment;
import net.sourceforge.fenixedu.domain.IEnrolment;
import net.sourceforge.fenixedu.domain.StudentCurricularPlan;
import net.sourceforge.fenixedu.domain.student.Registration;
import net.sourceforge.fenixedu.domain.student.registrationStates.RegistrationStateType;
import net.sourceforge.fenixedu.domain.studentCurriculum.Credits;
import net.sourceforge.fenixedu.domain.studentCurriculum.Dismissal;
import net.sourceforge.fenixedu.domain.studentCurriculum.Equivalence;
import net.sourceforge.fenixedu.domain.studentCurriculum.ExternalEnrolment;
import net.sourceforge.fenixedu.domain.studentCurriculum.Substitution;
import pt.utl.ist.fenix.tools.util.excel.Spreadsheet;
import pt.utl.ist.fenix.tools.util.excel.Spreadsheet.Row;
import pt.utl.ist.scripts.commons.AtomicScript;

public class UpdateEquivalenceClass extends AtomicScript {

    Spreadsheet spreadsheet = new Spreadsheet("");
    Spreadsheet spreadsheetEquivalence = new Spreadsheet("");

    @Override
    protected void run() throws Exception {
        for (Credits credits : rootDomainObject.getCreditsSet()) {
            if (credits.isEquivalence()) {
                processEquivalence((Equivalence) credits);
            }
        }

        spreadsheet.exportToCSV(new FileOutputStream(EXPORT_DIR_PATH + "/equivalenceToSubstitution.csv"), "\t");
        spreadsheetEquivalence.exportToCSV(new FileOutputStream(EXPORT_DIR_PATH + "/equivalenceNotChanged.csv"), "\t");
    }

    private void processEquivalence(Equivalence equivalence) {

        if (hasAzoresEquivalence(equivalence) || hasErasmusEquivalence(equivalence) || hasSameISTDegree(equivalence)
                || hasNotConcludedISTDegree(equivalence)) {
            logger.info(equivalence.getStudentCurricularPlan().getRegistration().getStudent().getNumber() + "\t"
                    + equivalence.getExternalId());
            Row row = spreadsheet.addRow();
            row.setCell(equivalence.getStudentCurricularPlan().getRegistration().getStudent().getNumber().toString());
            StringBuilder stringBuilder = new StringBuilder();
            for (IEnrolment enrolment : equivalence.getIEnrolments()) {
                stringBuilder.append(enrolment.getName() + "|");
            }
            row.setCell(stringBuilder.toString());

            StringBuilder stringBuilder2 = new StringBuilder();
            for (Dismissal dismissal : equivalence.getDismissalsSet()) {
                stringBuilder2.append(dismissal.getName() + "|");
            }
            row.setCell(stringBuilder2.toString());
            row.setCell(equivalence.getExecutionPeriod().getQualifiedName());
            row.setCell(equivalence.getGivenGrade());

            changeToSubstitution(equivalence);
        } else {
            Row row = spreadsheetEquivalence.addRow();
            row.setCell(equivalence.getStudentCurricularPlan().getRegistration().getStudent().getNumber().toString());
            StringBuilder stringBuilder = new StringBuilder();
            for (IEnrolment enrolment : equivalence.getIEnrolments()) {
                stringBuilder.append(enrolment.getName() + "|");
            }
            row.setCell(stringBuilder.toString());

            StringBuilder stringBuilder2 = new StringBuilder();
            for (Dismissal dismissal : equivalence.getDismissalsSet()) {
                stringBuilder2.append(dismissal.getName() + "|");
            }
            row.setCell(stringBuilder2.toString());
            row.setCell(equivalence.getExecutionPeriod().getQualifiedName());
            row.setCell(equivalence.getGivenGrade());

        }
    }

    private void changeToSubstitution(Equivalence equivalence) {

        Substitution substitution = new Substitution();
        substitution.setStudentCurricularPlan(equivalence.getStudentCurricularPlan());
        substitution.getDismissals().addAll(equivalence.getDismissals());
        substitution.getEnrolments().addAll(equivalence.getEnrolments());
        substitution.setExecutionPeriod(equivalence.getExecutionPeriod());
        substitution.setGrade(equivalence.getGrade());

        equivalence.delete();
    }

    private boolean hasNotConcludedISTDegree(Equivalence equivalence) {
        for (IEnrolment iEnrolment : equivalence.getIEnrolments()) {
            if (!iEnrolment.isExternalEnrolment()) {
                Enrolment enrolment = (Enrolment) iEnrolment;
                if (isNotConcludedISTDegree(enrolment)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isNotConcludedISTDegree(Enrolment enrolment) {
        return enrolment.getRegistration().getActiveStateType() != RegistrationStateType.CONCLUDED;
    }

    private boolean hasSameISTDegree(Equivalence equivalence) {
        for (IEnrolment iEnrolment : equivalence.getIEnrolments()) {
            if (!iEnrolment.isExternalEnrolment()) {
                Enrolment enrolment = (Enrolment) iEnrolment;
                if (isSameISTDegree(enrolment, equivalence.getStudentCurricularPlan())) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isSameISTDegree(Enrolment enrolment, StudentCurricularPlan studentCurricularPlan) {
        return enrolment.getStudentCurricularPlan().getDegree() == studentCurricularPlan.getDegree();
    }

    private boolean hasErasmusEquivalence(Equivalence equivalence) {
        for (IEnrolment enrolment : equivalence.getIEnrolments()) {
            if (enrolment.isExternalEnrolment()) {
                ExternalEnrolment externalEnrolment = (ExternalEnrolment) enrolment;
                if (isErasmusExternalEnrolment(externalEnrolment, equivalence.getStudentCurricularPlan().getRegistration())) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isErasmusExternalEnrolment(ExternalEnrolment externalEnrolment, Registration registration) {
        if (externalEnrolment.getExecutionYear() != null) {
            Set<RegistrationStateType> registrationStates =
                    registration.getRegistrationStatesTypes(externalEnrolment.getExecutionYear());
            if (registrationStates.contains(RegistrationStateType.MOBILITY)) {
                return externalEnrolment.getExternalCurricularCourse().getFullPathName().indexOf("Portugal") == -1;
            }
        }
        return false;
    }

    private boolean hasAzoresEquivalence(Equivalence equivalence) {
        // if(equivalence.getStudentCurricularPlan().getRegistration().getIngressionEnum()
        // == Ingression.CNA02) {
        for (IEnrolment enrolment : equivalence.getIEnrolments()) {
            if (enrolment.isExternalEnrolment()) {
                ExternalEnrolment externalEnrolment = (ExternalEnrolment) enrolment;
                if (isAzoresExternalEnrolment(externalEnrolment)) {
                    return true;
                }
            }
        }
        // }
        return false;
    }

    private boolean isAzoresExternalEnrolment(ExternalEnrolment externalEnrolment) {
        return !externalEnrolment.getRegistration().isConcluded()
                && externalEnrolment.getExternalCurricularCourse().getFullPathName().indexOf("Açores") != -1;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        processWriteTransaction(new UpdateEquivalenceClass());
        System.exit(0);
    }

}
