#     Copyright 2018, Kay Hayen, mailto:kay.hayen@gmail.com
#
#     Part of "Nuitka", an optimizing Python compiler that is compatible and
#     integrates with CPython, but also works on its own.
#
#     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.
#
""" Tuple codes

"""

from .CodeHelpers import (
    decideConversionCheckNeeded,
    generateExpressionCode,
    withObjectCodeTemporaryAssignment
)
from .ConstantCodes import getConstantAccess
from .PythonAPICodes import generateCAPIObjectCode


def _areConstants(expressions):
    for expression in expressions:
        if not expression.isExpressionConstantRef():
            return False

        if expression.isMutable():
            return False

    return True


def generateTupleCreationCode(to_name, expression, emit, context):
    with withObjectCodeTemporaryAssignment(to_name, "tuple_value", expression, emit, context) \
      as value_name:

        getTupleCreationCode(
            to_name  = value_name,
            elements = expression.getElements(),
            emit     = emit,
            context  = context
        )


def getTupleCreationCode(to_name, elements, emit, context):
    if _areConstants(elements):
        getConstantAccess(
            to_name  = to_name,
            constant = tuple(
                element.getConstant()
                for element in
                elements
            ),
            emit     = emit,
            context  = context
        )
    else:
        element_name = context.allocateTempName("tuple_element")

        for count, element in enumerate(elements):
            generateExpressionCode(
                to_name    = element_name,
                expression = element,
                emit       = emit,
                context    = context
            )

            if count == 0:
                emit(
                    "%s = PyTuple_New( %d );" % (
                        to_name,
                        len(elements)
                    )
                )

                context.addCleanupTempName(to_name)

            if not context.needsCleanup(element_name):
                emit("Py_INCREF( %s );" % element_name)
            else:
                context.removeCleanupTempName(element_name)

            emit(
                "PyTuple_SET_ITEM( %s, %d, %s );" % (
                    to_name,
                    count,
                    element_name
                )
            )


def generateBuiltinTupleCode(to_name, expression, emit, context):
    generateCAPIObjectCode(
        to_name          = to_name,
        capi             = "PySequence_Tuple",
        arg_desc         = (
            ("tuple_arg", expression.getValue()),
        ),
        may_raise        = expression.mayRaiseException(BaseException),
        conversion_check = decideConversionCheckNeeded(to_name, expression),
        source_ref       = expression.getCompatibleSourceReference(),
        emit             = emit,
        context          = context
    )
