/*
 * Copyright (c) 2014 QNX Software Systems and others.
 * 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
 */
package org.eclipse.cdt.qt.tests;

import java.util.Collection;

import org.eclipse.cdt.qt.core.index.IQObject;
import org.eclipse.cdt.qt.core.index.IQmlRegistration;
import org.eclipse.cdt.qt.core.index.QtIndex;

public class QmlRegistrationTests extends BaseQtTestCase {

	// #include "junit-QObject.hh"
    // class B : public QObject
    // {
    // Q_OBJECT
    // };
	//
    // class D : public B
    // {
    // Q_OBJECT
    // };
	//
	// static void func()
	// {
	//     qmlRegisterType<B>( "b-uri",    1, 2, "B" );
	//     qmlRegisterType<B>( "b-uri.34", 3, 4, "B34" );
	//
	//     const char * uri = "d-uri";
	//     int maj = 2, min = 3;
	//     const char * qmlName = "D1";
	//     qmlRegisterType<D, 1>( uri, maj, min, qmlName );
	// }
	public void testQmlRegisterType() throws Exception {
		loadComment("qmlregistertype.hh");

		QtIndex qtIndex = QtIndex.getIndex(fProject);
		assertNotNull(qtIndex);

		IQObject b_qobj = qtIndex.findQObject(new String[]{ "B" });
		if (!isIndexOk("B", b_qobj))
			return;
		assertNotNull(b_qobj);

		Collection<IQmlRegistration> qmlRegistrations = qtIndex.getQmlRegistrations();
		assertNotNull(qmlRegistrations);
		assertEquals(3, qmlRegistrations.size());

		for(IQmlRegistration qmlRegistration : qmlRegistrations) {
			IQObject qobj = qmlRegistration.getQObject();
			assertNotNull(qobj);

			// all values of B should be fully resolved, except for Revision, which was not provided
			if (qobj.getName().equals("B")) {
				assertNull(qmlRegistration.getVersion());
				String qmlName = qmlRegistration.getQmlName();
				assertNotNull(qmlName);
				if ("B".equals(qmlName)) {
					assertEquals(IQmlRegistration.Kind.Type, qmlRegistration.getKind());
					assertEquals("b-uri",         qmlRegistration.getURI());
					assertEquals(Long.valueOf(1), qmlRegistration.getMajor());
					assertEquals(Long.valueOf(2), qmlRegistration.getMinor());
					assertNull(qmlRegistration.getReason());
				} else if ("B34".equals(qmlName)) {
					assertEquals(IQmlRegistration.Kind.Type, qmlRegistration.getKind());
					assertEquals("b-uri.34",      qmlRegistration.getURI());
					assertEquals(Long.valueOf(3), qmlRegistration.getMajor());
					assertEquals(Long.valueOf(4), qmlRegistration.getMinor());
					assertNull(qmlRegistration.getReason());
				} else {
					fail("unexpected uri for B " + qmlName);
				}

			// the values for D are not expected to be resolved (yet), but it does have a Revision
			} else if (qobj.getName().equals("D")) {
				assertEquals(IQmlRegistration.Kind.Type, qmlRegistration.getKind());
				assertEquals(Long.valueOf(1), qmlRegistration.getVersion());
				assertNull(qmlRegistration.getURI());
				assertNull(qmlRegistration.getMajor());
				assertNull(qmlRegistration.getMinor());
				assertNull(qmlRegistration.getQmlName());
				assertNull(qmlRegistration.getReason());

			} else {
				fail("unexpected qmlRegistration " + qobj.getName());
			}
		}
	}

	// class T;
	//
	// static void func()
	// {
	//     qmlRegisterType<T>( "t-uri", 3, 4, "qml-T" );
	// }
	public void testQmlRegisterFwdDecl() throws Exception {
		loadComment("qmlregistertype.hh");
		waitForIndexer(fCProject);

		QtIndex qtIndex = QtIndex.getIndex(fProject);
		assertNotNull(qtIndex);

		Collection<IQmlRegistration> qmlRegistrations = qtIndex.getQmlRegistrations();
		assertNotNull(qmlRegistrations);
		assertEquals(1, qmlRegistrations.size());

		IQmlRegistration qmlRegistration = qmlRegistrations.iterator().next();
		assertNotNull(qmlRegistration);
		assertEquals(IQmlRegistration.Kind.Type, qmlRegistration.getKind());
		assertEquals("t-uri", qmlRegistration.getURI());
		assertEquals(Long.valueOf(3), qmlRegistration.getMajor());
		assertEquals(Long.valueOf(4), qmlRegistration.getMinor());
		assertEquals("qml-T", qmlRegistration.getQmlName());
		assertNull(qmlRegistration.getReason());

		// The QObject has not been defined, so it cannot be found.
		assertNull(qmlRegistration.getQObject());
	}

	// #include "junit-QObject.hh"
    // class B : public QObject
    // {
    // Q_OBJECT
    // };
	//
    // class D : public B
    // {
    // Q_OBJECT
    // };
	//
	// static void func()
	// {
	//     qmlRegisterUncreatableType<B>( "b-uri",    1, 2, "B",   QString( "msg1" ) );
	//     qmlRegisterUncreatableType<B>( "b-uri.34", 3, 4, "B34", QString( "msg2" ) );
	//
	//     const char * uri = "d-uri";
	//     int maj = 2, min = 3;
	//     const char * qmlName = "D1";
	//     const QString msg( "msg3" );
	//     qmlRegisterUncreatableType<D>( uri, maj, min, qmlName, msg );
	// }
	public void testQmlRegisterUncreatableType() throws Exception {
		loadComment("qmlregisteruncreatabletype.hh");

		QtIndex qtIndex = QtIndex.getIndex(fProject);
		assertNotNull(qtIndex);

		IQObject b_qobj = qtIndex.findQObject(new String[]{ "B" });
		if (!isIndexOk("B", b_qobj))
			return;
		assertNotNull(b_qobj);

		Collection<IQmlRegistration> qmlRegistrations = qtIndex.getQmlRegistrations();
		assertNotNull(qmlRegistrations);
		assertEquals(3, qmlRegistrations.size());

		for(IQmlRegistration qmlRegistration : qmlRegistrations) {
			IQObject qobj = qmlRegistration.getQObject();
			assertNotNull(qobj);

			// all values of B should be fully resolved, except for Revision, which was not provided
			if (qobj.getName().equals("B")) {
				assertNull(qmlRegistration.getVersion());
				String qmlName = qmlRegistration.getQmlName();
				assertNotNull(qmlName);
				if ("B".equals(qmlName)) {
					assertEquals(IQmlRegistration.Kind.Uncreatable, qmlRegistration.getKind());
					assertEquals("b-uri",         qmlRegistration.getURI());
					assertEquals(Long.valueOf(1), qmlRegistration.getMajor());
					assertEquals(Long.valueOf(2), qmlRegistration.getMinor());
					assertEquals(null/*"msg1"*/,          qmlRegistration.getReason());
				} else if ("B34".equals(qmlName)) {
					assertEquals(IQmlRegistration.Kind.Uncreatable, qmlRegistration.getKind());
					assertEquals("b-uri.34",      qmlRegistration.getURI());
					assertEquals(Long.valueOf(3), qmlRegistration.getMajor());
					assertEquals(Long.valueOf(4), qmlRegistration.getMinor());
					assertEquals(null/*"msg2"*/,          qmlRegistration.getReason());
				} else {
					fail("unexpected uri for B " + qmlName);
				}

			// the values for D are not expected to be resolved (yet), but it does have a Revision
			} else if (qobj.getName().equals("D")) {
				assertEquals(IQmlRegistration.Kind.Uncreatable, qmlRegistration.getKind());
				assertNull(qmlRegistration.getVersion());
				assertNull(qmlRegistration.getURI());
				assertNull(qmlRegistration.getMajor());
				assertNull(qmlRegistration.getMinor());
				assertNull(qmlRegistration.getQmlName());
				assertNull(qmlRegistration.getReason());
			} else {
				fail("unexpected qmlRegistration " + qobj.getName());
			}
		}
	}

	// #include "junit-QObject.hh"
    // class B : public QObject
    // {
    // Q_OBJECT
    // };
	//
    // class D : public B
    // {
    // Q_OBJECT
    // };
	//
	// static void func()
	// {
	//     qmlRegisterType<B>( "b-uri",    1, 2, "B" );
	//     qmlRegisterType<B>( "b-uri.34", 3, 4, "B34" );
	//     qmlRegisterType<D, 1>( "d-uri", 2, 3, "D" );
	// }
	public void testAccessFromQObject() throws Exception {
		loadComment("qmlregistertype_fromqobject.hh");

		QtIndex qtIndex = QtIndex.getIndex(fProject);
		assertNotNull(qtIndex);

		IQObject b_qobj = qtIndex.findQObject(new String[]{ "B" });
		if (!isIndexOk("B", b_qobj))
			return;
		assertNotNull(b_qobj);

		Collection<IQmlRegistration> b_qmlRegistrations = b_qobj.getQmlRegistrations();
		assertNotNull(b_qmlRegistrations);
		assertEquals(2, b_qmlRegistrations.size());
		for(IQmlRegistration qmlRegistration : b_qmlRegistrations)
			if ("B".equals(qmlRegistration.getQmlName()))
				assert_checkQmlRegistration(qmlRegistration, IQmlRegistration.Kind.Type, null, "b-uri", 1L, 2L, null);
			else if("B34".equals(qmlRegistration.getQmlName()))
				assert_checkQmlRegistration(qmlRegistration, IQmlRegistration.Kind.Type, null, "b-uri.34", 3L, 4L, null);
			else
				fail("unexpected QmlRegistration with qmlName '" + qmlRegistration.getQmlName() + '\'');

		IQObject d_qobj = qtIndex.findQObject(new String[]{ "D" });
		assertNotNull(d_qobj);

		Collection<IQmlRegistration> d_qmlRegistrations = d_qobj.getQmlRegistrations();
		assertNotNull(d_qmlRegistrations);
		assertEquals(1, d_qmlRegistrations.size());
		for(IQmlRegistration qmlRegistration : d_qmlRegistrations)
			if("D".equals(qmlRegistration.getQmlName()))
				assert_checkQmlRegistration(qmlRegistration, IQmlRegistration.Kind.Type, 1L, "d-uri", 2L, 3L, null);
			else
				fail("unexpected QmlRegistration with qmlName '" + qmlRegistration.getQmlName() + '\'');
	}

	private static void assert_checkQmlRegistration(IQmlRegistration qmlRegistration, IQmlRegistration.Kind eKind, Long eVersion, String eUri, Long eMaj, Long eMin, String reason) throws Exception {
		assertNotNull(qmlRegistration);
		assertEquals(eKind, qmlRegistration.getKind());
		assertEquals(eVersion, qmlRegistration.getVersion());
		assertEquals(eUri, qmlRegistration.getURI());
		assertEquals(eMaj, qmlRegistration.getMajor());
		assertEquals(eMin, qmlRegistration.getMinor());
		assertEquals(reason, qmlRegistration.getReason());
	}
}
