/**
 * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
 * <p/>
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * <p/>
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package org.arquillian.liferay.portal.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import java.net.URI;
import java.net.URL;

import org.jboss.arquillian.container.spi.client.protocol.metadata.HTTPContext;
import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.test.spi.TestEnricher;

/**
 * @author Cristina González
 */
public class PortalURLTestEnricher implements TestEnricher {

	public boolean contains(
		Annotation[] annotations, Class<?> annotationClass) {

		for (Annotation current : annotations) {
			if (annotationClass.isAssignableFrom(current.annotationType())) {
				return true;
			}
		}

		return false;
	}

	@Override
	public void enrich(Object testCase) {
		Class<?> testClass = testCase.getClass();

		Field[] declaredFields = testClass.getDeclaredFields();

		for (Field declaredField : declaredFields) {
			if (declaredField.isAnnotationPresent(PortalURL.class)) {
				PortalURL annotation = declaredField.getAnnotation(
					PortalURL.class);

				injectField(declaredField, testCase, annotation.value());
			}
		}
	}

	public Annotation getAnnotation(
		Annotation[] annotations, Class<?> annotationClass) {

		for (Annotation current : annotations) {
			if (annotationClass.isAssignableFrom(current.annotationType())) {
				return current;
			}
		}

		return null;
	}

	@Override
	public Object[] resolve(Method method) {
		Class<?>[] parameterTypes = method.getParameterTypes();
		Annotation[][] parametersAnnotations = method.getParameterAnnotations();

		Object[] parameters = new Object[parameterTypes.length];

		for (int i = 0; i < parameterTypes.length; i++) {
			Annotation[] parameterAnnotations = parametersAnnotations[i];

			if (contains(parameterAnnotations, PortalURL.class)) {
				PortalURL annotation = (PortalURL)getAnnotation(
					parameterAnnotations, PortalURL.class);

				parameters[i] = resolve(annotation.value());
			}
		}

		return parameters;
	}

	private void injectField(
		Field declaredField, Object testCase, String portletId) {

		setField(declaredField, testCase, resolve(portletId));
	}

	private URL resolve(String portletId) {
		ProtocolMetaData metaData = protocolMetadata.get();

		if (metaData == null) {
			return null;
		}

		if (metaData.hasContext(HTTPContext.class)) {
			HTTPContext context = metaData.getContexts(
				HTTPContext.class).iterator().next();

			try {
				URL url = new URI(
					"http", null, context.getHost(), context.getPort(), null,
					null, null).toURL();

				return new URL(
					url, "/o/install-portlet-servlet?portlet-id="+portletId);
			}
			catch (Exception e) {
				throw new RuntimeException("Can't obtain URL, " + context, e);
			}
		}

		return null;
	}

	private void setField(Field declaredField, Object testCase, URL service) {
		boolean accessible = declaredField.isAccessible();

		declaredField.setAccessible(true);

		try {
			declaredField.set(testCase, service);
		}
		catch (IllegalAccessException e) {
			e.printStackTrace();
		}

		declaredField.setAccessible(accessible);
	}

	@org.jboss.arquillian.core.api.annotation.Inject
	private Instance<ProtocolMetaData> protocolMetadata;

}
@@ -1736,24 +1736,35 @@
 RL.class);%0A%0A
+%09%09%09%09try %7B%0A%09
 %09%09%09%09injectFi
@@ -1805,32 +1805,199 @@
 ation.value());%0A
+%09%09%09%09%7D%0A%09%09%09%09catch (IllegalAccessException e) %7B%0A%09%09%09%09%09throw new RuntimeException(%0A%09%09%09%09%09%09%22It is not possible to inject the field %22 +%0A%09%09%09%09%09%09%09e.getMessage(),%0A%09%09%09%09%09%09e);%0A%09%09%09%09%7D%0A
 %09%09%09%7D%0A%09%09%7D%0A%09%7D%0A%0A%09pu
@@ -2880,16 +2880,17 @@
 ield(%0A%09%09
+%09
 Field de
@@ -2936,16 +2936,48 @@
 rtletId)
+%0A%09%09throws IllegalAccessException
  %7B%0A%0A%09%09se
@@ -3718,19 +3718,52 @@
 service)
+%0A%09%09throws IllegalAccessException
  %7B%0A
+%0A
 %09%09boolea
@@ -3846,25 +3846,16 @@
 true);%0A%0A
-%09%09try %7B%0A%09
 %09%09declar
@@ -3889,77 +3889,8 @@
 ce);
-%0A%09%09%7D%0A%09%09catch (IllegalAccessException e) %7B%0A%09%09%09e.printStackTrace();%0A%09%09%7D
 %0A%0A%09%09

Throw exception when the field can't be accessed