/*
 * Copyright 2003-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.mps.openapi.navigation;

import jetbrains.mps.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jetbrains.mps.util.Condition;

/**
 * Handy facility to replace code like:
 * <pre>
 *   final SNodeReference nodeRef = ...;
 *   getProject().getModelAccess().runWriteInEDT(new Runnable() {
 *     public void run() {
 *       SNode target = nodeRef.resolve(getProject().getRepository());
 *       if (target != null) {
 *         NavigationSupport.getInstance().openNode(getProject(), target, true, false);
 *       }
 *     }
 *   }
 * </pre>
 *
 * Instead, this class could be used:
 * <pre>
 *   final SNodeReference nodeRef = ...;
 *   new EditorNavigator(getProject()).shallFocus(true).open(nodeRef);
 * </pre>
 *
 * Primary benefit is that we hide all the knowledge about read/write model and thread access.
 *
 * @author Artem Tikhomirov
 * @since 3.3
 */
public final class EditorNavigator {
  private final Project myProject;
  private boolean myFocus = false;
  private boolean mySelect = false;
  private Condition<SNode> mySelectCondition;

  public EditorNavigator(@NotNull Project mpsProject) {
    myProject = mpsProject;
  }

  /**
   * Default: no focus, <code>false</code>
   */
  public EditorNavigator shallFocus(boolean shallFocus) {
    myFocus = shallFocus;
    return this;
  }

  /**
   * Default: no selection, <code>false</code>
   */
  public EditorNavigator shallSelect(boolean shallSelect) {
    mySelect = shallSelect;
    return this;
  }

  public EditorNavigator selectIfChild() {
    mySelectCondition = new Condition<SNode>() {
      @Override
      public boolean met(SNode node) {
        return node.getParent() != null;
      }
    };
    return this;
  }


  public void open(@NotNull final SNodeReference node) {
    myProject.getModelAccess().runWriteInEDT(new Runnable() {
      @Override
      public void run() {
        SNode target = node.resolve(myProject.getRepository());
        if (target != null) {
          NavigationSupport.getInstance().openNode(myProject, target, needFocus(target), needSelection(target));
        }
      }
    });
  }

  /*package*/ boolean needSelection(SNode target) {
    if (mySelectCondition != null) {
      return mySelectCondition.met(target);
    }
    return mySelect;
  }

  /*package*/ boolean needFocus(SNode target) {
    return myFocus;
  }
}
