<commit_before>package tornadofx

import javafx.application.Platform
import javafx.collections.FXCollections
import javafx.collections.ListChangeListener
import javafx.collections.ObservableList
import javafx.scene.control.ProgressBar.INDETERMINATE_PROGRESS
import javafx.scene.control.Tooltip
import org.apache.http.HttpHost
import org.apache.http.auth.AuthScope
import org.apache.http.auth.UsernamePasswordCredentials
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods.*
import org.apache.http.client.protocol.HttpClientContext
import org.apache.http.entity.InputStreamEntity
import org.apache.http.entity.StringEntity
import org.apache.http.impl.auth.BasicScheme
import org.apache.http.impl.client.*
import org.apache.http.util.EntityUtils
import tornadofx.Rest.Request.Method.*
import java.io.Closeable
import java.io.InputStream
import java.io.StringReader
import java.net.*
import java.nio.charset.StandardCharsets.UTF_8
import java.util.*
import java.util.concurrent.atomic.AtomicLong
import java.util.zip.DeflaterInputStream
import java.util.zip.GZIPInputStream
import javax.json.Json
import javax.json.JsonArray
import javax.json.JsonObject
import javax.json.JsonValue

open class Rest : Controller() {
    companion object {
        var engineProvider: (Rest) -> Engine = ::HttpURLEngine
        val ongoingRequests = FXCollections.observableArrayList<Request>()
        val atomicseq = AtomicLong()

        fun useApacheHttpClient() {
            engineProvider = ::HttpClientEngine
        }
    }

    var engine = engineProvider(this)
    var baseURI: String? = null
    var proxy: Proxy? = null

    fun setBasicAuth(username: String, password: String) = engine.setBasicAuth(username, password)
    fun reset() = engine.reset()

    fun get(path: String, data: JsonValue? = null, processor: ((Request) -> Unit)? = null) = execute(GET, path, data, processor)
    fun get(path: String, data: JsonModel, processor: ((Request) -> Unit)? = null) = get(path, JsonBuilder().apply { data.toJSON(this) }.build(), processor)

    fun put(path: String, data: JsonValue? = null, processor: ((Request) -> Unit)? = null) = execute(PUT, path, data, processor)
    fun put(path: String, data: JsonModel, processor: ((Request) -> Unit)? = null) = put(path, JsonBuilder().apply { data.toJSON(this) }.build(), processor)

    fun post(path: String, data: JsonValue? = null, processor: ((Request) -> Unit)? = null) = execute(POST, path, data, processor)
    fun post(path: String, data: JsonModel, processor: ((Request) -> Unit)? = null) = post(path, JsonBuilder().apply { data.toJSON(this) }.build(), processor)
    fun post(path: String, data: InputStream, processor: ((Request) -> Unit)? = null) = execute(POST, path, data, processor)

    fun delete(path: String, data: JsonValue? = null, processor: ((Request) -> Unit)? = null) = execute(DELETE, path, data, processor)
    fun delete(path: String, data: JsonModel, processor: ((Request) -> Unit)? = null) = delete(path, JsonBuilder().apply { data.toJSON(this) }.build(), processor)

    fun getURI(path: String): URI {
        try {
            val asURI = URI.create(path.replace(" ", "%20"))
            if (asURI.isAbsolute) return asURI

            val uri = StringBuilder()

            if (baseURI != null)
                uri.append(baseURI)

            if (uri.toString().endsWith("/") && path.startsWith("/"))
                uri.append(path.substring(1))
            else if (!uri.toString().endsWith("/") && !path.startsWith("/"))
                uri.append("/").append(path)
            else
                uri.append(path)

            return URI(uri.toString().replace(" ", "%20"))
        } catch (ex: URISyntaxException) {
            throw RuntimeException(ex)
        }

    }

    fun execute(method: Request.Method, target: String, data: Any? = null, processor: ((Request) -> Unit)? = null): Response {
        val request = engine.request(atomicseq.addAndGet(1), method, getURI(target), data)

        if (processor != null)
            processor(request)

        Platform.runLater { ongoingRequests.add(request) }
        return request.execute()
    }

    abstract class Engine {
        var authInterceptor: ((Request) -> Unit)? = null
        var responseInterceptor: ((Response) -> Unit)? = null
        abstract fun request(seq: Long, method: Request.Method, uri: URI, entity: Any? = null): Request
        abstract fun setBasicAuth(username: String, password: String)
        abstract fun reset()
    }

    interface Request {
        enum class Method { GET, PUT, POST, DELETE }

        val seq: Long
        val method: Method
        val uri: URI
        val entity: Any?
        fun addHeader(name: String, value: String)
        fun execute(): Response
    }

    interface Response : Closeable {
        val request: Request
        val statusCode: Int
        val reason: String
        fun text(): String?
        fun consume(): Response
        fun list(): JsonArray {
            try {
                val content = text()

                if (content == null || content.isEmpty())
                    return Json.createArrayBuilder().build()

                val json = Json.createReader(StringReader(content)).use { it.read() }

                return when (json) {
                    is JsonArray -> json
                    is JsonObject -> Json.createArrayBuilder().add(json).build()
                    else -> throw IllegalArgumentException("Unknown json result value")
                }
            } finally {
                consume()
            }
        }

        fun one(): JsonObject {
            try {
                val content = text()

                if (content == null || content.isEmpty())
                    return Json.createObjectBuilder().build()

                val json = Json.createReader(StringReader(content)).use { it.read() }

                return when (json) {
                    is JsonArray -> {
                        if (json.isEmpty())
                            return Json.createObjectBuilder().build()
                        else
                            return json.getJsonObject(0)
                    }
                    is JsonObject -> json
                    else -> throw IllegalArgumentException("Unknown json result value")
                }
            } finally {
                consume()
            }
        }

        fun content(): InputStream
        fun bytes(): ByteArray
        fun ok() = statusCode == 200
    }
}

class HttpURLEngine(val rest: Rest) : Rest.Engine() {
    override fun setBasicAuth(username: String, password: String) {
        authInterceptor = { engine ->
            val b64 = Base64.getEncoder().encodeToString("$username:$password".toByteArray(UTF_8))
            engine.addHeader("Authorization", "Basic $b64")
        }
    }

    override fun reset() {
        authInterceptor = null
    }

    override fun request(seq: Long, method: Rest.Request.Method, uri: URI, entity: Any?) =
            HttpURLRequest(this, seq, method, uri, entity)
}

class HttpURLRequest(val engine: HttpURLEngine, override val seq: Long, override val method: Rest.Request.Method, override val uri: URI, override val entity: Any?) : Rest.Request {
    val connection: HttpURLConnection
    val headers = mutableMapOf<String, String>()

    init {
        val url = uri.toURL()
        connection = (if (engine.rest.proxy != null) url.openConnection(engine.rest.proxy) else url.openConnection()) as HttpURLConnection
        headers += "Accept-Encoding" to "gzip, deflate"
        headers += "Content-Type" to "application/json"
        headers += "Accept" to "application/json"
        headers += "User-Agent" to "TornadoFX/Java ${System.getProperty("java.version")}"
        headers += "Connection" to "Keep-Alive"<commit_msg>Renamed setBasicAuth authInterceptor lambda param to request.<commit_after>package tornadofx

import javafx.application.Platform
import javafx.collections.FXCollections
import javafx.collections.ListChangeListener
import javafx.collections.ObservableList
import javafx.scene.control.ProgressBar.INDETERMINATE_PROGRESS
import javafx.scene.control.Tooltip
import org.apache.http.HttpHost
import org.apache.http.auth.AuthScope
import org.apache.http.auth.UsernamePasswordCredentials
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods.*
import org.apache.http.client.protocol.HttpClientContext
import org.apache.http.entity.InputStreamEntity
import org.apache.http.entity.StringEntity
import org.apache.http.impl.auth.BasicScheme
import org.apache.http.impl.client.*
import org.apache.http.util.EntityUtils
import tornadofx.Rest.Request.Method.*
import java.io.Closeable
import java.io.InputStream
import java.io.StringReader
import java.net.*
import java.nio.charset.StandardCharsets.UTF_8
import java.util.*
import java.util.concurrent.atomic.AtomicLong
import java.util.zip.DeflaterInputStream
import java.util.zip.GZIPInputStream
import javax.json.Json
import javax.json.JsonArray
import javax.json.JsonObject
import javax.json.JsonValue

open class Rest : Controller() {
    companion object {
        var engineProvider: (Rest) -> Engine = ::HttpURLEngine
        val ongoingRequests = FXCollections.observableArrayList<Request>()
        val atomicseq = AtomicLong()

        fun useApacheHttpClient() {
            engineProvider = ::HttpClientEngine
        }
    }

    var engine = engineProvider(this)
    var baseURI: String? = null
    var proxy: Proxy? = null

    fun setBasicAuth(username: String, password: String) = engine.setBasicAuth(username, password)
    fun reset() = engine.reset()

    fun get(path: String, data: JsonValue? = null, processor: ((Request) -> Unit)? = null) = execute(GET, path, data, processor)
    fun get(path: String, data: JsonModel, processor: ((Request) -> Unit)? = null) = get(path, JsonBuilder().apply { data.toJSON(this) }.build(), processor)

    fun put(path: String, data: JsonValue? = null, processor: ((Request) -> Unit)? = null) = execute(PUT, path, data, processor)
    fun put(path: String, data: JsonModel, processor: ((Request) -> Unit)? = null) = put(path, JsonBuilder().apply { data.toJSON(this) }.build(), processor)

    fun post(path: String, data: JsonValue? = null, processor: ((Request) -> Unit)? = null) = execute(POST, path, data, processor)
    fun post(path: String, data: JsonModel, processor: ((Request) -> Unit)? = null) = post(path, JsonBuilder().apply { data.toJSON(this) }.build(), processor)
    fun post(path: String, data: InputStream, processor: ((Request) -> Unit)? = null) = execute(POST, path, data, processor)

    fun delete(path: String, data: JsonValue? = null, processor: ((Request) -> Unit)? = null) = execute(DELETE, path, data, processor)
    fun delete(path: String, data: JsonModel, processor: ((Request) -> Unit)? = null) = delete(path, JsonBuilder().apply { data.toJSON(this) }.build(), processor)

    fun getURI(path: String): URI {
        try {
            val asURI = URI.create(path.replace(" ", "%20"))
            if (asURI.isAbsolute) return asURI

            val uri = StringBuilder()

            if (baseURI != null)
                uri.append(baseURI)

            if (uri.toString().endsWith("/") && path.startsWith("/"))
                uri.append(path.substring(1))
            else if (!uri.toString().endsWith("/") && !path.startsWith("/"))
                uri.append("/").append(path)
            else
                uri.append(path)

            return URI(uri.toString().replace(" ", "%20"))
        } catch (ex: URISyntaxException) {
            throw RuntimeException(ex)
        }

    }

    fun execute(method: Request.Method, target: String, data: Any? = null, processor: ((Request) -> Unit)? = null): Response {
        val request = engine.request(atomicseq.addAndGet(1), method, getURI(target), data)

        if (processor != null)
            processor(request)

        Platform.runLater { ongoingRequests.add(request) }
        return request.execute()
    }

    abstract class Engine {
        var authInterceptor: ((Request) -> Unit)? = null
        var responseInterceptor: ((Response) -> Unit)? = null
        abstract fun request(seq: Long, method: Request.Method, uri: URI, entity: Any? = null): Request
        abstract fun setBasicAuth(username: String, password: String)
        abstract fun reset()
    }

    interface Request {
        enum class Method { GET, PUT, POST, DELETE }

        val seq: Long
        val method: Method
        val uri: URI
        val entity: Any?
        fun addHeader(name: String, value: String)
        fun execute(): Response
    }

    interface Response : Closeable {
        val request: Request
        val statusCode: Int
        val reason: String
        fun text(): String?
        fun consume(): Response
        fun list(): JsonArray {
            try {
                val content = text()

                if (content == null || content.isEmpty())
                    return Json.createArrayBuilder().build()

                val json = Json.createReader(StringReader(content)).use { it.read() }

                return when (json) {
                    is JsonArray -> json
                    is JsonObject -> Json.createArrayBuilder().add(json).build()
                    else -> throw IllegalArgumentException("Unknown json result value")
                }
            } finally {
                consume()
            }
        }

        fun one(): JsonObject {
            try {
                val content = text()

                if (content == null || content.isEmpty())
                    return Json.createObjectBuilder().build()

                val json = Json.createReader(StringReader(content)).use { it.read() }

                return when (json) {
                    is JsonArray -> {
                        if (json.isEmpty())
                            return Json.createObjectBuilder().build()
                        else
                            return json.getJsonObject(0)
                    }
                    is JsonObject -> json
                    else -> throw IllegalArgumentException("Unknown json result value")
                }
            } finally {
                consume()
            }
        }

        fun content(): InputStream
        fun bytes(): ByteArray
        fun ok() = statusCode == 200
    }
}

class HttpURLEngine(val rest: Rest) : Rest.Engine() {
    override fun setBasicAuth(username: String, password: String) {
        authInterceptor = { request ->
            val b64 = Base64.getEncoder().encodeToString("$username:$password".toByteArray(UTF_8))
            request.addHeader("Authorization", "Basic $b64")
        }
    }

    override fun reset() {
        authInterceptor = null
    }

    override fun request(seq: Long, method: Rest.Request.Method, uri: URI, entity: Any?) =
            HttpURLRequest(this, seq, method, uri, entity)
}

class HttpURLRequest(val engine: HttpURLEngine, override val seq: Long, override val method: Rest.Request.Method, override val uri: URI, override val entity: Any?) : Rest.Request {
    val connection: HttpURLConnection
    val headers = mutableMapOf<String, String>()

    init {
        val url = uri.toURL()
        connection = (if (engine.rest.proxy != null) url.openConnection(engine.rest.proxy) else url.openConnection()) as HttpURLConnection
        headers += "Accept-Encoding" to "gzip, deflate"
        headers += "Content-Type" to "application/json"
        headers += "Accept" to "application/json"
        headers += "User-Agent" to "TornadoFX/Java ${System.getProperty("java.version")}"
        headers += "Connection" to "Keep-Alive"
{'fraction_non_alphanumeric': 0.11998221544715447, 'fraction_numerical': 0.0022865853658536584, 'mean_word_length': 2.505120213713268, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2207795', 'n_tokens_mistral': 4257, 'n_tokens_neox': 4129, 'n_words': 1133}