/*
* Copyright 2003-2016 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.idea.core.psi.impl;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.ArrayUtil;
import jetbrains.mps.ide.project.ProjectHelper;
import jetbrains.mps.openapi.navigation.EditorNavigator;
import jetbrains.mps.smodel.ModelAccessHelper;
import jetbrains.mps.smodel.SNodePointer;
import jetbrains.mps.util.NameUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeId;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jetbrains.mps.openapi.module.SRepository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* evgeny, 1/25/13
*/
public class MPSPsiNode extends MPSPsiNodeBase implements MPSPsiRealNode {
private static final String NAME_PROPERTY_KEY = "name";
private final SNodeId myId;
private final String myConcept;
private final String myContainingRole;
private String myName;
private final Map<String, String> myProperties;
private String myPresentation = null;
public MPSPsiNode(SNodeId id, String concept, String containingRole, PsiManager manager) {
super(manager);
myId = id;
myConcept = concept;
myContainingRole = containingRole;
myProperties = new HashMap<>();
}
@Override
public String getName() {
return myName;
}
public SNodeId getId() {
return myId;
}
public String getConcept() {
return myConcept;
}
public String getContainingRole() {
return myContainingRole;
}
@Override
public SNodeReference getSNodeReference() {
return new SNodePointer(getContainingModel().getSModelReference(), myId);
}
public String getProperty(String key) {
// special treatment of name: I just repeated how it's done in setProperty for now
// don't think it's needed
if (NAME_PROPERTY_KEY.equals(key)) {
return myName;
}
return myProperties.get(key);
}
@Override
public PsiFile getContainingFile() {
return getContainingRoot();
}
void setProperty(String key, String value) {
// TODO
if (key.equals(NAME_PROPERTY_KEY)) {
myName = value;
return;
}
myProperties.put(key, value);
}
protected void setNameProperty(String value) {
setProperty(NAME_PROPERTY_KEY, value);
}
protected <T extends PsiElement> T getReferenceTarget(String role, @NotNull Class<T> aClass) {
if (role == null) return null;
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
if (child instanceof MPSPsiRef && role.equals(((MPSPsiRef) child).getRole())) {
PsiElement refTarget = ((MPSPsiRef) child).resolve();
if (aClass.isInstance(refTarget)) {
return (T) refTarget;
}
}
}
return null;
}
public MPSPsiRef[] getReferences(String role) {
if (role == null) return null;
List<MPSPsiRef> result = new ArrayList<>();
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
if (child instanceof MPSPsiRef && role.equals(((MPSPsiRef) child).getRole())) {
result.add((MPSPsiRef) child);
}
}
return ArrayUtil.toObjectArray(result, MPSPsiRef.class);
}
public <T extends PsiElement> T getChildOfType(String role, @NotNull Class<T> aClass) {
if (role == null) return null;
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
if (child instanceof MPSPsiNode && role.equals(((MPSPsiNode) child).getContainingRole()) && aClass.isInstance(child)) {
return (T) child;
}
}
return null;
}
@Override
public String toString() {
return NameUtil.shortNameFromLongName(myConcept) + (myContainingRole == null ? "" : " in " + myContainingRole);
}
@Override
public void navigate(boolean requestFocus) {
new EditorNavigator(ProjectHelper.fromIdeaProject(getProject())).shallFocus(requestFocus).selectIfChild().open(getSNodeReference());
}
@Override
public boolean canNavigate() {
return isValid();
}
@Override
public boolean canNavigateToSource() {
return isValid();
}
@Override
public String getText() {
if(myPresentation == null) {
final SRepository repository = ProjectHelper.fromIdeaProject(myManager.getProject()).getRepository();
// Try resolve and set presentation. If it fails - will try next time.
myPresentation = new ModelAccessHelper(repository).runReadAction(() -> {
final SNode resolve = getSNodeReference().resolve(repository);
return resolve == null ? null : resolve.getPresentation();
});
}
return myPresentation == null ? myConcept + ": as " + myContainingRole : myPresentation;
}
@Override
public boolean isWritable() {
return true;
}
/*
@Nullable
@Override
public Icon getIcon(int flags) {
return getPresentation().getIcon(false);
}
@Override
public ItemPresentation getPresentation() {
return new NodePointerPresentation(getNodeReference());
}
*/
}