/*
 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package kotlinx.coroutines.experimental.channels

import com.devexperts.dxlab.lincheck.*
import com.devexperts.dxlab.lincheck.execution.*
import java.util.*

typealias ExecutionBuilder = (List<MutableList<Actor>>, List<ActorGenerator>) -> Unit

/**
 * Example of usage:
 *
 * ```
 * StressOptions().injectExecution { actors, methods ->
 *   actors[0].add(actorMethod(methods, "receive1"))
 *   actors[0].add(actorMethod(methods, "receive2"))
 *
 *   actors[1].add(actorMethod(methods, "send2"))
 *   actors[1].add(actorMethod(methods, "send1"))
 * }
 *
 * ```
 *
 * Will produce
 * ```
 * Actors per thread:
 * [receive1(), receive2()]
 * [send2(), send1()]
 * ```
 * at the first iteration.
 *
 * DSL will be improved when this method will be used frequently
 */
fun Options<*, *>.injectExecution(behaviourBuilder: ExecutionBuilder): Options<*, *> {
    injectedBehaviour.add(behaviourBuilder)
    executionGenerator(FixedBehaviourInjectorExecutionGenerator::class.java)
    return this
}

fun actorMethod(generators: List<ActorGenerator>, name: String): Actor =
    generators.find { it.generate().method.name.contains(name) }?.generate() ?: error("Actor method $name is not found in ${generators.map { it.generate().method.name }}")

private val injectedBehaviour: Queue<ExecutionBuilder> = ArrayDeque<ExecutionBuilder>()

class FixedBehaviourInjectorExecutionGenerator(testConfiguration: CTestConfiguration, testStructure: CTestStructure)
    : ExecutionGenerator(testConfiguration, testStructure) {

    private val randomGenerator = RandomExecutionGenerator(testConfiguration, testStructure)

    override fun nextExecution(): List<List<Actor>> {
        val injector = injectedBehaviour.poll()
        if (injector != null) {
            val parallelGroup = ArrayList(testStructure.actorGenerators)
            val actorsPerThread = ArrayList<MutableList<Actor>>()
            for (i in testConfiguration.threadConfigurations.indices) {
                actorsPerThread.add(ArrayList())
            }

            injector.invoke(actorsPerThread, parallelGroup)
            return actorsPerThread
        }

        return randomGenerator.nextExecution()
    }
}

// Ad-hoc fixed execution injection for lin-checker
class FixedBehaviourExecutionGenerator(testConfiguration: CTestConfiguration, testStructure: CTestStructure)
    : ExecutionGenerator(testConfiguration, testStructure) {

    override fun nextExecution(): List<List<Actor>> {
        val parallelGroup = ArrayList(testStructure.actorGenerators)
        val actorsPerThread = ArrayList<MutableList<Actor>>()
        for (i in testConfiguration.threadConfigurations.indices) {
            actorsPerThread.add(ArrayList())
        }


        actorsPerThread[0].add(actorMethod(parallelGroup, "receive1"))
        actorsPerThread[0].add(actorMethod(parallelGroup, "receive2"))
        actorsPerThread[0].add(actorMethod(parallelGroup, "close1"))

        actorsPerThread[1].add(actorMethod(parallelGroup, "send2"))
        actorsPerThread[1].add(actorMethod(parallelGroup, "send1"))

        return actorsPerThread
    }
}