All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.jetbrains.datalore.base.observable.property.Properties.kt Maven / Gradle / Ivy

There is a newer version: 4.5.3-alpha1
Show newest version
/*
 * Copyright (c) 2019. JetBrains s.r.o.
 * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
 */

package jetbrains.datalore.base.observable.property

import jetbrains.datalore.base.function.Predicate
import jetbrains.datalore.base.function.Runnable
import jetbrains.datalore.base.function.Supplier
import jetbrains.datalore.base.function.Value
import jetbrains.datalore.base.observable.collections.CollectionAdapter
import jetbrains.datalore.base.observable.collections.CollectionItemEvent
import jetbrains.datalore.base.observable.collections.ObservableCollection
import jetbrains.datalore.base.observable.event.EventHandler
import jetbrains.datalore.base.observable.event.EventSource
import jetbrains.datalore.base.registration.Registration
import kotlin.jvm.JvmOverloads

object Properties {
    val TRUE = constant(true)
    val FALSE = constant(false)

    fun not(prop: ReadableProperty): ReadableProperty {
        return map(prop) { value -> if (value == null) null else !value }
    }

    fun  notNull(prop: ReadableProperty): ReadableProperty {
        return map(prop) { value -> value != null }
    }

    fun  isNull(prop: ReadableProperty): ReadableProperty {
        return map(prop) { value -> value == null }
    }

    fun startsWith(string: ReadableProperty, prefix: ReadableProperty): ReadableProperty {

        return object : DerivedProperty(false, string, prefix) {
            override val propExpr: String
                get() = "startsWith(" + string.propExpr + ", " + prefix.propExpr + ")"

            override fun doGet(): Boolean {
                if (string.get() == null) return false
                return if (prefix.get() == null) false else string.get()!!.startsWith(prefix.get()!!)
            }
        }
    }

    fun isNullOrEmpty(prop: ReadableProperty): ReadableProperty {
        return object : DerivedProperty(false, prop) {

            override val propExpr: String
                get() = "isEmptyString(" + prop.propExpr + ")"

            override fun doGet(): Boolean {
                val `val` = prop.get()
                return `val` == null || `val`.isEmpty()
            }
        }
    }

    fun and(op1: ReadableProperty, op2: ReadableProperty): ReadableProperty {
        return object : DerivedProperty(null, op1, op2) {

            override val propExpr: String
                get() = "(" + op1.propExpr + " && " + op2.propExpr + ")"

            override fun doGet(): Boolean? {
                return and(op1.get(), op2.get())
            }
        }
    }

    private fun and(b1: Boolean?, b2: Boolean?): Boolean? {
        if (b1 == null) {
            return andWithNull(b2)
        }
        return if (b2 == null) {
            andWithNull(b1)
        } else b1 && b2
    }

    private fun andWithNull(b: Boolean?): Boolean? {
        return if (b == null || b) {
            null
        } else false
    }

    fun or(op1: ReadableProperty, op2: ReadableProperty): ReadableProperty {
        return object : DerivedProperty(null, op1, op2) {

            override val propExpr: String
                get() = "(" + op1.propExpr + " || " + op2.propExpr + ")"

            override fun doGet(): Boolean? {
                return or(op1.get(), op2.get())
            }
        }
    }

    private fun or(b1: Boolean?, b2: Boolean?): Boolean? {
        if (b1 == null) {
            return orWithNull(b2)
        }
        return if (b2 == null) {
            orWithNull(b1)
        } else b1 || b2
    }

    private fun orWithNull(b: Boolean?): Boolean? {
        return if (b == null || !b) {
            null
        } else true
//        return !(b == null || !b)
    }

    fun add(p1: ReadableProperty, p2: ReadableProperty): ReadableProperty {
        return object : DerivedProperty(null, p1, p2) {

            override val propExpr: String
                get() = "(" + p1.propExpr + " + " + p2.propExpr + ")"

            override fun doGet(): Int? {
                return if (p1.get() == null || p2.get() == null) null else p1.get()!! + p2.get()!!
            }
        }
    }

    fun  select(
            source: ReadableProperty, `fun`: (SourceT?) -> ReadableProperty): ReadableProperty {
        return select(source, `fun`, null)
    }

    fun  select(
            source: ReadableProperty, `fun`: (SourceT?) -> ReadableProperty,
            nullValue: TargetT?
    ): ReadableProperty {

        val calc = object : Supplier {
            override fun get(): TargetT? {
                val value = source.get() ?: return nullValue
                val prop = `fun`(value)
                return prop.get()
            }
        }

        return object : BaseDerivedProperty(null) {
            //        return object : BaseDerivedProperty() {
            private var myTargetProperty: ReadableProperty? = null

            private var mySourceRegistration: Registration? = null
            private var myTargetRegistration: Registration? = null

            override val propExpr: String
                get() = "select(" + source.propExpr + ", " + `fun` + ")"

            override fun doAddListeners() {
                myTargetProperty = if (source.get() == null) null else `fun`(source.get())

                val targetHandler = object : EventHandler> {
                    override fun onEvent(event: PropertyChangeEvent) {
                        somethingChanged()
                    }
                }
                val sourceHandler = object : EventHandler> {
                    override fun onEvent(event: PropertyChangeEvent) {
                        if (myTargetProperty != null) {
                            myTargetRegistration!!.remove()
                        }
                        val sourceValue = source.get()
                        if (sourceValue != null) {
                            myTargetProperty = `fun`(sourceValue)
                        } else {
                            myTargetProperty = null
                        }
                        if (myTargetProperty != null) {
                            myTargetRegistration = myTargetProperty!!.addHandler(targetHandler)
                        }
                        somethingChanged()
                    }
                }
                mySourceRegistration = source.addHandler(sourceHandler)
                if (myTargetProperty != null) {
                    myTargetRegistration = myTargetProperty!!.addHandler(targetHandler)
                }
            }

            override fun doRemoveListeners() {
                if (myTargetProperty != null) {
                    myTargetRegistration!!.remove()
                }
                mySourceRegistration!!.remove()
            }

            override fun doGet(): TargetT? {
                return calc.get()
            }
        }
    }

    fun  selectRw(
            source: ReadableProperty, `fun`: (SourceT) -> Property): Property {
        val calc = object : Supplier {
            override fun get(): TargetT? {
                val value = source.get() ?: return null
                val prop = `fun`(value)
                return prop.get()
            }
        }

        class MyProperty : BaseDerivedProperty(calc.get()), Property {
            //        class MyProperty : BaseDerivedProperty(), Property {
            private var myTargetProperty: Property? = null

            private var mySourceRegistration: Registration? = null
            private var myTargetRegistration: Registration? = null

            override val propExpr: String
                get() = "select(" + source.propExpr + ", " + `fun` + ")"

            override fun doAddListeners() {
                myTargetProperty = if (source.get() == null) null else `fun`(source.get())

                val targetHandler = object : EventHandler> {
                    override fun onEvent(event: PropertyChangeEvent) {
                        somethingChanged()
                    }
                }
                val sourceHandler = object : EventHandler> {
                    override fun onEvent(event: PropertyChangeEvent) {
                        if (myTargetProperty != null) {
                            myTargetRegistration!!.remove()
                        }
                        val sourceValue = source.get()
                        if (sourceValue != null) {
                            myTargetProperty = `fun`(sourceValue)
                        } else {
                            myTargetProperty = null
                        }
                        if (myTargetProperty != null) {
                            myTargetRegistration = myTargetProperty!!.addHandler(targetHandler)
                        }
                        somethingChanged()
                    }
                }
                mySourceRegistration = source.addHandler(sourceHandler)
                if (myTargetProperty != null) {
                    myTargetRegistration = myTargetProperty!!.addHandler(targetHandler)
                }
            }

            override fun doRemoveListeners() {
                if (myTargetProperty != null) {
                    myTargetRegistration!!.remove()
                }
                mySourceRegistration!!.remove()
            }

            override fun doGet(): TargetT? {
                return calc.get()
            }

            override fun set(value: TargetT?) {
                if (myTargetProperty == null) return
                myTargetProperty!!.set(value)
            }
        }

        return MyProperty()
    }

    fun  selectEvent(
            prop: ReadableProperty, selector: (ValueT) -> EventSource): EventSource {
        return object : EventSource {
            override fun addHandler(handler: EventHandler): Registration {
                val esReg = Value(Registration.EMPTY)

                val update = object : Runnable {
                    override fun run() {
                        esReg.get().remove()
                        if (prop.get() != null) {
                            esReg.set(selector(prop.get()).addHandler(handler))
                        } else {
                            esReg.set(Registration.EMPTY)
                        }
                    }
                }

                update.run()

                val propReg = prop.addHandler(object : EventHandler> {
                    override fun onEvent(event: PropertyChangeEvent) {
                        update.run()
                    }
                })

                return object : Registration() {
                    override fun doRemove() {
                        propReg.remove()
                        esReg.get().remove()
                    }
                }
            }
        }
    }

    fun  same(prop: ReadableProperty, v: ValueT?): ReadableProperty {
        return map(prop) { value -> value === v }
    }

    fun  equals(prop: ReadableProperty, v: ValueT?): ReadableProperty {
        return map(prop) { value -> value == v }
    }

    fun  equals(p1: ReadableProperty, p2: ReadableProperty): ReadableProperty {
        return object : DerivedProperty(false, p1, p2) {

            override val propExpr: String
                get() = "equals(" + p1.propExpr + ", " + p2.propExpr + ")"

            override fun doGet(): Boolean {
                return p1.get() == p2.get()
            }
        }
    }

    fun  notEquals(prop: ReadableProperty, value: ValueT?): ReadableProperty {
        return not(equals(prop, value))
    }

    fun  notEquals(p1: ReadableProperty, p2: ReadableProperty): ReadableProperty {
        return not(equals(p1, p2))
    }

    fun  map(
            prop: ReadableProperty, f: (SourceT) -> TargetT): ReadableProperty {
        return object : DerivedProperty(f(prop.get()), prop) {

            override val propExpr: String
                get() = "transform(" + prop.propExpr + ", " + f + ")"

            override fun doGet(): TargetT {
                return f(prop.get())
            }
        }
    }

    fun  map(
            prop: Property, sToT: (SourceT?) -> TargetT,
            tToS: (TargetT) -> SourceT
    ): Property {
        class TransformedProperty : Property {

            override val propExpr: String
                get() = "transform(" + prop.propExpr + ", " + sToT + ", " + tToS + ")"

            override fun get(): TargetT {
                return sToT(prop.get())
            }

            override fun addHandler(handler: EventHandler>): Registration {
                return prop.addHandler(object : EventHandler> {
                    override fun onEvent(event: PropertyChangeEvent) {
                        val oldValue = sToT(event.oldValue)
                        val newValue = sToT(event.newValue)

                        if (oldValue == newValue) return

                        handler.onEvent(PropertyChangeEvent(oldValue, newValue))
                    }
                })
            }

            override fun set(value: TargetT) {
                prop.set(tToS(value))
            }
        }

        return TransformedProperty()
    }

    fun  constant(value: ValueT): ReadableProperty {
        return object : BaseReadableProperty() {
            override val propExpr: String
                get() = "constant($value)"

            override fun get(): ValueT {
                return value
            }

            override fun addHandler(handler: EventHandler>): Registration {
                return Registration.EMPTY
            }
        }
    }

    fun  isEmpty(collection: ObservableCollection): ReadableProperty {
        return object : SimpleCollectionProperty(collection, collection.isEmpty()) {
//        return object : SimpleCollectionProperty(collection) {

            override val propExpr: String
                get() = "isEmpty($collection)"

            override fun doGet(): Boolean {
                return collection.isEmpty()
            }
        }
    }

    fun  size(collection: ObservableCollection): ReadableProperty {
        return object : SimpleCollectionProperty(collection, collection.size) {

            override val propExpr: String
                get() = "size($collection)"

            override fun doGet(): Int {
                return collection.size
            }
        }
    }

/*
    fun  indexOf(
            collection: ObservableList,
            item: ReadableProperty): ReadableProperty {
        return simplePropertyWithCollection(collection, item, object : Supplier {
            override fun get(): Int {
                return collection.indexOf(item.get())
            }
        })
    }

    fun  contains(
            collection: ObservableCollection,
            item: ReadableProperty): ReadableProperty {
        return simplePropertyWithCollection(collection, item, object : Supplier {
            override fun get(): Boolean {
                return collection.contains(item.get())
            }
        })
    }
*/

/*
    fun  simplePropertyWithCollection(
            collection: ObservableCollection<*>,
            item: ReadableProperty<*>,
            supplier: Supplier): ReadableProperty {

//        return object : BaseDerivedProperty(supplier.get()) {
        return object : BaseDerivedProperty() {
            private var myRegistration: Registration? = null
            private var myCollectionRegistration: Registration? = null

            override val propExpr: String
                get() = "fromCollection($collection, $item, $supplier)"

            override fun doGet(): T {
                return supplier.get()
            }

            override fun doAddListeners() {
                myRegistration = item.addHandler(object : EventHandler> {
                    override fun onEvent(event: PropertyChangeEvent<*>) {
                        somethingChanged()
                    }
                })
                myCollectionRegistration = collection.addListener(Properties.simpleAdapter(object : Runnable {
                    override fun run() {
                        somethingChanged()
                    }
                }))
            }

            protected override fun doRemoveListeners() {
                myRegistration!!.remove()
                myCollectionRegistration!!.remove()
            }
        }
    }
*/

    fun  notEmpty(collection: ObservableCollection): ReadableProperty {
        return not(empty(collection) as ReadableProperty)
    }

    fun  empty(collection: ObservableCollection): ReadableProperty {
        return object : BaseDerivedProperty(collection.isEmpty()) {
            //        return object : BaseDerivedProperty() {
            private var myCollectionRegistration: Registration? = null

            override val propExpr: String
                get() = "empty($collection)"

            override fun doAddListeners() {
                myCollectionRegistration = collection.addListener(simpleAdapter(object : Runnable {
                    override fun run() {
                        somethingChanged()
                    }
                }))
            }

            override fun doRemoveListeners() {
                myCollectionRegistration!!.remove()
            }

            override fun doGet(): Boolean {
                return collection.isEmpty()
            }
        }
    }

    private fun  simpleAdapter(r: Runnable): CollectionAdapter {
        return object : CollectionAdapter() {
            override fun onItemAdded(event: CollectionItemEvent) {
                r.run()
            }

            override fun onItemRemoved(event: CollectionItemEvent) {
                r.run()
            }
        }
    }

    fun  ifProp(
            cond: ReadableProperty, ifTrue: ReadableProperty, ifFalse: ReadableProperty): ReadableProperty {
        return object : DerivedProperty(null, cond, ifTrue, ifFalse) {

            override val propExpr: String
                get() = "if(" + cond.propExpr + ", " + ifTrue.propExpr + ", " + ifFalse.propExpr + ")"

            override fun doGet(): ValueT {
                return if (cond.get()) ifTrue.get() else ifFalse.get()
            }
        }
    }

    fun  ifProp(cond: ReadableProperty, ifTrue: ValueT, ifFalse: ValueT): ReadableProperty {
        return ifProp(cond, constant(ifTrue), constant(ifFalse))
    }

    fun  ifProp(cond: WritableProperty, ifTrue: ValueT, ifFalse: ValueT): WritableProperty {
        return object : WritableProperty {
            override fun set(value: Boolean) {
                if (value) {
                    cond.set(ifTrue)
                } else {
                    cond.set(ifFalse)
                }
            }
        }
    }

    fun  withDefaultValue(prop: ReadableProperty, ifNull: ValueT): ReadableProperty {
        return object : DerivedProperty(ifNull, prop) {
            override fun doGet(): ValueT {
                return if (prop.get() == null) {
                    ifNull
                } else {
                    prop.get()
                }
            }
        }
    }

    fun  firstNotNull(vararg values: ReadableProperty): ReadableProperty {
        return object : DerivedProperty(null, *values) {

            override val propExpr: String
                get() {
                    val result = StringBuilder()
                    result.append("firstNotNull(")

                    var first = true
                    for (v in values) {
                        if (first) {
                            first = false
                        } else {
                            result.append(", ")
                        }
                        result.append(v.propExpr)
                    }
                    result.append(")")
                    return result.toString()
                }

            override fun doGet(): ValueT? {
                for (v in values) {
                    if (v.get() != null) {
                        return v.get()
                    }
                }
                return null
            }
        }
    }

    fun  isPropertyValid(source: ReadableProperty, validator: Predicate): ReadableProperty {
        return object : DerivedProperty(false, source) {

            override val propExpr: String
                get() = "isValid(" + source.propExpr + ", " + validator + ")"

            override fun doGet(): Boolean {
                return validator(source.get())
            }
        }
    }

    fun  validatedProperty(source: Property, validator: Predicate): Property {

        class ValidatedProperty : DerivedProperty(null, source), Property {
            private var myLastValid: ValueT? = null

            override val propExpr: String
                get() = "validated(" + source.propExpr + ", " + validator + ")"

            override fun doGet(): ValueT? {
                val sourceValue = source.get()
                if (validator(sourceValue)) {
                    myLastValid = sourceValue
                }
                return myLastValid
            }

            override fun set(value: ValueT?) {
                if (!validator(value)) {
                    return
                }
                source.set(value)
            }
        }

        return ValidatedProperty()
    }

    @JvmOverloads
    fun toStringOf(p: ReadableProperty<*>, nullValue: String = "null"): ReadableProperty {
        return object : DerivedProperty(nullValue, p) {
            override fun doGet(): String {
                val value = p.get()
                return if (value != null) "" + value else nullValue
            }
        }
    }

    fun  property(read: ReadableProperty, write: WritableProperty): Property {
        return object : Property {
            override val propExpr: String
                get() = read.propExpr

            override fun get(): ValueT {
                return read.get()
            }

            override fun addHandler(handler: EventHandler>): Registration {
                return read.addHandler(handler)
            }

            override fun set(value: ValueT) {
                write.set(value)
            }
        }
    }

    fun  compose(vararg props: WritableProperty): WritableProperty {
        return object : WritableProperty {
            override fun set(value: ValueT) {
                for (wp in props) {
                    wp.set(value)
                }
            }
        }
    }


    fun  forSingleItemCollection(coll: ObservableCollection): Property {
        if (coll.size > 1) {
            throw IllegalStateException("Collection $coll has more than one item")
        }

        return object : Property {

            override val propExpr: String
                get() = "singleItemCollection($coll)"

            override fun get(): ItemT? {
                return if (coll.isEmpty()) {
                    null
                } else coll.iterator().next()
            }

            override fun set(value: ItemT?) {
                val current = get()
                if (current == value) return
                coll.clear()
                if (value != null) {
                    coll.add(value)
                }
            }

            override fun addHandler(handler: EventHandler>): Registration {
                return coll.addListener(object : CollectionAdapter() {
                    override fun onItemAdded(event: CollectionItemEvent) {
                        if (coll.size != 1) {
                            throw IllegalStateException()
                        }
                        handler.onEvent(PropertyChangeEvent(null, event.newItem))
                    }

                    override fun onItemSet(event: CollectionItemEvent) {
                        if (event.index != 0) {
                            throw IllegalStateException()
                        }
                        handler.onEvent(PropertyChangeEvent(event.oldItem, event.newItem))
                    }

                    override fun onItemRemoved(event: CollectionItemEvent) {
                        if (!coll.isEmpty()) {
                            throw IllegalStateException()
                        }
                        handler.onEvent(PropertyChangeEvent(event.oldItem, null))
                    }
                })
            }
        }
    }

    fun and(vararg props: ReadableProperty): ReadableProperty {
        if (props.isEmpty()) {
            throw IllegalArgumentException("No arguments")
        }
        return object : DerivedProperty(null, *props) {

            override val propExpr: String
                get() {
                    val propExpr = StringBuilder("(")
                    propExpr.append(props[0].propExpr)
                    for (i in 1 until props.size) {
                        propExpr.append(" && ").append(props[i].propExpr)
                    }
                    return propExpr.append(")").toString()
                }

            override fun doGet(): Boolean? {
                var res: Boolean? = true
                for (prop in props) {
                    res = and(res, prop.get())
                }
                return res
            }
        }
    }

    fun or(vararg props: ReadableProperty): ReadableProperty {
        if (props.isEmpty()) {
            throw IllegalArgumentException("No arguments")
        }
        return object : DerivedProperty(null, *props) {

            override val propExpr: String
                get() {
                    val propExpr = StringBuilder("(")
                    propExpr.append(props[0].propExpr)
                    for (i in 1 until props.size) {
                        propExpr.append(" || ").append(props[i].propExpr)
                    }
                    return propExpr.append(")").toString()
                }

            override fun doGet(): Boolean? {
                var res: Boolean? = false
                for (prop in props) {
                    res = or(res, prop.get())
                }
                return res
            }
        }
    }

/*
    fun > enumAsInteger(source: Property, enumClass: KClass): Property {
        return property(map(source) { value -> value.ordinal },
                object : WritableProperty {
                    override fun set(value: Int?) {
                        if (value == null) {
                            source.set(null)
                            return
                        }
                        source.set(enumClass.getEnumConstants()[value])
                    }
                })
    }
*/
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy