/*******************************************************************************
 * Copyright (c) 2007 Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Red Hat, Inc. - initial API and implementation
 ******************************************************************************/ 
package org.jboss.tools.seam.ui.views.properties;

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

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.jboss.tools.common.el.core.ca.AbstractELCompletionEngine;
import org.jboss.tools.common.el.core.model.ELInstance;
import org.jboss.tools.common.el.core.model.ELInvocationExpression;
import org.jboss.tools.common.el.core.model.ELModel;
import org.jboss.tools.common.el.core.model.ELUtil;
import org.jboss.tools.common.el.core.resolver.SimpleELContext;
import org.jboss.tools.common.meta.XAttribute;
import org.jboss.tools.common.meta.action.XEntityData;
import org.jboss.tools.common.model.XModelObject;
import org.jboss.tools.common.model.filesystems.FileSystemsHelper;
import org.jboss.tools.common.model.ui.attribute.AttributeContentProposalProviderFactory;
import org.jboss.tools.common.model.ui.attribute.IAttributeContentProposalProvider;
import org.jboss.tools.common.text.TextProposal;
import org.jboss.tools.seam.core.ISeamProject;
import org.jboss.tools.seam.core.SeamCorePlugin;
import org.jboss.tools.seam.internal.core.el.SeamELCompletionEngine;

/**
 * @author Viacheslav Kabanovich
 */
public class SeamELAttributeContentProposalProvider implements
		IAttributeContentProposalProvider {
	XModelObject object;
	XAttribute attribute;
	IFile file;
	SeamELCompletionEngine engine;

	public boolean isRelevant(XModelObject object, XAttribute attribute) {
		if(attribute == null) {
			return false;
		}
		String module = attribute.getModelEntity().getModule();
		if(module == null || !module.startsWith("Seam")) {
			return false;
		}
		String entity = attribute.getModelEntity().getName();
		if(entity.startsWith("File")) {
			return false;
		}
		return true;
	}

	public IContentProposalProvider getContentProposalProvider() {
		if(file == null || engine == null) return null;
		return new ContentProposalProvider();
	}

	public int getProposalAcceptanceStyle() {
		return ContentProposalAdapter.PROPOSAL_INSERT;
	}

	public void init(XModelObject object, XEntityData data, XAttribute attribute) {
		this.object = object;
		this.attribute = attribute;
		object = FileSystemsHelper.getFile(object);
		if(object != null) {
			IResource r = (IResource)object.getAdapter(IResource.class);
			if(r instanceof IFile) {
				file = (IFile)r;
			}
		}
		if(file != null) {
			IProject project = file.getProject();
			ISeamProject seamProject = SeamCorePlugin.getSeamProject(project, true);
			if(seamProject != null) {
				engine = new SeamELCompletionEngine();
			}
		}

	}

	static IContentProposal[] EMPTY = new IContentProposal[0];

	class ContentProposalProvider implements IContentProposalProvider {

		public IContentProposal[] getProposals(String contents, int position) {
			ELModel model = engine.getParserFactory().createParser().parse(contents);
			ELInstance is = ELUtil.findInstance(model, position);
			if(is == null) {
				return EMPTY;
			}

			boolean addClosingToken = is.getOpenInstanceToken() != null && is.getCloseInstanceToken() == null;
			
			String prefix = getPrefix(contents, position, 0, contents.length());
			if(prefix == null || prefix.length() == 0) {
				if(!isExpressionAllowed(contents, position)) {
					return EMPTY;
				}
			}

			if(prefix == null) prefix = "";
			
			List<TextProposal> suggestions = null;
			SimpleELContext context = new SimpleELContext();
			context.setResource(file);
			suggestions = engine.getProposals(context, prefix, -1);
			if(suggestions == null) {
				return EMPTY;
			}
			List<TextProposal> uniqueSuggestions = AbstractELCompletionEngine.makeProposalsUnique(suggestions);
			
			List<IContentProposal> list = new ArrayList<IContentProposal>();
			for (TextProposal p: uniqueSuggestions) {
				String label = prefix + p.getReplacementString();
				IContentProposal cp = AttributeContentProposalProviderFactory.makeContentProposal(p.getReplacementString() + (addClosingToken ? "}" : ""), label, null);
				list.add(cp);
			}
			return list.toArray(new IContentProposal[0]);
		}
		
	}

	public String getPrefix(String content, int offset, int start, int end) throws StringIndexOutOfBoundsException {
		if (content == null || offset > content.length())
			return null;
		ELInvocationExpression expr = engine.findExpressionAtOffset(content, offset, start, end);
		if (expr == null)
			return null;
		return content.substring(expr.getStartPosition(), offset);
	}

	private boolean isExpressionAllowed(String contents, int position) {
		String el = contents.substring(0, position) + "a";
		ELModel model1 = engine.getParserFactory().createParser().parse(el);
		ELInvocationExpression expr = ELUtil.findExpression(model1, el.length());
		return (expr != null);		
	}

	public void dispose() {
		object = null;
		attribute = null;
		file = null;
		engine = null;
	}

	public LabelProvider getCustomLabelProbider() {
		return null;
	}

}
