/*
 * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package kotlin.jvm.optionals

import java.util.Optional
import kotlin.contracts.*

/**
 * Returns this [Optional]'s value if [present][Optional.isPresent], or otherwise `null`.
 *
 * @sample samples.optionals.Optionals.getOrNull
 */
@SinceKotlin("1.8")
@WasExperimental(ExperimentalStdlibApi::class)
public fun <T : Any> Optional<T>.getOrNull(): T? = orElse(null)

/**
 * Returns this [Optional]'s value if [present][Optional.isPresent], or otherwise [defaultValue].
 *
 * @sample samples.optionals.Optionals.getOrDefault
 */
@SinceKotlin("1.8")
@WasExperimental(ExperimentalStdlibApi::class)
public fun <T> Optional<out T & Any>.getOrDefault(defaultValue: T): T = if (isPresent) get() else defaultValue

/**
 * Returns this [Optional]'s value if [present][Optional.isPresent], or otherwise the result of the [defaultValue] function.
 *
 * @sample samples.optionals.Optionals.getOrElse
 */
@SinceKotlin("1.8")
@WasExperimental(ExperimentalStdlibApi::class)
public inline fun <T> Optional<out T & Any>.getOrElse(defaultValue: () -> T): T {
    contract {
        callsInPlace(defaultValue, InvocationKind.AT_MOST_ONCE)
    }
    return if (isPresent) get() else defaultValue()
}

/**
 * Appends this [Optional]'s value to the given [destination] collection if [present][Optional.isPresent].
 *
 * @sample samples.optionals.Optionals.toCollection
 */
@SinceKotlin("1.8")
@WasExperimental(ExperimentalStdlibApi::class)
public fun <T : Any, C : MutableCollection<in T>> Optional<T>.toCollection(destination: C): C {
    if (isPresent) {
        destination.add(get())
    }
    return destination
}

/**
 * Returns a new read-only list of this [Optional]'s value if [present][Optional.isPresent], or otherwise an empty list.
 * The returned list is serializable (JVM).
 *
 * @sample samples.optionals.Optionals.toList
 */
@SinceKotlin("1.8")
@WasExperimental(ExperimentalStdlibApi::class)
public fun <T : Any> Optional<out T>.toList(): List<T> =
    if (isPresent) listOf(get()) else emptyList()

/**
 * Returns a new read-only set of this [Optional]'s value if [present][Optional.isPresent], or otherwise an empty set.
 * The returned set is serializable (JVM).
 *
 * @sample samples.optionals.Optionals.toSet
 */
@SinceKotlin("1.8")
@WasExperimental(ExperimentalStdlibApi::class)
public fun <T : Any> Optional<out T>.toSet(): Set<T> =
    if (isPresent) setOf(get()) else emptySet()

/**
 * Returns a new sequence for this [Optional]'s value if [present][Optional.isPresent], or otherwise an empty sequence.
 *
 * @sample samples.optionals.Optionals.asSequence
 */
@SinceKotlin("1.8")
@WasExperimental(ExperimentalStdlibApi::class)
public fun <T : Any> Optional<out T>.asSequence(): Sequence<T> =
    if (isPresent) sequenceOf(get()) else emptySequence()
