package jetbrains.mps.idea.core.refactoring;

import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.rename.RenameHandler;
import jetbrains.mps.ide.actions.MPSCommonDataKeys;
import jetbrains.mps.project.MPSProject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeUtil;
import org.jetbrains.mps.openapi.module.ModelAccess;
import org.jetbrains.mps.openapi.module.SRepository;

/**
 * danilla 5/29/13
 */
// This is glue that will invoke MPS refactoring, when Idea refactoring action is invoked
public class MPSRenameRefactoringHandler implements RenameHandler {
  private static final Logger LOG = Logger.getInstance("#jetbrains.mps.idea.core.refactoring.MPSRenameRefactoringHandler");

  @Override
  public boolean isAvailableOnDataContext(DataContext dataContext) {
    SNode currentNode = MPSCommonDataKeys.NODE.getData(dataContext);
    return currentNode != null;
  }

  @Override
  public boolean isRenaming(DataContext dataContext) {
    return isAvailableOnDataContext(dataContext);
  }

  @Override
  public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
    LOG.assertTrue(false);
  }

  @Override
  public void invoke(@NotNull final Project project, @NotNull PsiElement[] elements, final DataContext dataContext) {
    // we ignore 'elements' and take current node from dataContext
    // because Idea takes the root node as the element for our editor

    final MPSProject mpsProject = project.getComponent(MPSProject.class);
    final SRepository repository = mpsProject.getRepository();
    ModelAccess modelAccess = repository.getModelAccess();

    // taking NODE from dataContext outside of readInEDT because we can't take anything
    // from dataContext after we've invoked something in EDT;
    // see DataManagerImpl.getData() LOG.error() cannot share data context ...
    // also see IdeKeyEventDispatcher.processAction() for place where initial event count is set
    final SNode node = MPSCommonDataKeys.NODE.getData(dataContext);

    modelAccess.runReadInEDT(new Runnable() {
      @Override
      public void run() {
        if (!SNodeUtil.isAccessible(node, repository)) {
          return;
        }
        // trying to apply sequentially, the first one wins and we go no further
        for (RenameRefactoringContributorEP ep : RenameRefactoringContributorEP.EP_NAME.getExtensions()) {
          RenameRefactoringContributor contributor = ep.getContribitor();
          if (contributor.isAvailableFor(node)) {
            contributor.invoke(project, node);
            return;
          }
        }
      }
    });
  }
}