use length after document modification
[idea/community.git] / python / educational-core / course-creator / src / com / jetbrains / edu / coursecreator / actions / CCFromCourseArchive.java
1 package com.jetbrains.edu.coursecreator.actions;
2
3 import com.google.gson.FieldNamingPolicy;
4 import com.google.gson.Gson;
5 import com.google.gson.GsonBuilder;
6 import com.google.gson.JsonSyntaxException;
7 import com.intellij.icons.AllIcons;
8 import com.intellij.ide.projectView.ProjectView;
9 import com.intellij.openapi.actionSystem.AnActionEvent;
10 import com.intellij.openapi.actionSystem.CommonDataKeys;
11 import com.intellij.openapi.application.ApplicationManager;
12 import com.intellij.openapi.command.CommandProcessor;
13 import com.intellij.openapi.diagnostic.Logger;
14 import com.intellij.openapi.editor.Document;
15 import com.intellij.openapi.fileChooser.FileChooser;
16 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
17 import com.intellij.openapi.fileEditor.FileDocumentManager;
18 import com.intellij.openapi.project.DumbAwareAction;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.ui.Messages;
21 import com.intellij.openapi.util.TextRange;
22 import com.intellij.openapi.vfs.VirtualFile;
23 import com.intellij.openapi.vfs.VirtualFileManager;
24 import com.intellij.platform.templates.github.ZipUtil;
25 import com.jetbrains.edu.coursecreator.CCUtils;
26 import com.jetbrains.edu.learning.StudySerializationUtils;
27 import com.jetbrains.edu.learning.StudyTaskManager;
28 import com.jetbrains.edu.learning.core.EduDocumentListener;
29 import com.jetbrains.edu.learning.core.EduNames;
30 import com.jetbrains.edu.learning.courseFormat.*;
31 import org.jetbrains.annotations.NotNull;
32
33 import java.io.*;
34 import java.util.ArrayList;
35 import java.util.Map;
36
37 import static com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator.OUR_COURSES_DIR;
38
39 public class CCFromCourseArchive extends DumbAwareAction {
40   private static final Logger LOG = Logger.getInstance(CCFromCourseArchive.class.getName());
41
42   public CCFromCourseArchive() {
43     super("Unpack Course Archive", "Unpack Course Archive", AllIcons.FileTypes.Archive);
44   }
45
46   @Override
47   public void actionPerformed(@NotNull AnActionEvent e) {
48     final Project project = e.getData(CommonDataKeys.PROJECT);
49     if (project == null) {
50       return;
51     }
52     unpackCourseArchive(project);
53   }
54
55   private static void unpackCourseArchive(final Project project) {
56     FileChooserDescriptor descriptor = new FileChooserDescriptor(true, true, true, true, true, false);
57
58     final VirtualFile virtualFile = FileChooser.chooseFile(descriptor, project, null);
59     if (virtualFile == null) {
60       return;
61     }
62     final String basePath = project.getBasePath();
63     if (basePath == null) return;
64     Reader reader = null;
65     try {
66       ZipUtil.unzip(null, new File(basePath), new File(virtualFile.getPath()), null, null, true);
67       File courseMetaFile = new File(basePath, EduNames.COURSE_META_FILE);
68       reader = new InputStreamReader(new FileInputStream(courseMetaFile));
69       Gson gson = new GsonBuilder()
70         .registerTypeAdapter(Course.class, new StudySerializationUtils.Json.CourseTypeAdapter(courseMetaFile))
71         .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
72         .create();
73       Course course = gson.fromJson(reader, Course.class);
74
75       if (course == null) {
76         Messages.showErrorDialog("This course is incompatible with current version", "Failed to Unpack Course");
77         return;
78       }
79
80       StudyTaskManager.getInstance(project).setCourse(course);
81       File courseDir = new File(OUR_COURSES_DIR, course.getName() + "-" + project.getName());
82       course.setCourseDirectory(courseDir.getPath());
83       course.setCourseMode(CCUtils.COURSE_MODE);
84       project.getBaseDir().refresh(false, true);
85       int index = 1;
86       int taskIndex = 1;
87       for (Lesson lesson : course.getLessons()) {
88         final VirtualFile lessonDir = project.getBaseDir().findChild(EduNames.LESSON + String.valueOf(index));
89         lesson.setIndex(index);
90         if (lessonDir == null) continue;
91         for (Task task : lesson.getTaskList()) {
92           final VirtualFile taskDir = lessonDir.findChild(EduNames.TASK + String.valueOf(taskIndex));
93           task.setIndex(taskIndex);
94           task.setLesson(lesson);
95           if (taskDir == null) continue;
96           for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
97             ApplicationManager.getApplication().runWriteAction(() -> createAnswerFile(project, taskDir, entry));
98           }
99           taskIndex += 1;
100         }
101         index += 1;
102         taskIndex = 1;
103       }
104       course.initCourse(true);
105     }
106     catch (FileNotFoundException e) {
107       LOG.error(e.getMessage());
108     }
109     catch (IOException e) {
110       LOG.error(e.getMessage());
111     }
112     catch (JsonSyntaxException e) {
113       LOG.error(e.getMessage());
114     }
115     finally {
116       if (reader != null) {
117         try {
118           reader.close();
119         }
120         catch (IOException e) {
121           LOG.error(e.getMessage());
122         }
123       }
124     }
125     synchronize(project);
126   }
127
128   public static void createAnswerFile(@NotNull final Project project,
129                                       @NotNull final VirtualFile userFileDir,
130                                       @NotNull final Map.Entry<String, TaskFile> taskFileEntry) {
131     final String name = taskFileEntry.getKey();
132     final TaskFile taskFile = taskFileEntry.getValue();
133     VirtualFile file = userFileDir.findChild(name);
134     assert file != null;
135     final Document originDocument = FileDocumentManager.getInstance().getDocument(file);
136     if (originDocument == null) {
137       return;
138     }
139     final Document document = FileDocumentManager.getInstance().getDocument(file);
140     if (document == null) return;
141
142     CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> document.replaceString(0, document.getTextLength(), originDocument.getCharsSequence())), "Create answer document", "Create answer document");
143     EduDocumentListener listener = new EduDocumentListener(taskFile, false);
144     document.addDocumentListener(listener);
145     taskFile.sortAnswerPlaceholders();
146     for (int i = taskFile.getAnswerPlaceholders().size() - 1; i >= 0; i--) {
147       final AnswerPlaceholder answerPlaceholder = taskFile.getAnswerPlaceholders().get(i);
148       replaceAnswerPlaceholder(project, document, answerPlaceholder);
149     }
150     CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> FileDocumentManager.getInstance().saveDocument(document)), "x", "qwe");
151     document.removeDocumentListener(listener);
152   }
153
154   private static void replaceAnswerPlaceholder(@NotNull final Project project,
155                                                @NotNull final Document document,
156                                                @NotNull final AnswerPlaceholder answerPlaceholder) {
157     final int offset = answerPlaceholder.getOffset();
158     CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> {
159       final String text = document.getText(TextRange.create(offset, offset + answerPlaceholder.getRealLength()));
160       answerPlaceholder.setTaskText(text);
161       answerPlaceholder.init();
162       final VirtualFile hints = project.getBaseDir().findChild(EduNames.HINTS);
163       if (hints != null) {
164         final ArrayList<String> result = new ArrayList<>();
165         for (String hint : answerPlaceholder.getHints()) {
166           final VirtualFile virtualFile = hints.findChild(hint);
167           if (virtualFile != null) {
168             final Document hintDocument = FileDocumentManager.getInstance().getDocument(virtualFile);
169             if (hintDocument != null) {
170               final String hintText = hintDocument.getText();
171               result.add(hintText);
172             }
173           }          
174         }
175         answerPlaceholder.setHints(result);
176       }
177       document.replaceString(offset, offset + answerPlaceholder.getRealLength(), answerPlaceholder.getPossibleAnswer());
178       answerPlaceholder.setUseLength(false);
179       FileDocumentManager.getInstance().saveDocument(document);
180     }), "Replace answer placeholder", "From Course Archive");
181   }
182
183   private static void synchronize(@NotNull final Project project) {
184     VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
185     ProjectView.getInstance(project).refresh();
186   }
187
188 }