/*
 * Copyright 2010-2012 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 org.napile.idea.plugin.highlighter;

import static org.napile.compiler.lang.resolve.BindingContext.AUTOCAST;
import static org.napile.compiler.lang.resolve.BindingContext.AUTO_CREATED_IT;
import static org.napile.compiler.lang.resolve.BindingContext.CAPTURED_IN_CLOSURE;
import static org.napile.compiler.lang.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR;
import static org.napile.compiler.lang.resolve.BindingContext.REFERENCE_TARGET;

import org.jetbrains.annotations.NotNull;
import org.napile.compiler.lang.descriptors.DeclarationDescriptor;
import org.napile.compiler.lang.descriptors.LocalVariableDescriptor;
import org.napile.compiler.lang.descriptors.PropertyKind;
import org.napile.compiler.lang.descriptors.ParameterDescriptor;
import org.napile.compiler.lang.descriptors.VariableDescriptor;
import org.napile.compiler.lang.psi.NapileExpression;
import org.napile.compiler.lang.psi.NapileNamedDeclaration;
import org.napile.compiler.lang.psi.NapilePropertyParameter;
import org.napile.compiler.lang.psi.NapileProperty;
import org.napile.compiler.lang.psi.NapileSimpleNameExpression;
import org.napile.compiler.lang.resolve.BindingContext;
import org.napile.compiler.lang.types.JetType;
import org.napile.compiler.resolve.DescriptorRenderer;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.psi.PsiElement;

class VariablesHighlightingVisitor extends AfterAnalysisHighlightingVisitor
{
	VariablesHighlightingVisitor(AnnotationHolder holder, BindingContext bindingContext)
	{
		super(holder, bindingContext);
	}

	@Override
	public void visitSimpleNameExpression(@NotNull NapileSimpleNameExpression expression)
	{
		DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, expression);
		if(target == null)
		{
			return;
		}
		if(target instanceof ParameterDescriptor)
		{
			ParameterDescriptor parameterDescriptor = (ParameterDescriptor) target;
			if(Boolean.TRUE.equals(bindingContext.get(AUTO_CREATED_IT, parameterDescriptor)))
			{
				holder.createInfoAnnotation(expression, "Automatically declared based on the expected type").setTextAttributes(JetHighlightingColors.FUNCTION_LITERAL_DEFAULT_PARAMETER);
			}
		}

		highlightVariable(expression, target);
		super.visitSimpleNameExpression(expression);
	}

	@Override
	public void visitProperty(@NotNull NapileProperty property)
	{
		visitVariableDeclaration(property);
		super.visitProperty(property);
	}

	@Override
	public void visitPropertyParameter(NapilePropertyParameter parameter)
	{
		visitVariableDeclaration(parameter);
		super.visitPropertyParameter(parameter);
	}

	@Override
	public void visitExpression(@NotNull NapileExpression expression)
	{
		JetType autoCast = bindingContext.get(AUTOCAST, expression);
		if(autoCast != null)
		{
			holder.createInfoAnnotation(expression, "Automatically cast to " + DescriptorRenderer.TEXT.renderType(autoCast)).setTextAttributes(JetHighlightingColors.AUTO_CASTED_VALUE);
		}
		super.visitExpression(expression);
	}

	private void visitVariableDeclaration(NapileNamedDeclaration declaration)
	{
		DeclarationDescriptor declarationDescriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, declaration);
		PsiElement nameIdentifier = declaration.getNameIdentifier();
		if(nameIdentifier != null && declarationDescriptor != null)
		{
			highlightVariable(nameIdentifier, declarationDescriptor);
		}
	}

	private void highlightVariable(@NotNull PsiElement elementToHighlight, @NotNull DeclarationDescriptor descriptor)
	{
		if(descriptor instanceof VariableDescriptor)
		{
			VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
			if(variableDescriptor.getPropertyKind() == PropertyKind.VAR)
			{
				JetPsiChecker.highlightName(holder, elementToHighlight, JetHighlightingColors.MUTABLE_VARIABLE);
			}

			if(Boolean.TRUE.equals(bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor)))
			{
				String msg = ((VariableDescriptor) descriptor).getPropertyKind() == PropertyKind.VAR ? "Wrapped into a reference object to be modified when captured in a closure" : "Value captured in a closure";
				holder.createInfoAnnotation(elementToHighlight, msg).setTextAttributes(JetHighlightingColors.WRAPPED_INTO_REF);
			}

			if(descriptor instanceof LocalVariableDescriptor)
			{
				JetPsiChecker.highlightName(holder, elementToHighlight, JetHighlightingColors.LOCAL_VARIABLE);
			}

			if(descriptor instanceof ParameterDescriptor)
			{
				JetPsiChecker.highlightName(holder, elementToHighlight, JetHighlightingColors.PARAMETER);
			}
		}
	}
}

@@ -4273,32 +4273,34 @@
 d.VAR)%0A%09%09%09%7B%0A%09%09%09%09
+//
 JetPsiChecker.hi

remove underline of mutable var - stupied hardcode