/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES 3.1 Module
 * -------------------------------------------------
 *
 * Copyright 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Boolean State Query tests.
 *//*--------------------------------------------------------------------*/

#include "es31fBooleanStateQueryTests.hpp"
#include "glsStateQueryUtil.hpp"
#include "gluRenderContext.hpp"
#include "gluCallLogWrapper.hpp"
#include "tcuRenderTarget.hpp"
#include "glwFunctions.hpp"
#include "glwEnums.hpp"

namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace
{

using namespace gls::StateQueryUtil;

static const char *getVerifierSuffix(QueryType type)
{
    switch (type)
    {
    case QUERY_ISENABLED:
        return "isenabled";
    case QUERY_BOOLEAN:
        return "getboolean";
    case QUERY_INTEGER:
        return "getinteger";
    case QUERY_INTEGER64:
        return "getinteger64";
    case QUERY_FLOAT:
        return "getfloat";
    default:
        DE_ASSERT(false);
        return DE_NULL;
    }
}

class IsEnabledStateTestCase : public TestCase, private glu::CallLogWrapper
{
public:
    IsEnabledStateTestCase(Context &context, QueryType verifier, const char *name, const char *description,
                           glw::GLenum targetName, bool initial, glu::ApiType minimumContextVersion)
        : TestCase(context, name, description)
        , glu::CallLogWrapper(context.getRenderContext().getFunctions(), context.getTestContext().getLog())
        , m_targetName(targetName)
        , m_initial(initial)
        , m_verifier(verifier)
        , m_minimumVersion(minimumContextVersion)
    {
    }

    IterateResult iterate(void)
    {
        if (!contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
            TCU_CHECK_AND_THROW(NotSupportedError,
                                contextSupports(m_context.getRenderContext().getType(), m_minimumVersion),
                                "This test requires a higher context version.");

        tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
        enableLogging(true);

        // check inital value
        verifyStateBoolean(result, *this, m_targetName, m_initial, m_verifier);

        // check toggle

        GLU_CHECK_CALL(glEnable(m_targetName));

        verifyStateBoolean(result, *this, m_targetName, true, m_verifier);

        GLU_CHECK_CALL(glDisable(m_targetName));

        verifyStateBoolean(result, *this, m_targetName, false, m_verifier);

        result.setTestContextResult(m_testCtx);
        return STOP;
    }

private:
    const glw::GLenum m_targetName;
    const bool m_initial;
    const QueryType m_verifier;
    const glu::ApiType m_minimumVersion;
};

} // namespace

BooleanStateQueryTests::BooleanStateQueryTests(Context &context)
    : TestCaseGroup(context, "boolean", "Boolean State Query tests")
{
}

BooleanStateQueryTests::~BooleanStateQueryTests(void)
{
}

void BooleanStateQueryTests::init(void)
{
    const bool isDebugContext = (m_context.getRenderContext().getType().getFlags() & glu::CONTEXT_DEBUG) != 0;

    static const QueryType isEnabledVerifiers[] = {QUERY_ISENABLED, QUERY_BOOLEAN, QUERY_INTEGER, QUERY_INTEGER64,
                                                   QUERY_FLOAT};

#define FOR_EACH_VERIFIER(VERIFIERS, X)                                                       \
    do                                                                                        \
    {                                                                                         \
        for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(VERIFIERS); ++verifierNdx) \
        {                                                                                     \
            const char *verifierSuffix = getVerifierSuffix((VERIFIERS)[verifierNdx]);         \
            const QueryType verifier   = (VERIFIERS)[verifierNdx];                            \
            this->addChild(X);                                                                \
        }                                                                                     \
    } while (0)

    struct StateBoolean
    {
        const char *name;
        const char *description;
        glw::GLenum targetName;
        bool value;
        glu::ApiType minimumContext;
    };

    {
        const StateBoolean isEnableds[] = {
            {"sample_mask", "SAMPLE_MASK", GL_SAMPLE_MASK, false, glu::ApiType::es(3, 1)},
            {"sample_shading", "SAMPLE_SHADING", GL_SAMPLE_SHADING, false, glu::ApiType::es(3, 2)},
            {"debug_output", "DEBUG_OUTPUT", GL_DEBUG_OUTPUT, isDebugContext, glu::ApiType::es(3, 2)},
            {"debug_output_synchronous", "DEBUG_OUTPUT_SYNCHRONOUS", GL_DEBUG_OUTPUT_SYNCHRONOUS, false,
             glu::ApiType::es(3, 2)},
        };

        for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(isEnableds); testNdx++)
        {
            FOR_EACH_VERIFIER(
                isEnabledVerifiers,
                new IsEnabledStateTestCase(m_context, verifier,
                                           (std::string(isEnableds[testNdx].name) + "_" + verifierSuffix).c_str(),
                                           isEnableds[testNdx].description, isEnableds[testNdx].targetName,
                                           isEnableds[testNdx].value, isEnableds[testNdx].minimumContext));
        }
    }

#undef FOR_EACH_VERIFIER
}

} // namespace Functional
} // namespace gles31
} // namespace deqp
