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