@Override
  public void update(@NotNull AnActionEvent event) {
    final Presentation presentation = event.getPresentation();
    final Project project = event.getData(CommonDataKeys.PROJECT);
    if (project == null) {
      presentation.setVisible(false);
      presentation.setEnabled(false);
      return;
    }

    final IdeView view = event.getData(LangDataKeys.IDE_VIEW);
    if (view == null) {
      presentation.setVisible(false);
      presentation.setEnabled(false);
      return;
    }

    final PsiDirectory[] directories = view.getDirectories();
    if (directories.length == 0) {
      presentation.setVisible(false);
      presentation.setEnabled(false);
      return;
    }
    final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);
    final CCProjectService service = CCProjectService.getInstance(project);
    final Course course = service.getCourse();
    if (course != null && directory != null && course.getLesson(directory.getName()) == null) {
      presentation.setVisible(false);
      presentation.setEnabled(false);
      return;
    }

    presentation.setVisible(true);
    presentation.setEnabled(true);
  }
 private static void renameTask(
     @NotNull final Project project, Course course, @NotNull final PsiDirectory directory) {
   PsiDirectory lessonDir = directory.getParent();
   if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) {
     return;
   }
   Lesson lesson = course.getLesson(lessonDir.getName());
   if (lesson == null) {
     return;
   }
   String directoryName = directory.getName();
   Task task = lesson.getTask(directoryName);
   if (task != null) {
     processRename(task, EduNames.TASK, project);
   }
 }
  @Nullable
  public static FolderConfiguration selectFolderConfig(
      final Project project, VirtualFile res, ResourceFolderType folderType) {
    PsiDirectory dir = selectFolderDir(project, res, folderType);
    if (dir != null) {
      return FolderConfiguration.getConfigForFolder(dir.getName());
    }

    return null;
  }
 @NotNull
 @Override
 public Collection<AbstractTreeNode> modify(
     @NotNull AbstractTreeNode parent,
     @NotNull Collection<AbstractTreeNode> children,
     ViewSettings settings) {
   if (!isCourseBasedProject(parent)) {
     return children;
   }
   Collection<AbstractTreeNode> nodes = new ArrayList<AbstractTreeNode>();
   for (AbstractTreeNode node : children) {
     final Project project = node.getProject();
     if (project != null) {
       if (node.getValue() instanceof PsiDirectory) {
         final PsiDirectory nodeValue = (PsiDirectory) node.getValue();
         if (!nodeValue.getName().contains(EduNames.USER_TESTS)
             && !nodeValue.getName().equals(".idea")) {
           StudyDirectoryNode newNode = new StudyDirectoryNode(project, nodeValue, settings);
           nodes.add(newNode);
         }
       } else {
         if (parent instanceof StudyDirectoryNode && node instanceof PsiFileNode) {
           final PsiFileNode psiFileNode = (PsiFileNode) node;
           final VirtualFile virtualFile = psiFileNode.getVirtualFile();
           if (virtualFile == null) {
             return nodes;
           }
           final TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile);
           if (taskFile != null) {
             nodes.add(node);
           }
           final String parentName = parent.getName();
           if (parentName != null) {
             if (parentName.equals(EduNames.SANDBOX_DIR)) {
               nodes.add(node);
             }
           }
         }
       }
     }
   }
   return nodes;
 }
 private static void createValueResource(
     @NotNull PsiFile file,
     @NotNull AndroidFacet facet,
     @NotNull PsiDirectory dir,
     @NotNull final String resName,
     @NotNull final String value,
     @NotNull final ResourceType type,
     @NotNull final String oldTagText) {
   final String filename = file.getName();
   final List<String> dirNames = Collections.singletonList(dir.getName());
   final Module module = facet.getModule();
   final AtomicReference<PsiElement> openAfter = new AtomicReference<PsiElement>();
   final WriteCommandAction<Void> action =
       new WriteCommandAction<Void>(
           facet.getModule().getProject(), "Override Resource " + resName, file) {
         @Override
         protected void run(@NotNull Result<Void> result) {
           List<ResourceElement> elements = Lists.newArrayListWithExpectedSize(1);
           // AndroidResourceUtil.createValueResource will create a new resource value in the given
           // resource
           // folder (and record the corresponding tags added in the elements list passed into it).
           // However, it only creates a new element and sets the name attribute on it; it does not
           // transfer attributes, child content etc. Therefore, we use this utility method first
           // to
           // create the corresponding tag, and then *afterwards* we will replace the tag with a
           // text copy
           // from the resource tag we are overriding. We do this all under a single write lock
           // such
           // that it becomes a single atomic operation.
           AndroidResourceUtil.createValueResource(
               module, resName, type, filename, dirNames, value, elements);
           if (elements.size() == 1) {
             final XmlTag tag = elements.get(0).getXmlTag();
             if (tag != null && tag.isValid()) {
               try {
                 XmlTag tagFromText =
                     XmlElementFactory.getInstance(tag.getProject()).createTagFromText(oldTagText);
                 PsiElement replaced = tag.replace(tagFromText);
                 openAfter.set(replaced);
               } catch (IncorrectOperationException e) {
                 // The user tried to override an invalid XML fragment: don't attempt to do a
                 // replacement in that case
                 openAfter.set(tag);
               }
             }
           }
         }
       };
   action.execute();
   PsiElement tag = openAfter.get();
   if (tag != null) {
     NavigationUtil.openFileWithPsiElement(tag, true, true);
   }
 }
 @Override
 public int getTypeSortWeight(boolean sortByType) {
   String name = myValue.getName();
   String lessonDirName = "lesson";
   String taskDirName = "task";
   if (name.startsWith(lessonDirName) || name.startsWith(taskDirName)) {
     String logicalName = name.contains(lessonDirName) ? lessonDirName : taskDirName;
     int index = CCUtils.getIndex(name, logicalName) + 1;
     return index != -1 ? index : 0;
   }
   return 0;
 }
 private void doTestAppResolveTest(String expectedAppDirName) throws Exception {
   PsiFile testappuserErl = myFixture.getFile();
   assertTrue(testappuserErl instanceof ErlangFile);
   List<ErlangFile> directlyIncludedFiles =
       ErlangPsiImplUtil.getDirectlyIncludedFiles((ErlangFile) testappuserErl);
   assertEquals(1, directlyIncludedFiles.size());
   PsiDirectory ebinDirectory = directlyIncludedFiles.get(0).getParent();
   assertNotNull(ebinDirectory);
   PsiDirectory appDir = ebinDirectory.getParent();
   assertNotNull(appDir);
   assertEquals(expectedAppDirName, appDir.getName());
 }
  @Override
  protected void updateImpl(PresentationData data) {
    // TODO:change presentable name for files with suffix _answer

    String valueName = myValue.getName();
    final Course course = CCProjectService.getInstance(myProject).getCourse();
    if (course == null) return;
    if (myProject.getBaseDir().equals(myValue.getVirtualFile())) {
      data.clearText();
      data.addText(valueName, SimpleTextAttributes.REGULAR_ATTRIBUTES);
      data.addText(" (" + course.getName() + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
      return;
    }
    final Lesson lesson = course.getLesson(valueName);
    if (lesson != null) {
      data.clearText();
      data.addText(valueName, SimpleTextAttributes.REGULAR_ATTRIBUTES);
      data.addText(" (" + lesson.getName() + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
      return;
    } else {
      final PsiDirectory parentDir = myValue.getParentDirectory();
      if (parentDir != null) {
        final Lesson parentLesson = course.getLesson(parentDir.getName());
        if (parentLesson != null) {
          final Task task = parentLesson.getTask(valueName);
          if (task != null) {
            data.clearText();
            data.addText(valueName, SimpleTextAttributes.REGULAR_ATTRIBUTES);
            data.addText(" (" + task.name + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
            return;
          }
        }
      }
    }
    data.setPresentableText(valueName);
  }
 @Override
 public void invoke(
     @NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
   PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
   assert element != null;
   PsiDirectory directory = (PsiDirectory) element;
   String name = directory.getName();
   CCProjectService instance = CCProjectService.getInstance(project);
   Course course = instance.getCourse();
   if (name.contains(EduNames.LESSON)) {
     renameLesson(project, course, name);
   }
   if (name.contains(EduNames.TASK)) {
     renameTask(project, course, directory);
   }
   ProjectView.getInstance(project).refresh();
 }
  /**
   * @param elementToCopy PsiFile or PsiDirectory
   * @param newName can be not null only if elements.length == 1
   * @param choice a horrible way to pass/keep user preference
   * @return first copied PsiFile (recursively); null if no PsiFiles copied
   */
  @Nullable
  public static PsiFile copyToDirectory(
      @NotNull PsiFileSystemItem elementToCopy,
      @Nullable String newName,
      @NotNull PsiDirectory targetDirectory,
      @Nullable int[] choice)
      throws IncorrectOperationException, IOException {
    if (elementToCopy instanceof PsiFile) {
      PsiFile file = (PsiFile) elementToCopy;
      String name = newName == null ? file.getName() : newName;
      if (checkFileExist(targetDirectory, choice, file, name, "Copy")) return null;
      return targetDirectory.copyFileFrom(name, file);
    } else if (elementToCopy instanceof PsiDirectory) {
      PsiDirectory directory = (PsiDirectory) elementToCopy;
      if (directory.equals(targetDirectory)) {
        return null;
      }
      if (newName == null) newName = directory.getName();
      final PsiDirectory existing = targetDirectory.findSubdirectory(newName);
      final PsiDirectory subdirectory =
          existing == null ? targetDirectory.createSubdirectory(newName) : existing;
      EncodingRegistry.doActionAndRestoreEncoding(
          directory.getVirtualFile(),
          new ThrowableComputable<VirtualFile, IOException>() {
            @Override
            public VirtualFile compute() {
              return subdirectory.getVirtualFile();
            }
          });

      PsiFile firstFile = null;
      PsiElement[] children = directory.getChildren();
      for (PsiElement child : children) {
        PsiFileSystemItem item = (PsiFileSystemItem) child;
        PsiFile f = copyToDirectory(item, item.getName(), subdirectory, choice);
        if (firstFile == null) {
          firstFile = f;
        }
      }
      return firstFile;
    } else {
      throw new IllegalArgumentException("unexpected elementToCopy: " + elementToCopy);
    }
  }
  private void doTest() throws Exception {
    PsiPolyVariantReference reference =
        (PsiPolyVariantReference) configureByFile(getTestName(true) + ".kt");
    PsiElement resolved = reference.resolve();
    assertNotNull(resolved);
    assertEquals(1, reference.multiResolve(false).length);

    List<PsiComment> comments = PsiTreeUtil.getChildrenOfTypeAsList(getFile(), PsiComment.class);
    String[] expectedTarget = comments.get(comments.size() - 1).getText().substring(2).split(":");
    assertEquals(2, expectedTarget.length);
    String expectedFile = expectedTarget[0];
    String expectedName = expectedTarget[1];

    PsiFile targetFile = resolved.getContainingFile();
    PsiDirectory targetDir = targetFile.getParent();
    assertNotNull(targetDir);
    assertEquals(expectedFile, targetDir.getName() + "/" + targetFile.getName());
    assertInstanceOf(resolved, PsiNamedElement.class);
    assertEquals(expectedName, ((PsiNamedElement) resolved).getName());
  }
  @Override
  public void actionPerformed(final AnActionEvent e) {
    final IdeView view = e.getData(LangDataKeys.IDE_VIEW);
    final Project project = e.getData(CommonDataKeys.PROJECT);

    if (view == null || project == null) {
      return;
    }
    final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);

    if (directory == null) return;
    final CCProjectService service = CCProjectService.getInstance(project);
    final Course course = service.getCourse();
    final Lesson lesson = course.getLesson(directory.getName());
    final int size = lesson.getTaskList().size();

    final String taskName =
        Messages.showInputDialog("Name:", "Task Name", null, "task" + (size + 1), null);
    if (taskName == null) return;

    ApplicationManager.getApplication()
        .runWriteAction(
            new Runnable() {
              @Override
              public void run() {
                final PsiDirectory taskDirectory =
                    DirectoryUtil.createSubdirectories("task" + (size + 1), directory, "\\/");
                if (taskDirectory != null) {
                  final FileTemplate template =
                      FileTemplateManager.getInstance().getInternalTemplate("task.html");
                  final FileTemplate testsTemplate =
                      FileTemplateManager.getInstance().getInternalTemplate("tests");
                  final FileTemplate taskTemplate =
                      FileTemplateManager.getInstance().getInternalTemplate("task.answer");
                  try {
                    final PsiElement taskFile =
                        FileTemplateUtil.createFromTemplate(
                            template, "task.html", null, taskDirectory);
                    final PsiElement testsFile =
                        FileTemplateUtil.createFromTemplate(
                            testsTemplate, "tests.py", null, taskDirectory);
                    final PsiElement taskPyFile =
                        FileTemplateUtil.createFromTemplate(
                            taskTemplate, "file1", null, taskDirectory);

                    final Task task = new Task(taskName);
                    task.addTaskFile("file1.py", size + 1);
                    task.setIndex(size + 1);
                    lesson.addTask(task, taskDirectory);
                    ApplicationManager.getApplication()
                        .invokeLater(
                            new Runnable() {
                              @Override
                              public void run() {
                                EditorHelper.openInEditor(testsFile, false);
                                EditorHelper.openInEditor(taskPyFile, false);
                                view.selectElement(taskFile);
                              }
                            });
                  } catch (Exception ignored) {
                  }
                }
              }
            });
  }
    public void showPreview(@Nullable ResourceItem element) {
      CardLayout layout = (CardLayout) myPreviewPanel.getLayout();

      if (element == null || element.getGroup().getType() == ResourceType.ID) {
        layout.show(myPreviewPanel, NONE);
        return;
      }

      try {
        VirtualFile file = element.getFile();
        if (file == null) {
          String value = element.getPreviewString();
          if (value == null) {
            java.util.List<ResourceElement> resources = element.getPreviewResources();

            if (resources == null) {
              long time = System.currentTimeMillis();
              resources =
                  myManager.findValueResources(
                      element.getGroup().getType().getName(), element.toString());
              if (ApplicationManagerEx.getApplicationEx().isInternal()) {
                System.out.println("Time: " + (System.currentTimeMillis() - time)); // XXX
              }

              int size = resources.size();
              if (size == 1) {
                value = getResourceElementValue(resources.get(0));
                element.setPreviewString(value);
              } else if (size > 1) {
                resources = new ArrayList<ResourceElement>(resources);
                Collections.sort(
                    resources,
                    new Comparator<ResourceElement>() {
                      @Override
                      public int compare(ResourceElement element1, ResourceElement element2) {
                        PsiDirectory directory1 =
                            element1.getXmlTag().getContainingFile().getParent();
                        PsiDirectory directory2 =
                            element2.getXmlTag().getContainingFile().getParent();

                        if (directory1 == null && directory2 == null) {
                          return 0;
                        }
                        if (directory2 == null) {
                          return 1;
                        }
                        if (directory1 == null) {
                          return -1;
                        }

                        return directory1.getName().compareTo(directory2.getName());
                      }
                    });

                DefaultComboBoxModel model = new DefaultComboBoxModel();
                String defaultSelection = null;
                for (int i = 0; i < size; i++) {
                  ResourceElement resource = resources.get(i);
                  PsiDirectory directory = resource.getXmlTag().getContainingFile().getParent();
                  String name = directory == null ? "unknown-" + i : directory.getName();
                  model.addElement(name);
                  if (defaultSelection == null && "values".equalsIgnoreCase(name)) {
                    defaultSelection = name;
                  }
                }
                element.setPreviewResources(resources, model, defaultSelection);

                showComboPreview(element);
                return;
              } else {
                layout.show(myPreviewPanel, NONE);
                return;
              }
            } else {
              showComboPreview(element);
              return;
            }
          }
          if (value == null) {
            layout.show(myPreviewPanel, NONE);
            return;
          }

          myTextArea.setText(value);
          layout.show(myPreviewPanel, TEXT);
        } else if (ImageFileTypeManager.getInstance().isImage(file)) {
          Icon icon = element.getPreviewIcon();
          if (icon == null) {
            icon = new SizedIcon(100, 100, new ImageIcon(file.getPath()));
            element.setPreviewIcon(icon);
          }
          myImageComponent.setIcon(icon);
          layout.show(myPreviewPanel, IMAGE);
        } else if (file.getFileType() == XmlFileType.INSTANCE) {
          String value = element.getPreviewString();
          if (value == null) {
            value = new String(file.contentsToByteArray());
            element.setPreviewString(value);
          }
          myTextArea.setText(value);
          myTextArea.setEditable(false);
          layout.show(myPreviewPanel, TEXT);
        } else {
          layout.show(myPreviewPanel, NONE);
        }
      } catch (IOException e) {
        layout.show(myPreviewPanel, NONE);
      }
    }