2021-02-08 12:39:52 +07:00
|
|
|
package com.cubetiqs.money
|
|
|
|
|
2021-02-08 18:53:46 +07:00
|
|
|
import java.util.*
|
2021-02-08 12:39:52 +07:00
|
|
|
|
2021-02-08 18:53:46 +07:00
|
|
|
/**
|
|
|
|
* Money Object Generator (Quick building the money)
|
|
|
|
*
|
|
|
|
* @since 1.0
|
|
|
|
* @author sombochea
|
|
|
|
*/
|
2021-02-09 09:38:11 +07:00
|
|
|
open class MoneyObject(
|
2021-02-08 21:34:17 +07:00
|
|
|
private var value: Double,
|
|
|
|
private var currency: String,
|
2021-02-08 21:36:34 +07:00
|
|
|
|
|
|
|
// operator, used with "with" below
|
|
|
|
// example: if we have next we will use this operator to compute the value with
|
2021-02-09 09:38:11 +07:00
|
|
|
private var operator: MoneyOperator? = null,
|
2021-02-08 21:36:34 +07:00
|
|
|
// the value to compute with current object
|
2021-02-09 09:38:11 +07:00
|
|
|
private var with: MoneyObject? = null,
|
2021-02-08 18:53:46 +07:00
|
|
|
) : StdMoney {
|
2021-02-08 21:34:17 +07:00
|
|
|
override fun getCurrency(): StdMoney.Currency {
|
2021-02-08 18:53:46 +07:00
|
|
|
return StdMoney.initCurrency(currency)
|
2021-02-08 12:39:52 +07:00
|
|
|
}
|
|
|
|
|
2021-02-08 21:34:17 +07:00
|
|
|
override fun getValue(): Double {
|
2021-02-08 18:53:46 +07:00
|
|
|
return value
|
|
|
|
}
|
2021-02-08 12:39:52 +07:00
|
|
|
|
2021-02-09 09:38:11 +07:00
|
|
|
open fun getOperator(): MoneyOperator? = operator
|
|
|
|
open fun getWith(): MoneyObject? = with
|
|
|
|
|
2021-02-08 21:25:16 +07:00
|
|
|
fun appendWithNext(with: MoneyObject?) {
|
|
|
|
if (with == null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.with == null) {
|
|
|
|
this.with = with
|
|
|
|
} else {
|
|
|
|
this.with!!.appendWithNext(with)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal Generate the value by next compute (First and next)
|
|
|
|
*
|
|
|
|
* Example: we have 3 items => [10, 20, 50]
|
|
|
|
* We want to sum of them => [10 + 20] => [30 + 50] => 80
|
|
|
|
*/
|
2021-02-08 18:53:46 +07:00
|
|
|
private fun generate(): StdMoney {
|
2021-02-08 21:25:16 +07:00
|
|
|
// get next record for compute with
|
|
|
|
var next = this.with
|
|
|
|
// get first operator
|
|
|
|
var operatorFirst = this.operator
|
|
|
|
while (next != null) {
|
|
|
|
val temp = when (operatorFirst) {
|
|
|
|
MoneyOperator.PLUS -> this plusWith next
|
|
|
|
MoneyOperator.MINUS -> this minusWith next
|
|
|
|
MoneyOperator.DIVIDE -> this divideWith next
|
|
|
|
MoneyOperator.MULTIPLY -> this multiplyWith next
|
2021-02-08 18:53:46 +07:00
|
|
|
// if operator is null or empty with default Plus operator
|
2021-02-08 21:25:16 +07:00
|
|
|
else -> this plusWith next
|
2021-02-08 18:53:46 +07:00
|
|
|
}
|
2021-02-08 21:25:16 +07:00
|
|
|
// move the temp value that computed
|
2021-02-08 21:34:17 +07:00
|
|
|
this.value = temp.getValue()
|
2021-02-08 21:25:16 +07:00
|
|
|
// move the currency into parent, if changed
|
2021-02-08 21:34:17 +07:00
|
|
|
this.currency = temp.getCurrency().getCurrency()
|
2021-02-08 21:25:16 +07:00
|
|
|
// move the first operator to previous next operator
|
|
|
|
// example: first ops = +, then next ops = -, then inside next ops = *, n
|
|
|
|
// return next: first ops = -, then next ops = *, then n
|
|
|
|
operatorFirst = next.operator
|
|
|
|
// move next element
|
|
|
|
next = next.with
|
2021-02-08 18:53:46 +07:00
|
|
|
}
|
2021-02-08 12:39:52 +07:00
|
|
|
|
2021-02-08 21:25:16 +07:00
|
|
|
return this
|
2021-02-08 18:53:46 +07:00
|
|
|
}
|
2021-02-08 12:39:52 +07:00
|
|
|
|
2021-02-08 18:53:46 +07:00
|
|
|
fun compute(): StdMoney {
|
|
|
|
return generate()
|
2021-02-08 12:39:52 +07:00
|
|
|
}
|
|
|
|
|
2021-02-08 18:53:46 +07:00
|
|
|
override fun toString(): String {
|
|
|
|
return "MoneyObject(value=$value, currency='$currency', operator=$operator, with=$with)"
|
|
|
|
}
|
|
|
|
|
|
|
|
enum class MoneyOperator {
|
|
|
|
// (+)
|
|
|
|
PLUS,
|
|
|
|
|
|
|
|
// (-)
|
|
|
|
MINUS,
|
|
|
|
|
|
|
|
// (/)
|
|
|
|
DIVIDE,
|
|
|
|
|
|
|
|
// (*)
|
|
|
|
MULTIPLY;
|
|
|
|
|
|
|
|
companion object {
|
2021-02-08 21:25:16 +07:00
|
|
|
fun operator(value: Any?, defaultOperator: MoneyOperator? = null): MoneyOperator {
|
2021-02-08 18:53:46 +07:00
|
|
|
return try {
|
2021-02-08 21:25:16 +07:00
|
|
|
when (val temp = value!!) {
|
|
|
|
is String -> {
|
|
|
|
if (temp.length == 1) {
|
|
|
|
operator(temp[0])
|
|
|
|
} else {
|
|
|
|
valueOf(temp.toUpperCase().trim())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is Char -> {
|
|
|
|
when (temp) {
|
|
|
|
'+' -> PLUS
|
|
|
|
'-' -> MINUS
|
|
|
|
'/' -> DIVIDE
|
|
|
|
'*' -> MULTIPLY
|
|
|
|
else -> throw IllegalArgumentException("operator not found with value: $temp!")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else -> throw IllegalArgumentException("operator not found by value: $value!")
|
2021-02-08 18:53:46 +07:00
|
|
|
}
|
|
|
|
} catch (ex: Exception) {
|
2021-02-08 21:25:16 +07:00
|
|
|
defaultOperator ?: throw IllegalArgumentException("operator not found!")
|
2021-02-08 18:53:46 +07:00
|
|
|
}
|
|
|
|
}
|
2021-02-08 12:39:52 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-08 21:25:16 +07:00
|
|
|
class MoneyObjectBuilder {
|
|
|
|
private val defaultCurrency = MoneyCurrency.USD.getCurrency()
|
|
|
|
|
2021-02-08 18:53:46 +07:00
|
|
|
private var currency: String? = null
|
2021-02-08 21:25:16 +07:00
|
|
|
private val withs: Deque<MoneyObject> = ArrayDeque()
|
2021-02-08 18:53:46 +07:00
|
|
|
|
|
|
|
fun withCurrency(currency: String) = apply {
|
|
|
|
this.currency = currency
|
|
|
|
}
|
|
|
|
|
2021-02-08 21:25:16 +07:00
|
|
|
fun with(value: MoneyObject) = apply {
|
|
|
|
this.withs.add(value)
|
2021-02-08 18:53:46 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
fun with(value: Double, currency: String, operator: MoneyOperator = MoneyOperator.PLUS) = apply {
|
|
|
|
this.with(
|
|
|
|
MoneyObject(
|
|
|
|
value, currency, operator
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fun with(value: Double, currency: String, operator: Char) = apply {
|
|
|
|
this.with(
|
|
|
|
MoneyObject(
|
|
|
|
value, currency, MoneyOperator.operator(operator)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-02-08 21:25:16 +07:00
|
|
|
/**
|
|
|
|
* Example: String format => usd:1:+,khr:4000.0:-,usd:1 => 1 + (4000 eh) - 1 = 1USD
|
|
|
|
*/
|
|
|
|
fun parseFromString(valuesString: String) = apply {
|
|
|
|
val valueGroups = valuesString.split(",")
|
|
|
|
valueGroups.forEach { value ->
|
|
|
|
val tempValue = value.trim().split(":")
|
|
|
|
if (tempValue.isNotEmpty() && !tempValue.firstOrNull().isNullOrEmpty()) {
|
|
|
|
this.with(
|
|
|
|
tempValue.getOrNull(1)?.toDoubleOrNull() ?: 0.0,
|
|
|
|
tempValue.firstOrNull() ?: defaultCurrency,
|
|
|
|
MoneyOperator.operator(tempValue.getOrNull(2), MoneyOperator.PLUS),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-08 18:53:46 +07:00
|
|
|
fun build(): MoneyObject {
|
2021-02-08 21:25:16 +07:00
|
|
|
val first: MoneyObject = if (this.currency.isNullOrEmpty() && withs.isNotEmpty()) {
|
|
|
|
withs.removeFirst()
|
2021-02-08 18:53:46 +07:00
|
|
|
} else {
|
2021-02-08 21:25:16 +07:00
|
|
|
MoneyObject(
|
2021-02-08 18:53:46 +07:00
|
|
|
value = 0.0,
|
2021-02-08 21:25:16 +07:00
|
|
|
currency = this.currency ?: defaultCurrency,
|
2021-02-08 18:53:46 +07:00
|
|
|
operator = MoneyOperator.PLUS,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-02-08 21:25:16 +07:00
|
|
|
while (withs.isNotEmpty()) {
|
|
|
|
first.appendWithNext(withs.pop())
|
2021-02-08 18:53:46 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return first
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun toString(): String {
|
|
|
|
return "MoneyGeneratorBuilder(currency=$currency, withs=$withs)"
|
|
|
|
}
|
2021-02-08 12:39:52 +07:00
|
|
|
}
|
|
|
|
|
2021-02-08 18:53:46 +07:00
|
|
|
companion object {
|
2021-02-08 21:25:16 +07:00
|
|
|
fun builder() = MoneyObjectBuilder()
|
2021-02-08 12:39:52 +07:00
|
|
|
}
|
|
|
|
}
|