/*
 * Copyright 2010 JBoss Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.optaplanner.examples.pas.persistence;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.builder.CompareToBuilder;
import org.optaplanner.core.impl.solution.Solution;
import org.optaplanner.examples.common.domain.PersistableIdComparator;
import org.optaplanner.examples.common.persistence.AbstractTxtSolutionImporter;
import org.optaplanner.examples.pas.domain.AdmissionPart;
import org.optaplanner.examples.pas.domain.Bed;
import org.optaplanner.examples.pas.domain.BedDesignation;
import org.optaplanner.examples.pas.domain.Department;
import org.optaplanner.examples.pas.domain.DepartmentSpecialism;
import org.optaplanner.examples.pas.domain.Equipment;
import org.optaplanner.examples.pas.domain.Gender;
import org.optaplanner.examples.pas.domain.GenderLimitation;
import org.optaplanner.examples.pas.domain.Night;
import org.optaplanner.examples.pas.domain.Patient;
import org.optaplanner.examples.pas.domain.PatientAdmissionSchedule;
import org.optaplanner.examples.pas.domain.PreferredPatientEquipment;
import org.optaplanner.examples.pas.domain.RequiredPatientEquipment;
import org.optaplanner.examples.pas.domain.Room;
import org.optaplanner.examples.pas.domain.RoomEquipment;
import org.optaplanner.examples.pas.domain.RoomSpecialism;
import org.optaplanner.examples.pas.domain.Specialism;

public class PatientAdmissionScheduleImporter extends AbstractTxtSolutionImporter {

    public static void main(String[] args) {
        new PatientAdmissionScheduleImporter().convertAll();
    }

    public PatientAdmissionScheduleImporter() {
        super(new PatientAdmissionScheduleDao());
    }

    public TxtInputBuilder createTxtInputBuilder() {
        return new PatientAdmissionScheduleInputBuilder();
    }

    public static class PatientAdmissionScheduleInputBuilder extends TxtInputBuilder {

        private PatientAdmissionSchedule patientAdmissionSchedule;

        private int specialismListSize;
        private int departmentListSize;
        private int equipmentListSize;
        private int roomListSize;
        private int bedListSize;
        private int nightListSize;
        private int patientListSize;

        private Map<Long, Specialism> idToSpecialismMap = null;
        private Map<Long, Department> idToDepartmentMap = null;
        private Map<Integer, Equipment> indexToEquipmentMap = null;
        private Map<Long, Room> idToRoomMap = null;
        private Map<Integer, Night> indexToNightMap = null;

        public Solution readSolution() throws IOException {
            patientAdmissionSchedule = new PatientAdmissionSchedule();
            patientAdmissionSchedule.setId(0L);
            readSizes();
            readEmptyLine();
            readEmptyLine();
            readSpecialismList();
            readEmptyLine();
            readDepartmentListAndDepartmentSpecialismList();
            readEmptyLine();
            readEquipmentList();
            readEmptyLine();
            readRoomListAndRoomSpecialismListAndRoomEquipmentList();
            readEmptyLine();
            readBedList();
            readEmptyLine();
            generateNightList();
            readPatientListAndAdmissionPartListAndRequiredPatientEquipmentListAndPreferredPatientEquipmentList();
            readEmptyLine();
            readConstantLine("END.");
            createBedDesignationList();
            // TODO not all nights are planned, only the "planning horizon" nights are planned
            BigInteger possibleSolutionSize = BigInteger.valueOf(patientAdmissionSchedule.getBedList().size()).pow(
                    patientAdmissionSchedule.getAdmissionPartList().size());
            logger.info("PatientAdmissionSchedule {} has {} specialisms, {} equipments, {} departments, {} rooms, "
                    + "{} beds, {} nights, {} patients and {} admissions with a search space of {}.",
                    getInputId(),
                    patientAdmissionSchedule.getSpecialismList().size(),
                    patientAdmissionSchedule.getEquipmentList().size(),
                    patientAdmissionSchedule.getDepartmentList().size(),
                    patientAdmissionSchedule.getRoomList().size(),
                    patientAdmissionSchedule.getBedList().size(),
                    patientAdmissionSchedule.getNightList().size(),
                    patientAdmissionSchedule.getPatientList().size(),
                    patientAdmissionSchedule.getAdmissionPartList().size(),
                    getFlooredPossibleSolutionSize(possibleSolutionSize));
            return patientAdmissionSchedule;
        }

        private void readSizes() throws IOException {
            readConstantLine("ARTICLE BENCHMARK DATA SET");
            roomListSize = readIntegerValue("Rooms:");
            equipmentListSize = readIntegerValue("Roomproperties:");
            bedListSize = readIntegerValue("Beds:");
            departmentListSize = readIntegerValue("Departments:");
            specialismListSize = readIntegerValue("Specialisms:");
            patientListSize = readIntegerValue("Patients:");
            nightListSize = readIntegerValue("Planning horizon:");
        }

        private void readSpecialismList() throws IOException {
            readConstantLine("SPECIALISMS:");
            List<Specialism> specialismList = new ArrayList<Specialism>(specialismListSize);
            idToSpecialismMap = new HashMap<Long, Specialism>(specialismListSize);
            for (int i = 0; i < specialismListSize; i++) {
                String line = bufferedReader.readLine();
                String[] lineTokens = splitBySpace(line, 2);
                Specialism specialism = new Specialism();
                specialism.setId(Long.parseLong(lineTokens[0]));
                specialism.setName(lineTokens[1]);
                specialismList.add(specialism);
                idToSpecialismMap.put(specialism.getId(), specialism);
            }
            patientAdmissionSchedule.setSpecialismList(specialismList);
        }

        private void readDepartmentListAndDepartmentSpecialismList() throws IOException {
            readConstantLine("DEPARTMENTS:");
            List<Department> departmentList = new ArrayList<Department>(departmentListSize);
            idToDepartmentMap = new HashMap<Long, Department>(departmentListSize);
            List<DepartmentSpecialism> departmentSpecialismList = new ArrayList<DepartmentSpecialism>(
                    departmentListSize * 5);
            long departmentSpecialismId = 0L;
            for (int i = 0; i < departmentListSize; i++) {
                String line = bufferedReader.readLine();
                String[] lineTokens = splitByPipelineAndTrim(line, 2);

                String[] departmentTokens = splitBySpace(lineTokens[0], 4);
                Department department = new Department();
                department.setId(Long.parseLong(departmentTokens[0]));
                department.setName(departmentTokens[1]);
                department.setRoomList(new ArrayList<Room>());
                int minimumAge = Integer.parseInt(departmentTokens[2]);
                if (minimumAge != 0) {
                    department.setMinimumAge(Integer.valueOf(minimumAge));
                }
                int maximumAge = Integer.parseInt(departmentTokens[3]);
                if (maximumAge != 0) {
                    department.setMaximumAge(Integer.valueOf(maximumAge));
                }
                departmentList.add(department);
                idToDepartmentMap.put(department.getId(), department);

                String[] departmentSpecialismTokens = splitBySpace(lineTokens[1]);
                if (departmentSpecialismTokens.length % 2 != 0) {
                    throw new IllegalArgumentException("Read line (" + line
                            + ") is expected to contain even number of tokens (" + departmentSpecialismTokens.length
                            + ") after 1st pipeline (|) separated by a space ( ).");
                }
                for (int j = 0; j < departmentSpecialismTokens.length; j += 2) {
                    long specialismId = Long.parseLong(departmentSpecialismTokens[j + 1]);
                    if (specialismId != 0) {
                        DepartmentSpecialism departmentSpecialism = new DepartmentSpecialism();
                        departmentSpecialism.setId(departmentSpecialismId);
                        departmentSpecialism.setDepartment(department);
                        departmentSpecialism.setPriority(Integer.parseInt(departmentSpecialismTokens[j]));
                        Specialism specialism = idToSpecialismMap.get(specialismId);
                        if (specialism == null) {
                            throw new IllegalArgumentException("Read line (" + line
                                    + ") has a non existing specialismId (" + specialismId + ").");
                        }
                        departmentSpecialism.setSpecialism(specialism);
                        departmentSpecialismList.add(departmentSpecialism);
                        departmentSpecialismId++;
                    }
                }
            }
            Collections.sort(departmentList, new PersistableIdComparator());
            patientAdmissionSchedule.setDepartmentList(departmentList);
            patientAdmissionSchedule.setDepartmentSpecialismList(departmentSpecialismList);
        }

        private void readEquipmentList() throws IOException {
            readConstantLine("ROOMPROPERTIES:");
            List<Equipment> equipmentList = new ArrayList<Equipment>(equipmentListSize);
            indexToEquipmentMap = new HashMap<Integer, Equipment>(equipmentListSize);
            for (int i = 0; i < equipmentListSize; i++) {
                String line = bufferedReader.readLine();
                String[] lineTokens = splitBySpace(line, 2);
                Equipment equipment = new Equipment();
                equipment.setId(Long.parseLong(lineTokens[0]));
                equipment.setName(lineTokens[1]);
                equipmentList.add(equipment);
                indexToEquipmentMap.put(i, equipment);
            }
            patientAdmissionSchedule.setEquipmentList(equipmentList);
        }

        private void readRoomListAndRoomSpecialismListAndRoomEquipmentList() throws IOException {
            readConstantLine("ROOMS:");
            List<Room> roomList = new ArrayList<Room>(roomListSize);
            idToRoomMap = new HashMap<Long, Room>(roomListSize);
            List<RoomSpecialism> roomSpecialismList = new ArrayList<RoomSpecialism>(roomListSize * 5);
            List<RoomEquipment> roomEquipmentList = new ArrayList<RoomEquipment>(roomListSize * 2);
            long roomSpecialismId = 0L;
            long roomEquipmentId = 0L;
            for (int i = 0; i < roomListSize; i++) {
                String line = bufferedReader.readLine();
                String[] lineTokens = splitByPipelineAndTrim(line, 6);

                String[] roomTokens = splitBySpace(lineTokens[0], 2);
                Room room = new Room();
                room.setId(Long.parseLong(roomTokens[0]));
                room.setName(roomTokens[1]);
                room.setCapacity(Integer.parseInt(lineTokens[1]));
                Department department = idToDepartmentMap.get(
                        Long.parseLong(lineTokens[2]));
                room.setDepartment(department);
                room.setGenderLimitation(GenderLimitation.valueOfCode(lineTokens[3]));
                room.setBedList(new ArrayList<Bed>());
                roomList.add(room);
                idToRoomMap.put(room.getId(), room);
                department.getRoomList().add(room);

                String[] roomSpecialismTokens = splitBySpace(lineTokens[4]);
                if (roomSpecialismTokens.length % 2 != 0) {
                    throw new IllegalArgumentException("Read line (" + line
                            + ") is expected to contain even number of tokens (" + roomSpecialismTokens.length
                            + ") after 4th pipeline (|) separated by a space ( ).");
                }
                List<RoomSpecialism> roomSpecialismListOfRoom = new ArrayList<RoomSpecialism>(roomSpecialismTokens.length / 2);
                for (int j = 0; j < roomSpecialismTokens.length; j += 2) {
                    int priority = Integer.parseInt(roomSpecialismTokens[j]);
                    long specialismId = Long.parseLong(roomSpecialismTokens[j + 1]);
                    if (specialismId != 0) {
                        RoomSpecialism roomSpecialism = new RoomSpecialism();
                        roomSpecialism.setId(roomSpecialismId);
                        roomSpecialism.setRoom(room);
                        Specialism specialism = idToSpecialismMap.get(specialismId);
                        if (specialism == null) {
                            throw new IllegalArgumentException("Read line (" + line
                                    + ") has a non existing specialismId (" + specialismId + ").");
                        }
                        roomSpecialism.setSpecialism(specialism);
                        roomSpecialism.setPriority(priority);
                        roomSpecialismListOfRoom.add(roomSpecialism);
                        roomSpecialismList.add(roomSpecialism);
                        roomSpecialismId++;
                    }
                }
                room.setRoomSpecialismList(roomSpecialismListOfRoom);

                List<RoomEquipment> roomEquipmentListOfRoom = new ArrayList<RoomEquipment>(equipmentListSize);
                String[] roomEquipmentTokens = splitBySpace(lineTokens[5]);
                if (roomEquipmentTokens.length != equipmentListSize) {
                    throw new IllegalArgumentException("Read line (" + line
                            + ") is expected to contain equal number of tokens (" + roomEquipmentTokens.length
                            + ") as equipmentListSize (" + equipmentListSize + ") after 5th pipeline (|).");
                }
                for (int j = 0; j < roomEquipmentTokens.length; j++) {
                    int hasEquipment = Integer.parseInt(roomEquipmentTokens[j]);
                    if (hasEquipment == 1) {
                        RoomEquipment roomEquipment = new RoomEquipment();
                        roomEquipment.setId(roomEquipmentId);
                        roomEquipment.setRoom(room);
                        roomEquipment.setEquipment(indexToEquipmentMap.get(j));
                        roomEquipmentListOfRoom.add(roomEquipment);
                        roomEquipmentList.add(roomEquipment);
                        roomEquipmentId++;
                    } else if (hasEquipment != 0) {
                        throw new IllegalArgumentException("Read line (" + line
                                + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
                    }
                }
                room.setRoomEquipmentList(roomEquipmentListOfRoom);
            }
            Collections.sort(roomList, new Comparator<Room>() {
                public int compare(Room a, Room b) {
                    return new CompareToBuilder()
                            .append(a.getDepartment().getId(), b.getDepartment().getId())
                            .append(a.getId(), b.getId())
                            .toComparison();
                }
            });
            patientAdmissionSchedule.setRoomList(roomList);
            patientAdmissionSchedule.setRoomSpecialismList(roomSpecialismList);
            patientAdmissionSchedule.setRoomEquipmentList(roomEquipmentList);
        }

        private void readBedList() throws IOException {
            readConstantLine("BEDS:");
            List<Bed> bedList = new ArrayList<Bed>(bedListSize);
            Map<Room, Integer> roomToLastIndexInRoomMap = new HashMap<Room, Integer>(roomListSize);
            for (int i = 0; i < bedListSize; i++) {
                String line = bufferedReader.readLine();
                String[] lineTokens = splitBySpace(line, 2);
                Bed bed = new Bed();
                bed.setId(Long.parseLong(lineTokens[0]));
                Room room = idToRoomMap.get(Long.parseLong(lineTokens[1]));
                bed.setRoom(room);
                Integer indexInRoom = roomToLastIndexInRoomMap.get(room);
                if (indexInRoom == null) {
                    indexInRoom = 0;
                } else {
                    indexInRoom++;
                }
                bed.setIndexInRoom(indexInRoom);
                roomToLastIndexInRoomMap.put(room, indexInRoom);
                bedList.add(bed);
                room.getBedList().add(bed);
            }
            Collections.sort(bedList, new Comparator<Bed>() {
                public int compare(Bed a, Bed b) {
                    return new CompareToBuilder()
                            .append(a.getRoom().getDepartment().getId(), b.getRoom().getDepartment().getId())
                            .append(a.getRoom().getId(), b.getRoom().getId())
                            .append(a.getIndexInRoom(), b.getIndexInRoom())
                            .append(a.getId(), b.getId())
                            .toComparison();
                }
            });
            patientAdmissionSchedule.setBedList(bedList);
        }

        private void generateNightList() {
            List<Night> nightList = new ArrayList<Night>(nightListSize);
            indexToNightMap = new HashMap<Integer, Night>(nightListSize);
            long nightId = 0L;
            for (int i = 0; i < nightListSize; i++) {
                Night night = new Night();
                night.setId(nightId);
                night.setIndex(i);
                nightList.add(night);
                indexToNightMap.put(i, night);
                nightId++;
            }
            patientAdmissionSchedule.setNightList(nightList);
        }

        private void readPatientListAndAdmissionPartListAndRequiredPatientEquipmentListAndPreferredPatientEquipmentList() throws IOException {
            readConstantLine("PATIENTS:");
            List<Patient> patientList = new ArrayList<Patient>(patientListSize);
            List<AdmissionPart> admissionPartList = new ArrayList<AdmissionPart>(patientListSize);
            List<RequiredPatientEquipment> requiredPatientEquipmentList = new ArrayList<RequiredPatientEquipment>(patientListSize * equipmentListSize);
            List<PreferredPatientEquipment> preferredPatientEquipmentList = new ArrayList<PreferredPatientEquipment>(patientListSize * equipmentListSize);
            long admissionPartId = 0L;
            long requiredPatientEquipmentId = 0L;
            long preferredPatientEquipmentId = 0L;
            for (int i = 0; i < patientListSize; i++) {
                String line = bufferedReader.readLine();
                String[] lineTokens = splitByPipelineAndTrim(line, 6);

                String[] nightTokens = splitBySpace(lineTokens[1], 2);
                int firstNightIndex = Integer.parseInt(nightTokens[0]);
                int lastNightIndex = Integer.parseInt(nightTokens[1]);
                int patientNightListSize = lastNightIndex - firstNightIndex;
                // A patient with no nights in the planning horizon or no nights at all is ignored
                if (firstNightIndex >= nightListSize || patientNightListSize == 0) {
                    continue;
                }

                String[] patientTokens = splitBySpace(lineTokens[0], 4);
                Patient patient = new Patient();
                patient.setId(Long.parseLong(patientTokens[0]));
                patient.setName(patientTokens[1]);
                patient.setAge(Integer.parseInt(patientTokens[2]));
                patient.setGender(Gender.valueOfCode(patientTokens[3]));
                int preferredMaximumRoomCapacity = Integer.parseInt(lineTokens[3]);
                patient.setPreferredMaximumRoomCapacity(preferredMaximumRoomCapacity == 0
                        ? null : preferredMaximumRoomCapacity);
                patientList.add(patient);

                String[] admissionPartTokens = splitBySpace(lineTokens[2]);
                int patientAdmissionPartListSize = Integer.parseInt(admissionPartTokens[0]);
                if (admissionPartTokens.length != ((patientAdmissionPartListSize * 2) + 1)) {
                    throw new IllegalArgumentException("Read line (" + line
                            + ") is expected to contain " + ((patientAdmissionPartListSize * 2) + 1)
                            + " number of tokens after 2th pipeline (|).");
                }
                int nextFirstNightIndex = firstNightIndex;
                for (int j = 1; j < admissionPartTokens.length; j += 2) {
                    long specialismId = Long.parseLong(admissionPartTokens[j]);
                    int admissionPartNightListSize = Integer.parseInt(admissionPartTokens[j + 1]);
                    if (nextFirstNightIndex >= nightListSize || admissionPartNightListSize == 0) {
                        nextFirstNightIndex += admissionPartNightListSize;
                        continue;
                    }
                    AdmissionPart admissionPart = new AdmissionPart();
                    admissionPart.setId(admissionPartId);
                    admissionPart.setPatient(patient);
                    Specialism specialism = (specialismId == 0) ? null : idToSpecialismMap.get(specialismId);
                    if (specialism == null) {
                        throw new IllegalArgumentException("Read line (" + line
                                + ") has a non existing specialismId (" + specialismId + ").");
                    }
                    admissionPart.setSpecialism(specialism);
                    int admissionPartFirstNightIndex = nextFirstNightIndex;
                    Night admissionPartFirstNight = indexToNightMap.get(admissionPartFirstNightIndex);
                    if (admissionPartFirstNight == null) {
                        throw new IllegalStateException(
                                "The admissionPartFirstNight was not found for admissionPartFirstNightIndex("
                                        + admissionPartFirstNightIndex + ").");
                    }
                    admissionPart.setFirstNight(admissionPartFirstNight);
                    int admissionPartLastNightIndex = nextFirstNightIndex + admissionPartNightListSize - 1;
                    // TODO Instead of ensureEnoughNights(lastNightIndex);
                    // the official score function ignores any broken constraints after the planning horizon
                    if (admissionPartLastNightIndex >= nightListSize) {
                        admissionPartLastNightIndex = nightListSize - 1;
                    }
                    Night admissionPartLastNight = indexToNightMap.get(admissionPartLastNightIndex);
                    if (admissionPartLastNight == null) {
                        throw new IllegalStateException(
                                "The admissionPartLastNight was not found for admissionPartLastNightIndex("
                                        + admissionPartLastNightIndex + ").");
                    }
                    admissionPart.setLastNight(admissionPartLastNight);
                    admissionPartList.add(admissionPart);
                    admissionPartId++;
                    nextFirstNightIndex += admissionPartNightListSize;
                }
                int admissionPartNightListSizeSum = nextFirstNightIndex - firstNightIndex;
                if (patientNightListSize != admissionPartNightListSizeSum) {
                    throw new IllegalArgumentException("Read line (" + line
                            + ") has patientNightListSize (" + patientNightListSize
                            + ") different from admissionPartNightListSizeSum(" + admissionPartNightListSizeSum + ")");
                }

                String[] requiredPatientEquipmentTokens = splitBySpace(lineTokens[4]);
                if (requiredPatientEquipmentTokens.length != equipmentListSize) {
                    throw new IllegalArgumentException("Read line (" + line
                            + ") is expected to contain equal number of tokens ("
                            + requiredPatientEquipmentTokens.length
                            + ") as equipmentListSize (" + equipmentListSize + ") after 4th pipeline (|).");
                }
                List<RequiredPatientEquipment> requiredPatientEquipmentOfPatientList
                        = new ArrayList<RequiredPatientEquipment>(equipmentListSize);
                for (int j = 0; j < requiredPatientEquipmentTokens.length; j++) {
                    int hasEquipment = Integer.parseInt(requiredPatientEquipmentTokens[j]);
                    if (hasEquipment == 1) {
                        RequiredPatientEquipment requiredPatientEquipment = new RequiredPatientEquipment();
                        requiredPatientEquipment.setId(requiredPatientEquipmentId);
                        requiredPatientEquipment.setPatient(patient);
                        requiredPatientEquipment.setEquipment(indexToEquipmentMap.get(j));
                        requiredPatientEquipmentOfPatientList.add(requiredPatientEquipment);
                        requiredPatientEquipmentList.add(requiredPatientEquipment);
                        requiredPatientEquipmentId++;
                    } else if (hasEquipment != 0) {
                        throw new IllegalArgumentException("Read line (" + line
                                + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
                    }
                }
                patient.setRequiredPatientEquipmentList(requiredPatientEquipmentOfPatientList);

                String[] preferredPatientEquipmentTokens = splitBySpace(lineTokens[5]);
                if (preferredPatientEquipmentTokens.length != equipmentListSize) {
                    throw new IllegalArgumentException("Read line (" + line
                            + ") is expected to contain equal number of tokens ("
                            + preferredPatientEquipmentTokens.length
                            + ") as equipmentListSize (" + equipmentListSize + ") after 5th pipeline (|).");
                }
                List<PreferredPatientEquipment> preferredPatientEquipmentOfPatientList
                        = new ArrayList<PreferredPatientEquipment>(equipmentListSize);
                for (int j = 0; j < preferredPatientEquipmentTokens.length; j++) {
                    int hasEquipment = Integer.parseInt(preferredPatientEquipmentTokens[j]);
                    if (hasEquipment == 1) {
                        boolean alreadyRequired = (Integer.parseInt(requiredPatientEquipmentTokens[j]) == 1);
                        // Official spec: if equipment is required
                        // then a duplicate preffered constraint should be ignored 
                        if (!alreadyRequired) {
                            PreferredPatientEquipment preferredPatientEquipment = new PreferredPatientEquipment();
                            preferredPatientEquipment.setId(preferredPatientEquipmentId);
                            preferredPatientEquipment.setPatient(patient);
                            preferredPatientEquipment.setEquipment(indexToEquipmentMap.get(j));
                            preferredPatientEquipmentOfPatientList.add(preferredPatientEquipment);
                            preferredPatientEquipmentList.add(preferredPatientEquipment);
                            preferredPatientEquipmentId++;
                        }
                    } else if (hasEquipment != 0) {
                        throw new IllegalArgumentException("Read line (" + line
                                + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
                    }
                }
                patient.setPreferredPatientEquipmentList(preferredPatientEquipmentOfPatientList);
            }
            patientAdmissionSchedule.setPatientList(patientList);
            patientAdmissionSchedule.setAdmissionPartList(admissionPartList);
            patientAdmissionSchedule.setRequiredPatientEquipmentList(requiredPatientEquipmentList);
            patientAdmissionSchedule.setPreferredPatientEquipmentList(preferredPatientEquipmentList);
        }

//        /**
//         * hack to make sure there are enough nights
//         * @param lastNightIndex >= 0
//         */
//        private void ensureEnoughNights(int lastNightIndex) {
//            List<Night> nightList = patientAdmissionSchedule.getNightList();
//            if (lastNightIndex >= nightList.size()) {
//                long nightId = nightList.size();
//                for (int j = nightList.size(); j <= lastNightIndex; j++) {
//                    Night night = new Night();
//                    night.setId(nightId);
//                    night.setIndex(j);
//                    nightList.add(night);
//                    indexToNightMap.put(j, night);
//                    nightId++;
//                }
//            }
//        }

        private void createBedDesignationList() {
            List<AdmissionPart> admissionPartList = patientAdmissionSchedule.getAdmissionPartList();
            List<BedDesignation> bedDesignationList = new ArrayList<BedDesignation>(admissionPartList.size());
            long id = 0L;
            for (AdmissionPart admissionPart : admissionPartList) {
                BedDesignation bedDesignation = new BedDesignation();
                bedDesignation.setId(id);
                id++;
                bedDesignation.setAdmissionPart(admissionPart);
                // Notice that we leave the PlanningVariable properties on null
                bedDesignationList.add(bedDesignation);
            }
            patientAdmissionSchedule.setBedDesignationList(bedDesignationList);
        }

    }

}
