package org.jetbrains.plugins.ruby.motion;
import com.intellij.codeInsight.generation.ClassMember;
import com.intellij.codeInsight.generation.MemberChooserObject;
import com.intellij.codeInsight.generation.MemberChooserObjectBase;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.ruby.motion.bridgesupport.Function;
import org.jetbrains.plugins.ruby.motion.symbols.FunctionSymbol;
import org.jetbrains.plugins.ruby.motion.symbols.MotionSymbolUtil;
import org.jetbrains.plugins.ruby.ruby.codeInsight.OverriddenMethodGenerator;
import org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.Type;
import org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.structure.Symbol;
import org.jetbrains.plugins.ruby.ruby.lang.psi.RubyElementFactory;
import org.jetbrains.plugins.ruby.ruby.sdk.LanguageLevel;
import java.util.List;
/**
* @author Dennis.Ushakov
*/
public class RubyMotionOverriddenMethodGenerator extends OverriddenMethodGenerator {
@Override
public Type getSupportedType() {
return Type.INSTANCE_METHOD;
}
@Nullable
@Override
public PsiElement generateOverriddenMethod(ClassMember baseMember, @NotNull final LanguageLevel languageLevel) {
if (baseMember instanceof FunctionMember) {
final FunctionSymbol symbol = ((FunctionMember)baseMember).getMethodSymbol();
return generateObjCOverride(symbol.getProject(), symbol.getFunction(), languageLevel);
}
return null;
}
private static PsiElement generateObjCOverride(Project project, Function function, @NotNull final LanguageLevel languageLevel) {
final StringBuilder text = new StringBuilder();
text.append("def ");
text.append(MotionSymbolUtil.getSelectorNames(function).get(0));
final List<Pair<String,String>> arguments = function.getArguments();
if (arguments.size() > 0) {
final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project);
final boolean generateParenthesesAroundArguments = settings.PARENTHESES_AROUND_METHOD_ARGUMENTS;
text.append(generateParenthesesAroundArguments ? "(" : " ");
text.append(arguments.get(0).first);
final String[] namedArguments = function.getName().split(":");
for (int i = 1; i < namedArguments.length; i++) {
String argument = namedArguments[i];
text.append(", ").append(argument).append(":").append(arguments.get(i).first);
}
text.append(generateParenthesesAroundArguments ? ")" : "");
}
text.append("\n").append(" super\nend\n");
return RubyElementFactory.createElementFromText(project, text.toString(), languageLevel);
}
@Nullable
@Override
public ClassMember createMemberToOverride(final Symbol methodSymbol) {
if (methodSymbol instanceof FunctionSymbol) {
final FunctionSymbol symbol = (FunctionSymbol)methodSymbol;
final Function function = symbol.getFunction();
if (!function.isClassMethod() && symbol.getParentSymbol() != null) {
return new FunctionMember(symbol);
}
}
return null;
}
@Override
public boolean isContainerNode(MemberChooserObject member) {
return member instanceof ObjCClass;
}
private static class FunctionMember extends MemberChooserObjectBase implements ClassMember{
private final FunctionSymbol myMethodSymbol;
public FunctionMember(FunctionSymbol methodSymbol) {
super(methodSymbol.getFunction().getName(), AllIcons.Nodes.Method);
myMethodSymbol = methodSymbol;
}
public FunctionSymbol getMethodSymbol() {
return myMethodSymbol;
}
@Override
public MemberChooserObject getParentNodeDelegate() {
return new ObjCClass(myMethodSymbol.getParentSymbol());
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null) return false;
if (obj.getClass() != FunctionMember.class) return false;
return ((FunctionMember)obj).myMethodSymbol.equals(myMethodSymbol);
}
@Override
public int hashCode() {
return myMethodSymbol.hashCode();
}
}
private static class ObjCClass extends MemberChooserObjectBase implements ClassMember {
private final Symbol myClazz;
public ObjCClass(Symbol clazz) {
super(clazz.getName(), AllIcons.Nodes.Class);
myClazz = clazz;
}
@Override
public MemberChooserObject getParentNodeDelegate() {
return null;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null) return false;
if (obj.getClass() != ObjCClass.class) return false;
return ((ObjCClass)obj).myClazz.equals(myClazz);
}
@Override
public int hashCode() {
return myClazz.hashCode();
}
}
}