7f4318dcfa82c014c8ecf52ed15f47b68ed2bb41
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / courseFormat / Task.java
1 package com.jetbrains.edu.learning.courseFormat;
2
3 import com.google.gson.annotations.Expose;
4 import com.google.gson.annotations.SerializedName;
5 import com.intellij.openapi.editor.Document;
6 import com.intellij.openapi.fileEditor.FileDocumentManager;
7 import com.intellij.openapi.project.Project;
8 import com.intellij.openapi.util.text.StringUtil;
9 import com.intellij.openapi.vfs.VirtualFile;
10 import com.intellij.util.xmlb.XmlSerializer;
11 import com.intellij.util.xmlb.annotations.Transient;
12 import com.jetbrains.edu.learning.StudyUtils;
13 import com.jetbrains.edu.learning.core.EduNames;
14 import com.jetbrains.edu.learning.stepic.EduStepicConnector;
15 import org.jdom.Element;
16 import org.jetbrains.annotations.NotNull;
17 import org.jetbrains.annotations.Nullable;
18
19 import java.util.Date;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 /**
24  * Implementation of task which contains task files, tests, input file for tests
25  */
26 public class Task implements StudyItem {
27   @Expose private String name;
28
29   // index is visible to user number of task from 1 to task number
30   private int myIndex;
31   private StudyStatus myStatus = StudyStatus.Unchecked;
32
33   @SerializedName("stepic_id")
34   @Expose private int myStepId;
35   
36   @SerializedName("task_files")
37   @Expose public Map<String, TaskFile> taskFiles = new HashMap<>();
38
39   private String text;
40   private Map<String, String> testsText = new HashMap<>();
41
42   @Transient private Lesson myLesson;
43   @Expose @SerializedName("update_date") private Date myUpdateDate;
44
45   private int myActiveStepIndex = 0;
46
47   public Task() {}
48
49   public Task(@NotNull final String name) {
50     this.name = name;
51   }
52
53   /**
54    * Initializes state of task file
55    *
56    * @param lesson lesson which task belongs to
57    */
58   public void initTask(final Lesson lesson, boolean isRestarted) {
59     setLesson(lesson);
60     if (!isRestarted) myStatus = StudyStatus.Unchecked;
61     for (TaskFile taskFile : getTaskFiles().values()) {
62       taskFile.initTaskFile(this, isRestarted);
63     }
64   }
65
66   public String getName() {
67     return name;
68   }
69
70   public void setName(String name) {
71     this.name = name;
72   }
73
74   public String getText() {
75     return text;
76   }
77
78   public void setText(final String text) {
79     this.text = text;
80   }
81
82   public int getIndex() {
83     return myIndex;
84   }
85
86   public void setIndex(int index) {
87     myIndex = index;
88   }
89
90   public Map<String, String> getTestsText() {
91     return testsText;
92   }
93
94   public void addTestsTexts(String name, String text) {
95     testsText.put(name, text);
96   }
97
98   public Map<String, TaskFile> getTaskFiles() {
99     return taskFiles;
100   }
101
102   @Nullable
103   public TaskFile getTaskFile(final String name) {
104     return name != null ? taskFiles.get(name) : null;
105   }
106
107   public boolean isTaskFile(@NotNull final String fileName) {
108     return taskFiles.get(fileName) != null;
109   }
110
111   public void addTaskFile(@NotNull final String name, int index) {
112     TaskFile taskFile = new TaskFile();
113     taskFile.setIndex(index);
114     taskFile.setTask(this);
115     taskFile.name = name;
116     taskFiles.put(name, taskFile);
117   }
118
119   public void addTaskFile(@NotNull final TaskFile taskFile) {
120     taskFiles.put(taskFile.name, taskFile);
121   }
122
123   @Nullable
124   public TaskFile getFile(@NotNull final String fileName) {
125     return taskFiles.get(fileName);
126   }
127
128   @Transient
129   public Lesson getLesson() {
130     return myLesson;
131   }
132
133   @Transient
134   public void setLesson(Lesson lesson) {
135     myLesson = lesson;
136   }
137
138   @Nullable
139   public VirtualFile getTaskDir(@NotNull final Project project) {
140     String lessonDirName = EduNames.LESSON + String.valueOf(myLesson.getIndex());
141     String taskDirName = EduNames.TASK + String.valueOf(myIndex);
142     VirtualFile courseDir = project.getBaseDir();
143     if (courseDir != null) {
144       VirtualFile lessonDir = courseDir.findChild(lessonDirName);
145       if (lessonDir != null) {
146         return lessonDir.findChild(taskDirName);
147       }
148     }
149     return null;
150   }
151
152   @NotNull
153   public String getTaskText(@NotNull final Project project) {
154     if (!StringUtil.isEmptyOrSpaces(text)) return text;
155     final VirtualFile taskDir = getTaskDir(project);
156     if (taskDir != null) {
157       final VirtualFile file = StudyUtils.findTaskDescriptionVirtualFile(taskDir);
158       if (file == null) return "";
159       final Document document = FileDocumentManager.getInstance().getDocument(file);
160       if (document != null) {
161         return document.getImmutableCharSequence().toString();
162       }
163     }
164
165     return "";
166   }
167
168   @NotNull
169   public String getTestsText(@NotNull final Project project) {
170     final VirtualFile taskDir = getTaskDir(project);
171     if (taskDir != null) {
172       final VirtualFile file = taskDir.findChild(EduNames.TESTS_FILE);
173       if (file == null) return "";
174       final Document document = FileDocumentManager.getInstance().getDocument(file);
175       if (document != null) {
176         return document.getImmutableCharSequence().toString();
177       }
178     }
179
180     return "";
181   }
182
183   @Override
184   public boolean equals(Object o) {
185     if (this == o) return true;
186     if (o == null || getClass() != o.getClass()) return false;
187
188     Task task = (Task)o;
189
190     if (myIndex != task.myIndex) return false;
191     if (name != null ? !name.equals(task.name) : task.name != null) return false;
192     if (taskFiles != null ? !taskFiles.equals(task.taskFiles) : task.taskFiles != null) return false;
193     if (text != null ? !text.equals(task.text) : task.text != null) return false;
194     if (testsText != null ? !testsText.equals(task.testsText) : task.testsText != null) return false;
195
196     return true;
197   }
198
199   @Override
200   public int hashCode() {
201     int result = name != null ? name.hashCode() : 0;
202     result = 31 * result + myIndex;
203     result = 31 * result + (taskFiles != null ? taskFiles.hashCode() : 0);
204     result = 31 * result + (text != null ? text.hashCode() : 0);
205     result = 31 * result + (testsText != null ? testsText.hashCode() : 0);
206     return result;
207   }
208
209   public void setStepId(int stepId) {
210     myStepId = stepId;
211   }
212
213   public int getStepId() {
214     return myStepId;
215   }
216
217   public StudyStatus getStatus() {
218     return myStatus;
219   }
220   
221   public void setStatus(StudyStatus status) {
222     myStatus = status;
223     for (TaskFile taskFile : taskFiles.values()) {
224       for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) {
225         placeholder.setStatus(status);
226       }
227     }
228   }
229
230   public Task copy() {
231     Element element = XmlSerializer.serialize(this);
232     Task copy = XmlSerializer.deserialize(element, Task.class);
233     if (copy == null) {
234       return null;
235     }
236     copy.initTask(null, true);
237     return copy;
238   }
239
240   public void setUpdateDate(Date date) {
241     myUpdateDate = date;
242   }
243
244   public Date getUpdateDate() {
245     return myUpdateDate;
246   }
247
248   public boolean isUpToDate() {
249     if (getStepId() == 0) return true;
250     final Date date = EduStepicConnector.getTaskUpdateDate(getStepId());
251     if (date == null) return true;
252     if (myUpdateDate == null) return false;
253     return !date.after(myUpdateDate);
254   }
255
256   public int getActiveStepIndex() {
257     return myActiveStepIndex;
258   }
259
260   public void setActiveStepIndex(int activeStepIndex) {
261     myActiveStepIndex = activeStepIndex;
262   }
263 }