////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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.
////

= Model the domain objects
:imagesdir: ../..

Your goal is to assign each lesson to a time slot and a room.
You will create these classes:

image::quickstart/school-timetabling/schoolTimetablingClassDiagramPure.png[]

== Timeslot

The `Timeslot` class represents a time interval when lessons are taught,
for example, `Monday 10:30 - 11:30` or `Tuesday 13:30 - 14:30`.
For simplicity's sake, all time slots have the same duration
and there are no time slots during lunch or other breaks.

A time slot has no date, because a high school schedule just repeats every week.
So there is no need for xref:repeated-planning/repeated-planning.adoc#continuousPlanning[continuous planning].

Create the `src/main/java/org/acme/schooltimetabling/domain/Timeslot.java` class:

[source,java]
----
package org.acme.schooltimetabling.domain;

import java.time.DayOfWeek;
import java.time.LocalTime;

public class Timeslot {

    private DayOfWeek dayOfWeek;
    private LocalTime startTime;
    private LocalTime endTime;

    public Timeslot() {
    }

    public Timeslot(DayOfWeek dayOfWeek, LocalTime startTime, LocalTime endTime) {
        this.dayOfWeek = dayOfWeek;
        this.startTime = startTime;
        this.endTime = endTime;
    }

    public DayOfWeek getDayOfWeek() {
        return dayOfWeek;
    }

    public LocalTime getStartTime() {
        return startTime;
    }

    public LocalTime getEndTime() {
        return endTime;
    }

    @Override
    public String toString() {
        return dayOfWeek + " " + startTime;
    }

}
----

Because no `Timeslot` instances change during solving, a `Timeslot` is called a _problem fact_.
Such classes do not require any OptaPlanner specific annotations.

Notice the `toString()` method keeps the output short,
so it is easier to read OptaPlanner's `DEBUG` or `TRACE` log, as shown later.

== Room

The `Room` class represents a location where lessons are taught,
for example, `Room A` or `Room B`.
For simplicity's sake, all rooms are without capacity limits
and they can accommodate all lessons.

Create the `src/main/java/org/acme/schooltimetabling/domain/Room.java` class:

[source,java]
----
package org.acme.schooltimetabling.domain;

public class Room {

    private String name;

    public Room() {
    }

    public Room(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return name;
    }

}
----

`Room` instances do not change during solving, so `Room` is also a _problem fact_.

== Lesson

During a lesson, represented by the `Lesson` class,
a teacher teaches a subject to a group of students,
for example, `Math by A.Turing for 9th grade` or `Chemistry by M.Curie for 10th grade`.
If a subject is taught multiple times per week by the same teacher to the same student group,
there are multiple `Lesson` instances that are only distinguishable by `id`.
For example, the 9th grade has six math lessons a week.

During solving, OptaPlanner changes the `timeslot` and `room` fields of the `Lesson` class,
to assign each lesson to a time slot and a room.
Because OptaPlanner changes these fields, `Lesson` is a _planning entity_:

image::quickstart/school-timetabling/schoolTimetablingClassDiagramAnnotated.png[]

Most of the fields in the previous diagram contain input data, except for the orange fields:
A lesson's `timeslot` and `room` fields are unassigned (`null`) in the input data
and assigned (not `null`) in the output data.
OptaPlanner changes these fields during solving.
Such fields are called planning variables.
In order for OptaPlanner to recognize them,
both the `timeslot` and `room` fields require an `@PlanningVariable` annotation.
Their containing class, `Lesson`, requires an `@PlanningEntity` annotation.

Create the `src/main/java/org/acme/schooltimetabling/domain/Lesson.java` class:

[source,java]
----
package org.acme.schooltimetabling.domain;

import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.lookup.PlanningId;
import org.optaplanner.core.api.domain.variable.PlanningVariable;

@PlanningEntity
public class Lesson {

    @PlanningId
    private Long id;

    private String subject;
    private String teacher;
    private String studentGroup;

    @PlanningVariable
    private Timeslot timeslot;
    @PlanningVariable
    private Room room;

    public Lesson() {
    }

    public Lesson(Long id, String subject, String teacher, String studentGroup) {
        this.id = id;
        this.subject = subject;
        this.teacher = teacher;
        this.studentGroup = studentGroup;
    }

    public Long getId() {
        return id;
    }

    public String getSubject() {
        return subject;
    }

    public String getTeacher() {
        return teacher;
    }

    public String getStudentGroup() {
        return studentGroup;
    }

    public Timeslot getTimeslot() {
        return timeslot;
    }

    public void setTimeslot(Timeslot timeslot) {
        this.timeslot = timeslot;
    }

    public Room getRoom() {
        return room;
    }

    public void setRoom(Room room) {
        this.room = room;
    }

    @Override
    public String toString() {
        return subject + "(" + id + ")";
    }

}
----

The `Lesson` class has an `@PlanningEntity` annotation,
so OptaPlanner knows that this class changes during solving
because it contains one or more planning variables.

The `timeslot` field has an `@PlanningVariable` annotation,
so OptaPlanner knows that it can change its value.
In order to find potential `Timeslot` instances to assign to this field,
OptaPlanner uses the variable type to connect to a xref:planner-configuration/planner-configuration.adoc#planningValueRangeProvider[value range provider]
that provides a `List<Timeslot>` to pick from.

The `room` field also has an `@PlanningVariable` annotation, for the same reasons.

[NOTE]
====
Determining the `@PlanningVariable` fields for an arbitrary constraint solving use case
is often challenging the first time.
Read xref:design-patterns/design-patterns.adoc#domainModelingGuide[the domain modeling guidelines] to avoid common pitfalls.
====
