/**
 * Copyright (c) 2017 NumberFour AG.
 * All rights reserved. This program and the accompanying materials
 * are 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:
 *   NumberFour AG - Initial API and implementation
 */
package org.eclipse.n4js.ui.editor;

import java.util.List;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.n4js.ts.types.TMember;
import org.eclipse.n4js.utils.URIUtils;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.hyperlinking.HyperlinkHelper;
import org.eclipse.xtext.ui.editor.hyperlinking.HyperlinkLabelProvider;
import org.eclipse.xtext.ui.editor.hyperlinking.IHyperlinkAcceptor;
import org.eclipse.xtext.ui.editor.hyperlinking.XtextHyperlink;

import com.google.inject.Inject;
import com.google.inject.Provider;

/**
 * This class provides multiple hyperlinks for composed members.
 */
public class N4JSHyperlinkHelper extends HyperlinkHelper {

	@Inject
	@HyperlinkLabelProvider
	private ILabelProvider labelProvider;

	@Inject
	private Provider<XtextHyperlink> hyperlinkProvider;

	@Override
	public void createHyperlinksTo(XtextResource from, Region region, EObject target, IHyperlinkAcceptor acceptor) {
		boolean linksProvided = provideHyperlinksForComposedTypes(from, region, target, acceptor);
		if (!linksProvided) {
			internalCreateHyperlinksTo(from, region, target, acceptor);
		}
	}

	/** This method provides multiple hyperlinks for composed members. */
	private boolean provideHyperlinksForComposedTypes(XtextResource from, Region region, EObject target,
			IHyperlinkAcceptor acceptor) {

		if (target instanceof TMember) {
			TMember member = (TMember) target;
			if (member.isComposed()) {
				List<TMember> constituentMembers = member.getConstituentMembers();
				for (TMember constituentMember : constituentMembers) {
					internalCreateHyperlinksTo(from, region, constituentMember, acceptor);
				}
				return true;
			}
		}
		return false;
	}

	private void internalCreateHyperlinksTo(XtextResource from, Region region, EObject target,
			IHyperlinkAcceptor acceptor) {

		boolean linksProvided = provideHyperlinksForExternalFiles(region, target, acceptor);
		if (!linksProvided) {
			super.createHyperlinksTo(from, region, target, acceptor);
		}
	}

	/** This method converts file URIs to platform URIs for external library files. */
	private boolean provideHyperlinksForExternalFiles(IRegion region, EObject target, IHyperlinkAcceptor acceptor) {
		URI targetUriWithFragment = EcoreUtil.getURI(target);
		if (targetUriWithFragment.isFile()) {
			URI uri = URIUtils.tryToPlatformUri(targetUriWithFragment);
			superCreateHyperlinksTo(region, target, acceptor, uri);
			return true;
		}
		return false;
	}

	private void superCreateHyperlinksTo(IRegion region, EObject target, IHyperlinkAcceptor acceptor, URI normalized) {
		String hyperlinkText = labelProvider.getText(target);
		XtextHyperlink result = hyperlinkProvider.get();
		result.setHyperlinkRegion(region);
		result.setURI(normalized);
		result.setHyperlinkText(hyperlinkText);
		acceptor.accept(result);
	}
}