/*
* Copyright 2003-2017 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.smodel.adapter.structure;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SEnumOperations;
import jetbrains.mps.smodel.SNodeId.Regular;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.language.SEnumeration;
import org.jetbrains.mps.openapi.language.SEnumerationLiteral;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
/**
* Provisional implementation of SEnumeration, backed-up by {@code node<EnumerationDataTypeDeclaration>} till we generate proper EnumDescriptor in
* structure aspect, add enum identity (optional). If we manage to do this in 2017.2, there's no need to keep SNode-based implementation.
*
* @author Artem Tikhomirov
* @since 2017.2
*/
public class SEnumAdapter implements SEnumeration {
private final Literal[] myLiterals;
private final Literal myDefaultLiteral;
private final long myEnumDeclId;
/**
* NULL value, when no enum found.
*/
public SEnumAdapter() {
myEnumDeclId = -1;
myLiterals = new Literal[0];
myDefaultLiteral = null;
}
public SEnumAdapter(SNode/*node<EnumerationDataTypeDeclaration>*/ enumDeclaration) {
myEnumDeclId = ((Regular) enumDeclaration.getNodeId()).getId(); // FIXME shall become SEnumId object
ArrayList<Literal> literals = new ArrayList<>();
for (SNode/*enummember<>*/ enumMember : SEnumOperations.getEnumMembers(enumDeclaration)) {
String value = SEnumOperations.getEnumMemberValue(enumMember);
String presentation = SEnumOperations.getEnumMemberName(enumMember);
literals.add(new Literal(value, presentation));
}
myLiterals = literals.toArray(new Literal[literals.size()]);
myDefaultLiteral = myLiterals[0];
}
@Override
public Collection<SEnumerationLiteral> getLiterals() {
return Arrays.asList(myLiterals);
}
@Override
public SEnumerationLiteral getLiteral(String name) {
for (Literal l : myLiterals) {
if (Objects.equals(l.getName(), name)) {
return l;
}
}
return null;
}
@Override
public SEnumerationLiteral getDefault() {
return myDefaultLiteral;
}
@Override
public int hashCode() {
return (int) myEnumDeclId;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (myEnumDeclId == -1 || false == obj instanceof SEnumAdapter) {
// non-existend enum doesn't match any other
return false;
}
return myEnumDeclId == ((SEnumAdapter) obj).myEnumDeclId;
}
@Override
public Object fromString(String value) {
// XXX I don't think we use these for SEnumeration. Need to check how node.property of enum type is set, whether there's literal name and no conversion
// There's conversion code in lang.smodel generator, perhaps, it's the answer?
return getLiteral(value);
}
@Override
public String toString(Object value) {
return ((SEnumerationLiteral) value).getName();
}
private class Literal implements SEnumerationLiteral {
private final String myName;
private final String myPresentation;
/**
* @param name correstponds to internalValue
* @param presentation getName() result
*/
Literal(@Nullable String name, String presentation) {
myName = name;
myPresentation = presentation;
}
@Override
public SEnumeration getEnumeration() {
return SEnumAdapter.this;
}
@Override
public String getPresentation() {
return myPresentation;
}
@Override
public String getName() {
return myName;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Literal) {
if (this == obj) {
return true;
}
Literal other = (Literal) obj;
return getEnumeration().equals(other.getEnumeration()) && Objects.equals(myName, other.myName) && Objects.equals(myPresentation, other.myPresentation);
}
return false;
}
@Override
public int hashCode() {
return myPresentation.hashCode();
}
@Override
public String toString() {
return getPresentation();
}
}
}