.pragma library

function compareArray(a, b) {
    if (a.length !== b.length)
        return false;

    for (var i = 0; i < a.length; ++i) {
        var aMatched = false;
        var bMatched = false;

        for (var j = 0; j < b.length; ++j) {
            if (a[i] === b[j])
                aMatched = true;
            if (b[i] === a[j])
                bMatched = true;
            if (aMatched && bMatched)
                break;
        }

        if (!aMatched || !bMatched)
            return false;
    }

    return true;
}

function testObjectProperties(testCase, testObject, data) {
    var signalSpy = Qt.createQmlObject('import QtTest 1.0; SignalSpy {}', testCase, "SignalSpy");
    signalSpy.target = testObject;
    signalSpy.signalName = data.signal;

    // set property to something new
    testObject[data.property] = data.value;
    if (data.array) {
        if (data.expectedValue) {
            testCase.verify(compareArray(testObject[data.property], data.expectedValue));
            testCase.compare(
                        signalSpy.count,
                        1 + (data.emitsExtraSignals ? data.expectedValue.length : 0));
        } else {
            testCase.verify(compareArray(testObject[data.property], data.value));
            testCase.compare(signalSpy.count, 1 + (data.emitsExtraSignals ? data.value.length : 0));
        }

    } else {
        testCase.compare(testObject[data.property], data.value);
        testCase.compare(signalSpy.count, 1);
    }

    signalSpy.clear();

    // set property to same value
    testObject[data.property] = data.value;
    if (data.array) {
        if (data.expectedValue) {
            testCase.verify(compareArray(testObject[data.property], data.expectedValue));
            testCase.expectFailContinue(
                        "category",
                        "The QML engine should check equality before assigning a single object to a list.")
            testCase.compare(signalSpy.count, 0);
        } else {
            testCase.verify(compareArray(testObject[data.property], data.value));
            testCase.compare(signalSpy.count, 0);
        }

    } else {
        testCase.compare(testObject[data.property], data.value);
        testCase.compare(signalSpy.count, 0);
    }

    signalSpy.clear();

    // reset property
    if (data.reset === undefined) {
        testObject[data.property] = null;
        testCase.compare(testObject[data.property], null);
    } else {
        testObject[data.property] = data.reset;
        if (data.array)
            testCase.verify(compareArray(testObject[data.property], data.reset));
        else
            testCase.compare(testObject[data.property], data.reset);
    }
    testCase.compare(signalSpy.count, 1);
    signalSpy.destroy();
}

function compareObj(testCase, obj1, obj2) {
    for (var propertyName in obj2) {
        if (obj1[propertyName] !== undefined) {
            if (propertyName === "dateTime" && isNaN(obj2["dateTime"].getTime()))
                testCase.verify(isNaN(obj1["dateTime"].getTime()));
            else
                testCase.compare(obj1[propertyName], obj2[propertyName])
        }
    }
}

function testConsecutiveFetch(testCase, model, place, expectedValues, data)
{
    var signalSpy = Qt.createQmlObject('import QtTest 1.0; SignalSpy {}', testCase, "SignalSpy");
    signalSpy.target = model;
    signalSpy.signalName ="totalCountChanged";

    var visDataModel = Qt.createQmlObject('import QtQuick 2.0; import QtQml.Models 2.14; '
                                       + 'DelegateModel{ delegate: Text{} }',
                                       testCase, "dataModel");
    visDataModel.model = model;

    //check that initial values are as expected
    testCase.compare(model.totalCount, -1);
    testCase.compare(model.place, null);
    testCase.compare(visDataModel.items.count, 0);

    //perform an initial fetch with the default batch size
    model.batchSize = data.batchSize
    model.place = place;
    testCase.tryCompare(signalSpy, "count", 1);
    signalSpy.clear();

    var totalCount = model.totalCount;
    testCase.compare(totalCount, 5);
    testCase.compare(visDataModel.items.count, Math.min(data.batchSize, totalCount));

    compareObj(testCase, visDataModel.items.get(0).model, expectedValues[0]);

    //fetch remaining items, in batchSize batches
    while (visDataModel.items.count < totalCount) {
        var startIndex = visDataModel.items.count

        //'creating' the last item will trigger a fetch
        visDataModel.items.create(visDataModel.items.count - 1);

        testCase.tryCompare(visDataModel.items, "count", Math.min(totalCount, startIndex + data.batchSize));
        testCase.compare(signalSpy.count, 0);
        testCase.compare(model.totalCount, totalCount);

        for (var i = startIndex; i < Math.min(totalCount, startIndex + data.batchSize); ++i)
            compareObj(testCase, visDataModel.items.get(i).model, expectedValues[i]);
    }

    visDataModel.destroy();
    signalSpy.destroy();
}

function testReset(testCase, model, place)
{
    var dataModel = Qt.createQmlObject('import QtQuick 2.0; import QtQml.Models 2.14; '
                                       + 'DelegateModel{ delegate: Text{} }',
                                       testCase, "dataModel");

    dataModel.model = model;
    model.place = place;
    testCase.tryVerify(() => { return model.totalCount > 0 }, 100);
    testCase.verify(dataModel.items.count > 0);

    model.place = null;
    testCase.tryCompare(model, "totalCount", -1);
    testCase.compare(dataModel.items.count, 0);

    dataModel.destroy();
}

function testFetch(testCase, data)
{
    var model = data.model;
    var visDataModel = Qt.createQmlObject('import QtQuick 2.0; import QtQml.Models 2.14; '
                                       + 'DelegateModel{ delegate: Text{} }',
                                       testCase, "dataModel");
    visDataModel.model = model

    var signalSpy = Qt.createQmlObject('import QtTest 1.0; SignalSpy {}',
                                       testCase, "SignalSpy");
    signalSpy.target = model;
    signalSpy.signalName ="totalCountChanged";

    model.batchSize = data.batchSize;
    model.place = data.place;
    testCase.tryCompare(signalSpy, "count", 1);
    signalSpy.clear();
    testCase.compare(model.totalCount, data.expectedTotalCount);
    testCase.compare(visDataModel.items.count, data.expectedCount);

    visDataModel.destroy();
    signalSpy.destroy();
}
