summaryrefslogtreecommitdiff
path: root/app/src/main/java/net/taler/wallet/Amount.kt
blob: 2b41be19517992cec9334fc9d2bc0a6df733dfd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 This file is part of GNU Taler
 (C) 2019 Taler Systems S.A.

 GNU Taler is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.

 GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */

@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")

package net.taler.wallet

import org.json.JSONObject
import kotlin.math.round

private const val FRACTIONAL_BASE = 1e8

data class Amount(val currency: String, val amount: String) {
    fun isZero(): Boolean {
        return amount.toDouble() == 0.0
    }

    companion object {
        fun fromJson(jsonAmount: JSONObject): Amount {
            val amountCurrency = jsonAmount.getString("currency")
            val amountValue = jsonAmount.getString("value")
            val amountFraction = jsonAmount.getString("fraction")
            val amountIntValue = Integer.parseInt(amountValue)
            val amountIntFraction = Integer.parseInt(amountFraction)
            return Amount(
                amountCurrency,
                (amountIntValue + amountIntFraction / FRACTIONAL_BASE).toString()
            )
        }

        fun fromString(strAmount: String): Amount {
            val components = strAmount.split(":")
            return Amount(components[0], components[1])
        }
    }
}

class ParsedAmount(
    /**
     * name of the currency using either a three-character ISO 4217 currency code,
     * or a regional currency identifier starting with a "*" followed by at most 10 characters.
     * ISO 4217 exponents in the name are not supported,
     * although the "fraction" is corresponds to an ISO 4217 exponent of 6.
     */
    val currency: String,

    /**
     * unsigned 32 bit value in the currency,
     * note that "1" here would correspond to 1 EUR or 1 USD, depending on currency, not 1 cent.
     */
    val value: UInt,

    /**
     * unsigned 32 bit fractional value to be added to value
     * representing an additional currency fraction,
     * in units of one millionth (1e-6) of the base currency value.
     * For example, a fraction of 500,000 would correspond to 50 cents.
     */
    val fraction: Double
) {
    companion object {
        fun parseAmount(str: String): ParsedAmount {
            val split = str.split(":")
            check(split.size == 2)
            val currency = split[0]
            val valueSplit = split[1].split(".")
            val value = valueSplit[0].toUInt()
            val fraction: Double = if (valueSplit.size > 1) {
                round("0.${valueSplit[1]}".toDouble() * FRACTIONAL_BASE)
            } else 0.0
            return ParsedAmount(currency, value, fraction)
        }
    }

    operator fun minus(other: ParsedAmount): ParsedAmount {
        check(currency == other.currency) { "Can only subtract from same currency" }
        var resultValue = value
        var resultFraction = fraction
        if (resultFraction < other.fraction) {
            if (resultValue < 1u) {
                return ParsedAmount(currency, 0u, 0.0)
            }
            resultValue--
            resultFraction += FRACTIONAL_BASE
        }
        check(resultFraction >= other.fraction)
        resultFraction -= other.fraction
        if (resultValue < other.value) {
            return ParsedAmount(currency, 0u, 0.0)
        }
        resultValue -= other.value
        return ParsedAmount(currency, resultValue, resultFraction)
    }

    fun isZero(): Boolean {
        return value == 0u && fraction == 0.0
    }

    fun toJSONString(): String {
        return "$currency:${getValueString()}"
    }

    override fun toString(): String {
        return "${getValueString()} $currency"
    }

    private fun getValueString(): String {
        return "$value${(fraction / FRACTIONAL_BASE).toString().substring(1)}"
    }

}