/*
 * Copyright 2013-2014 must-be.org
 *
 * 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 org.mustbe.consulo.csharp.lang.psi.impl.source;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mustbe.consulo.csharp.lang.psi.CSharpCallArgumentList;
import org.mustbe.consulo.csharp.lang.psi.CSharpCallArgumentListOwner;
import org.mustbe.consulo.csharp.lang.psi.CSharpElementVisitor;
import org.mustbe.consulo.csharp.lang.psi.CSharpElements;
import org.mustbe.consulo.csharp.lang.psi.CSharpPseudoMethod;
import org.mustbe.consulo.csharp.lang.psi.impl.source.resolve.type.CSharpLambdaResolveResult;
import org.mustbe.consulo.dotnet.psi.DotNetExpression;
import org.mustbe.consulo.dotnet.psi.DotNetTypeList;
import org.mustbe.consulo.dotnet.psi.DotNetVariable;
import org.mustbe.consulo.dotnet.resolve.DotNetTypeRef;
import org.mustbe.consulo.dotnet.resolve.DotNetTypeResolveResult;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.ResolveResult;

/**
 * @author VISTALL
 * @since 16.12.13.
 */
public class CSharpMethodCallExpressionImpl extends CSharpElementImpl implements DotNetExpression, CSharpCallArgumentListOwner
{
	public CSharpMethodCallExpressionImpl(@NotNull ASTNode node)
	{
		super(node);
	}

	@Override
	public boolean canResolve()
	{
		return true;
	}

	@Override
	@Nullable
	public CSharpCallArgumentList getParameterList()
	{
		return findChildByClass(CSharpCallArgumentList.class);
	}

	@Nullable
	@Override
	public DotNetTypeList getTypeArgumentList()
	{
		return (DotNetTypeList) findChildByType(CSharpElements.TYPE_CALL_ARGUMENTS);
	}

	@NotNull
	@Override
	public DotNetTypeRef[] getTypeArgumentListRefs()
	{
		DotNetTypeList typeArgumentList = getTypeArgumentList();
		return typeArgumentList == null ? DotNetTypeRef.EMPTY_ARRAY : typeArgumentList.getTypeRefs();
	}

	@Override
	@NotNull
	public DotNetExpression[] getParameterExpressions()
	{
		CSharpCallArgumentList parameterList = getParameterList();
		return parameterList == null ? DotNetExpression.EMPTY_ARRAY : parameterList.getExpressions();
	}

	@NotNull
	public DotNetExpression getCallExpression()
	{
		return findNotNullChildByClass(DotNetExpression.class);
	}

	@Override
	public void accept(@NotNull CSharpElementVisitor visitor)
	{
		visitor.visitMethodCallExpression(this);
	}

	@Override
	@Nullable
	public PsiElement resolveToCallable()
	{
		DotNetExpression callExpression = getCallExpression();

		if(callExpression instanceof CSharpReferenceExpressionImpl)
		{
			return ((CSharpReferenceExpressionImpl) callExpression).resolve();
		}
		return null;
	}

	@NotNull
	@Override
	public ResolveResult[] multiResolve(boolean incompleteCode)
	{
		DotNetExpression callExpression = getCallExpression();

		if(callExpression instanceof CSharpReferenceExpressionImpl)
		{
			return ((CSharpReferenceExpressionImpl) callExpression).multiResolve(incompleteCode);
		}
		return ResolveResult.EMPTY_ARRAY;
	}

	@NotNull
	@Override
	public DotNetTypeRef toTypeRef(boolean resolveFromParent)
	{
		PsiElement resolve = resolveToCallable();
		if(resolve instanceof DotNetVariable)
		{
			DotNetTypeRef dotNetTypeRef = ((DotNetVariable) resolve).toTypeRef(false);
			DotNetTypeResolveResult typeResolveResult = dotNetTypeRef.resolve(this);
			if(typeResolveResult instanceof CSharpLambdaResolveResult)
			{
				return ((CSharpLambdaResolveResult) typeResolveResult).getReturnTypeRef();
			}
		}
		if(resolve instanceof CSharpPseudoMethod)
		{
			return ((CSharpPseudoMethod) resolve).getReturnTypeRef();
		}
		return CSharpReferenceExpressionImpl.toTypeRef(resolve);
	}
}

@@ -3045,38 +3045,60 @@
 ionImpl)%0A%09%09%7B%0A%09%09%09
-return
+PsiElement resolvedElement =
  ((CSharpReferen
@@ -3138,24 +3138,237 @@
 .resolve();%0A
+%09%09%09if(resolvedElement != null)%0A%09%09%09%7B%0A%09%09%09%09return resolvedElement;%0A%09%09%09%7D%0A%0A%09%09%09ResolveResult%5B%5D resolveResults = multiResolve(false);%0A%09%09%09if(resolveResults.length %3E 0)%0A%09%09%09%7B%0A%09%09%09%09return resolveResults%5B0%5D.getElement();%0A%09%09%09%7D%0A
 %09%09%7D%0A%09%09return
@@ -3823,16 +3823,24 @@
  resolve
+dElement
  = resol
@@ -3859,32 +3859,40 @@
 ();%0A%09%09if(resolve
+dElement
  instanceof DotN
@@ -3965,16 +3965,24 @@
  resolve
+dElement
 ).toType
@@ -4236,16 +4236,24 @@
 (resolve
+dElement
  instanc
@@ -4319,16 +4319,24 @@
  resolve
+dElement
 ).getRet
@@ -4409,16 +4409,24 @@
 (resolve
+dElement
 );%0A%09%7D%0A%7D%0A

resolve callable even it not valid