/*
 * Copyright 2013 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.ide.codeInsight.actions;

import java.util.ArrayList;
import java.util.List;

import org.jetbrains.annotations.NotNull;
import org.mustbe.consulo.csharp.lang.psi.impl.source.CSharpReferenceExpressionImpl;
import org.mustbe.consulo.dotnet.DotNetBundle;
import org.mustbe.consulo.dotnet.psi.DotNetTypeDeclaration;
import org.mustbe.consulo.dotnet.psi.stub.index.TypeIndex;
import com.intellij.codeInsight.daemon.impl.ShowAutoImportPass;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.codeInspection.HintAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import lombok.val;

/**
 * @author VISTALL
 * @since 30.12.13.
 */
public class UsingNamespaceFix implements HintAction, HighPriorityAction
{
	enum PopupResult
	{
		NOT_AVAILABLE,
		SHOW_HIT,
		SHOW_ACTION
	}

	private final CSharpReferenceExpressionImpl myRef;

	public UsingNamespaceFix(CSharpReferenceExpressionImpl ref)
	{
		myRef = ref;
	}

	public PopupResult doFix(Editor editor)
	{
		PsiElement resolve = myRef.resolve();
		if(resolve != null && resolve.isValid())
		{
			return PopupResult.NOT_AVAILABLE;
		}

		List<String> q = collectAvailableNamespaces();
		if(q.isEmpty())
		{
			return PopupResult.NOT_AVAILABLE;
		}

		AddUsingAction action = new AddUsingAction(editor, myRef, q);
		String message = ShowAutoImportPass.getMessage(q.size() != 1, DotNetBundle.message("use.popup", q.iterator().next()));

		HintManager.getInstance().showQuestionHint(editor, message, myRef.getTextOffset(), myRef.getTextRange().getEndOffset(), action);

		return PopupResult.SHOW_HIT;
	}

	private List<String> collectAvailableNamespaces()
	{
		val set = new ArrayList<String>();

		String referenceName = myRef.getReferenceName();
		val types = TypeIndex.getInstance().get(referenceName, myRef.getProject(), myRef.getResolveScope());

		for(DotNetTypeDeclaration type : types)
		{
			String presentableParentQName = type.getPresentableParentQName();
			if(StringUtil.isEmpty(presentableParentQName))
			{
				continue;
			}
			set.add(presentableParentQName);
		}

		return set;
	}

	@Override
	public boolean showHint(@NotNull Editor editor)
	{
		return doFix(editor) == PopupResult.SHOW_HIT;
	}

	@NotNull
	@Override
	public String getText()
	{
		return DotNetBundle.message("add.using");
	}

	@NotNull
	@Override
	public String getFamilyName()
	{
		return "Import";
	}

	@Override
	public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile psiFile)
	{
		return true;
	}

	@Override
	public void invoke(@NotNull Project project, Editor editor, PsiFile psiFile) throws IncorrectOperationException
	{

	}

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

@@ -910,27 +910,32 @@
 t.psi.DotNet
-Typ
+Namespac
 eDeclaration
@@ -932,24 +932,85 @@
 eclaration;%0A
+import org.mustbe.consulo.dotnet.psi.stub.index.MethodIndex;%0A
 import org.m
@@ -2585,18 +2585,19 @@
 %7B%0A%09%09val 
+li
 s
-e
 t = new 
@@ -2783,29 +2783,11 @@
 for(
-DotNetTypeDeclaration
+val
  typ
@@ -2951,45 +2951,518 @@
 %0A%09%09%09
-set.add(presentableParentQName);%0A%09%09%7D%0A
+list.add(presentableParentQName);%0A%09%09%7D%0A%0A%09%09val methods = MethodIndex.getInstance().get(referenceName, myRef.getProject(), myRef.getResolveScope());%0A%0A%09%09for(val method : methods)%0A%09%09%7B%0A%09%09%09if((method.getParent() instanceof DotNetNamespaceDeclaration %7C%7C method.getParent() instanceof PsiFile) && method.isDelegate())%0A%09%09%09%7B%0A%09%09%09%09String presentableParentQName = method.getPresentableParentQName();%0A%09%09%09%09if(StringUtil.isEmpty(presentableParentQName))%0A%09%09%09%09%7B%0A%09%09%09%09%09continue;%0A%09%09%09%09%7D%0A%09%09%09%09list.add(presentableParentQName);%0A%09%09%09%7D%0A%09%09%7D
 %0A%09%09r
@@ -3467,18 +3467,19 @@
 %09return 
+li
 s
-e
 t;%0A%09%7D%0A%0A%09

use namespace for delegated methods impl