## SPDX-License-Identifier: BSD-2-Clause
##
## Copyright 2020-2025 Inria & Université de Bordeaux
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions
## are met:
##
## 1. Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
##
## 2. Redistributions in binary form must reproduce the above
## copyright notice, this list of conditions and the following
## disclaimer in the documentation and/or other materials provided
## with the distribution.
##
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
## CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
## INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
## DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
## TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
## ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
## TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
## THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
## SUCH DAMAGE.
##

import scotchpy as SCOTCH
import ctypes
import threading
import os

# taken from check/test_scotch_context.c


class TestThreadData:
    contptr = None
    thrdnum = 0


def graphTest():
    return SCOTCH.build_graph(
        verttab=[1, 4, 10, 13, 16, 19, 22, 25],
        edgetab=[
            3,
            2,
            6,
            3,
            4,
            1,
            7,
            6,
            5,
            1,
            2,
            4,
            2,
            7,
            3,
            7,
            2,
            6,
            2,
            1,
            5,
            5,
            2,
            4,
        ],
    )


def testMain():

    for thrdnbr in {3, os.cpu_count()}:
        try:
            context = SCOTCH.Context()
        except SCOTCH.LibraryError:
            assert False, "cannot initialize context"
            raise

        graf0 = graphTest()
        try:
            graf1 = SCOTCH.Graph()
        except SCOTCH.LibraryError:
            assert False, "cannot initialize graph"
            raise

        try:
            context.bind_graph(graf0, graf1)
        except SCOTCH.LibraryError:
            assert False, "cannot bind context(1)"
            raise

        graf1.exit()
        context.exit()

        context.init()
        context.thread_spawn(thrdnbr, None)
        graf1.init()

        try:
            context.bind_graph(graf0, graf1)
        except SCOTCH.LibraryError:
            assert False, "cannot bind context(2)"
            raise

        graf1.exit()
        context.exit()

        coretab = ctypes.POINTER(ctypes.c_int)()
        coretab = (ctypes.c_int * thrdnbr)()
        coretab[0] = 0

        for thrdnum in range(1, thrdnbr):
            coretab[thrdnum] = thrdnbr - thrdnum

        context.init()
        context.thread_spawn(thrdnbr, coretab)

        try:
            context.random_clone()
        except SCOTCH.LibraryError:
            assert False, "cannot clone random context"
            raise
        graf1.init()

        try:
            context.bind_graph(graf0, graf1)
        except SCOTCH.LibraryError:
            assert False, "cannot bind context(3)"
            raise
        graf1.exit()
        context.exit()

        thrdtab = [TestThreadData() for _ in range(thrdnbr)]
        for thrdnum in range(thrdnbr):
            thrdtab[thrdnum].thrdnum = thrdnum
            thrdtab[thrdnum].contptr = context._contextptr
        context.init()
        context.thread_import1(thrdnbr)

        for thrdnum in range(1, thrdnbr):
            try:
                threading.Thread(
                    target=context.thread_import2, args=(thrdtab[thrdnum].thrdnum,)
                ).start()
            except SCOTCH.LibraryError:
                assert False, "cannot import thread"
                raise
        context.thread_import2(0)
        graf1.init()

        try:
            context.bind_graph(graf0, graf1)
        except SCOTCH.LibraryError:
            assert False, "cannot bind context(4)"
            raise
        graf1.exit()
        context.exit()
        graf0.exit()
