<commit_before>package org.reekwest.http.contract.module

import org.reekwest.http.core.HttpHandler
import org.reekwest.http.core.Method
import org.reekwest.http.core.Request
import org.reekwest.http.core.then
import org.reekwest.http.lens.LensFailure
import org.reekwest.http.lens.Path
import org.reekwest.http.lens.PathLens

class ServerRoute internal constructor(internal val pathBinder: PathBinder, private val toHandler: (ExtractedParts) -> HttpHandler) {
    fun router(moduleRoot: BasePath): Router = pathBinder.toRouter(moduleRoot, toHandler)

    fun describeFor(moduleRoot: BasePath): String = pathBinder.describe(moduleRoot)
}

abstract class PathBinder internal constructor(internal val core: Core, private vararg val pathLenses: PathLens<*>) {
    abstract infix operator fun <T> div(next: PathLens<T>): PathBinder

    open infix operator fun div(next: String) = div(Path.fixed(next))

    internal fun toRouter(moduleRoot: BasePath, toHandler: (ExtractedParts) -> HttpHandler): Router =
        {
            if (core.matches(moduleRoot, it)) {
                try {
                    it.without(core.pathFn(moduleRoot)).extract(pathLenses.toList())?.let { core.route.validationFilter.then(toHandler(it)) }
                } catch (e: LensFailure) {
                    null
                }
            } else null
        }

    fun describe(moduleRoot: BasePath): String = "${core.pathFn(moduleRoot)}/${pathLenses.joinToString("/")}"

    companion object {
        internal data class Core(val route: Route, val method: Method, val pathFn: (BasePath) -> BasePath) {
            infix operator fun div(next: String) = copy(pathFn = { pathFn(it) / next })
            fun matches(moduleRoot: BasePath, request: Request) =
                request.method == method && request.basePath().startsWith(pathFn(moduleRoot))
        }
    }
}

class PathBinder0 internal constructor(core: Core) : PathBinder(core) {

    override infix operator fun div(next: String) = PathBinder0(core / next)

    override infix operator fun <T> div(next: PathLens<T>) = PathBinder1(core, next)

    infix fun bind(handler: HttpHandler) = ServerRoute(this, { handler })
}

class PathBinder1<out A> internal constructor(core: Core,
                                              private val psA: PathLens<A>) : PathBinder(core, psA) {

    override infix operator fun div(next: String) = div(Path.fixed(next))

    override infix operator fun <T> div(next: PathLens<T>) = PathBinder2(core, psA, next)

    infix fun bind(fn: (A) -> HttpHandler) = ServerRoute(this, { parts -> fn(parts[psA]) })
}

class PathBinder2<out A, out B> internal constructor(core: Core,
                                                     private val psA: PathLens<A>,
                                                     private val psB: PathLens<B>) : PathBinder(core, psA, psB) {
    override infix operator fun div(next: String) = div(Path.fixed(next))

    override fun <T> div(next: PathLens<T>) = PathBinder3(core, psA, psB, next)<commit_msg>refactor pathbinder<commit_after>package org.reekwest.http.contract.module

import org.reekwest.http.core.HttpHandler
import org.reekwest.http.core.Method
import org.reekwest.http.core.Request
import org.reekwest.http.core.then
import org.reekwest.http.lens.LensFailure
import org.reekwest.http.lens.Path
import org.reekwest.http.lens.PathLens

class ServerRoute internal constructor(internal val pathBinder: PathBinder, private val toHandler: (ExtractedParts) -> HttpHandler) {
    fun router(moduleRoot: BasePath): Router = pathBinder.toRouter(moduleRoot, toHandler)

    fun describeFor(moduleRoot: BasePath): String = pathBinder.describe(moduleRoot)
}

abstract class PathBinder internal constructor(internal val core: Core, private vararg val pathLenses: PathLens<*>) {
    abstract infix operator fun <T> div(next: PathLens<T>): PathBinder

    open infix operator fun div(next: String) = div(Path.fixed(next))

    internal fun toRouter(moduleRoot: BasePath, toHandler: (ExtractedParts) -> HttpHandler): Router =
        {
            core.matches(moduleRoot, it, pathLenses.toList(), toHandler)
        }

    fun describe(moduleRoot: BasePath): String = "${core.pathFn(moduleRoot)}/${pathLenses.joinToString("/")}"

    companion object {
        internal data class Core(val route: Route, val method: Method, val pathFn: (BasePath) -> BasePath) {
            infix operator fun div(next: String) = copy(pathFn = { pathFn(it) / next })

            fun matches(moduleRoot: BasePath, request: Request, lenses: List<PathLens<*>>, toHandler: (ExtractedParts) -> HttpHandler): HttpHandler? =
                if (request.method == method && request.basePath().startsWith(pathFn(moduleRoot))) {
                    try {
                        request.without(pathFn(moduleRoot)).extract(lenses)?.let { route.validationFilter.then(toHandler(it)) }
                    } catch (e: LensFailure) {
                        null
                    }
                } else null
        }

    }
}

class PathBinder0 internal constructor(core: Core) : PathBinder(core) {

    override infix operator fun div(next: String) = PathBinder0(core / next)

    override infix operator fun <T> div(next: PathLens<T>) = PathBinder1(core, next)

    infix fun bind(handler: HttpHandler) = ServerRoute(this, { handler })
}

class PathBinder1<out A> internal constructor(core: Core,
                                              private val psA: PathLens<A>) : PathBinder(core, psA) {

    override infix operator fun div(next: String) = div(Path.fixed(next))

    override infix operator fun <T> div(next: PathLens<T>) = PathBinder2(core, psA, next)

    infix fun bind(fn: (A) -> HttpHandler) = ServerRoute(this, { parts -> fn(parts[psA]) })
}

class PathBinder2<out A, out B> internal constructor(core: Core,
                                                     private val psA: PathLens<A>,
                                                     private val psB: PathLens<B>) : PathBinder(core, psA, psB) {
    override infix operator fun div(next: String) = div(Path.fixed(next))

    override fun <T> div(next: PathLens<T>) = PathBinder3(core, psA, psB, next)
{'fraction_non_alphanumeric': 0.11330847787323715, 'fraction_numerical': 0.0022694115739990274, 'mean_word_length': 2.975515463917526, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5656091', 'n_tokens_mistral': 1821, 'n_tokens_neox': 1778, 'n_words': 456}