EDU-488 Make "Unpack course" action available from "Find action"
[idea/community.git] / python / educational / 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.util.TextRange;
21 import com.intellij.openapi.util.text.StringUtil;
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.EduDocumentListener;
26 import com.jetbrains.edu.EduNames;
27 import com.jetbrains.edu.EduUtils;
28 import com.jetbrains.edu.courseFormat.*;
29 import com.jetbrains.edu.coursecreator.CCProjectService;
30 import com.jetbrains.edu.oldCourseFormat.OldCourse;
31 import org.jetbrains.annotations.NotNull;
32
33 import java.io.*;
34 import java.util.Map;
35
36 public class CCFromCourseArchive extends DumbAwareAction {
37   private static final Logger LOG = Logger.getInstance(CCFromCourseArchive.class.getName());
38
39   public CCFromCourseArchive() {
40     super("Unpack Course Archive", "Unpack Course Archive", AllIcons.FileTypes.Archive);
41   }
42
43   @Override
44   public void actionPerformed(@NotNull AnActionEvent e) {
45     final Project project = e.getData(CommonDataKeys.PROJECT);
46     if (project == null) {
47       return;
48     }
49     unpackCourseArchive(project);
50   }
51
52   private static void unpackCourseArchive(final Project project) {
53     FileChooserDescriptor descriptor = new FileChooserDescriptor(true, true, true, true, true, false);
54
55     final VirtualFile virtualFile = FileChooser.chooseFile(descriptor, project, null);
56     if (virtualFile == null) {
57       return;
58     }
59     final String basePath = project.getBasePath();
60     if (basePath == null) return;
61     final CCProjectService service = CCProjectService.getInstance(project);
62     Reader reader = null;
63     try {
64       ZipUtil.unzip(null, new File(basePath), new File(virtualFile.getPath()), null, null, true);
65       reader = new InputStreamReader(new FileInputStream(new File(basePath, EduNames.COURSE_META_FILE)));
66       Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
67       Course course = gson.fromJson(reader, Course.class);
68       if (course == null || course.getLessons().isEmpty() || StringUtil.isEmptyOrSpaces(course.getLessons().get(0).getName())) {
69         try {
70           reader.close();
71         }
72         catch (IOException e) {
73           LOG.error(e.getMessage());
74         }
75         reader = new InputStreamReader(new FileInputStream(new File(basePath, EduNames.COURSE_META_FILE)));
76         OldCourse oldCourse = gson.fromJson(reader, OldCourse.class);
77         course = EduUtils.transformOldCourse(oldCourse);
78       }
79
80       service.setCourse(course);
81       project.getBaseDir().refresh(false, true);
82       int index = 1;
83       int taskIndex = 1;
84       for (Lesson lesson : course.getLessons()) {
85         final VirtualFile lessonDir = project.getBaseDir().findChild(EduNames.LESSON + String.valueOf(index));
86         lesson.setIndex(index);
87         if (lessonDir == null) continue;
88         for (Task task : lesson.getTaskList()) {
89           final VirtualFile taskDir = lessonDir.findChild(EduNames.TASK + String.valueOf(taskIndex));
90           task.setIndex(taskIndex);
91           task.setLesson(lesson);
92           if (taskDir == null) continue;
93           for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
94             ApplicationManager.getApplication().runWriteAction(new Runnable() {
95               @Override
96               public void run() {
97                 createAnswerFile(project, taskDir, taskDir, entry);
98               }
99             });
100           }
101           taskIndex += 1;
102         }
103         index += 1;
104         taskIndex = 1;
105       }
106     }
107     catch (FileNotFoundException e) {
108       LOG.error(e.getMessage());
109     }
110     catch (IOException e) {
111       LOG.error(e.getMessage());
112     }
113     catch (JsonSyntaxException e) {
114       LOG.error(e.getMessage());
115     }
116     finally {
117       if (reader != null) {
118         try {
119           reader.close();
120         }
121         catch (IOException e) {
122           LOG.error(e.getMessage());
123         }
124       }
125     }
126     synchronize(project);
127   }
128
129   public static void createAnswerFile(@NotNull final Project project,
130                                       @NotNull final VirtualFile userFileDir,
131                                       @NotNull final VirtualFile answerFileDir,
132                                       @NotNull final Map.Entry<String, TaskFile> taskFileEntry) {
133     final String name = taskFileEntry.getKey();
134     final TaskFile taskFile = taskFileEntry.getValue();
135     VirtualFile file = userFileDir.findChild(name);
136     assert file != null;
137     String answerFileName = file.getNameWithoutExtension() + ".answer." + file.getExtension();
138     VirtualFile answerFile = answerFileDir.findChild(answerFileName);
139     if (answerFile != null) {
140       try {
141         answerFile.delete(project);
142       }
143       catch (IOException e) {
144         LOG.error(e);
145       }
146     }
147     try {
148       answerFile = userFileDir.createChildData(project, answerFileName);
149     }
150     catch (IOException e) {
151       LOG.error(e);
152     }
153     if (answerFile == null) return;
154
155     final Document originDocument = FileDocumentManager.getInstance().getDocument(file);
156     if (originDocument == null) {
157       return;
158     }
159     final Document document = FileDocumentManager.getInstance().getDocument(answerFile);
160     if (document == null) return;
161
162     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
163       @Override
164       public void run() {
165         ApplicationManager.getApplication().runWriteAction(new Runnable() {
166           @Override
167           public void run() {
168             document.replaceString(0, document.getTextLength(), originDocument.getCharsSequence());
169           }
170         });
171       }
172     }, "Create answer document", "Create answer document");
173     EduDocumentListener listener = new EduDocumentListener(taskFile, false);
174     document.addDocumentListener(listener);
175     taskFile.sortAnswerPlaceholders();
176     for (int i = taskFile.getAnswerPlaceholders().size() - 1; i >= 0; i--) {
177       final AnswerPlaceholder answerPlaceholder = taskFile.getAnswerPlaceholders().get(i);
178       replaceAnswerPlaceholder(project, document, answerPlaceholder);
179     }
180     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
181       @Override
182       public void run() {
183         ApplicationManager.getApplication().runWriteAction(new Runnable() {
184           @Override
185           public void run() {
186             FileDocumentManager.getInstance().saveDocument(document);
187           }
188         });
189       }
190     }, "x", "qwe");
191     document.removeDocumentListener(listener);
192   }
193
194   private static void replaceAnswerPlaceholder(@NotNull final Project project,
195                                                @NotNull final Document document,
196                                                @NotNull final AnswerPlaceholder answerPlaceholder) {
197     final int offset = answerPlaceholder.getRealStartOffset(document);
198     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
199       @Override
200       public void run() {
201         ApplicationManager.getApplication().runWriteAction(new Runnable() {
202           @Override
203           public void run() {
204             final String text = document.getText(TextRange.create(offset, offset + answerPlaceholder.getLength()));
205             answerPlaceholder.setTaskText(text);
206             final VirtualFile hints = project.getBaseDir().findChild(EduNames.HINTS);
207             if (hints != null) {
208               final String hintFile = answerPlaceholder.getHint();
209               final VirtualFile virtualFile = hints.findChild(hintFile);
210               if (virtualFile != null) {
211                 final Document hintDocument = FileDocumentManager.getInstance().getDocument(virtualFile);
212                 if (hintDocument != null) {
213                   final String hintText = hintDocument.getText();
214                   answerPlaceholder.setHint(hintText);
215                 }
216               }
217             }
218
219             document.replaceString(offset, offset + answerPlaceholder.getLength(), answerPlaceholder.getPossibleAnswer());
220             FileDocumentManager.getInstance().saveDocument(document);
221           }
222         });
223       }
224     }, "x", "qwe");
225   }
226
227   private static void synchronize(@NotNull final Project project) {
228     VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
229     ProjectView.getInstance(project).refresh();
230   }
231
232 }