parent
294b30e86d
commit
51a524116e
@ -0,0 +1,24 @@ |
||||
package net.pokeranalytics.android.util |
||||
|
||||
import android.content.Context |
||||
import java.io.OutputStreamWriter |
||||
|
||||
class FileUtils { |
||||
|
||||
companion object{ |
||||
|
||||
/*** |
||||
* Writes a [string] into a file named [fileName], using a [context] |
||||
* Should be surrounded by a try/catch IOException |
||||
*/ |
||||
fun writeToFile(string: String, fileName: String, context: Context) { |
||||
|
||||
val outputStreamWriter = OutputStreamWriter(context.openFileOutput(fileName, Context.MODE_PRIVATE)) |
||||
outputStreamWriter.write(string) |
||||
outputStreamWriter.close() |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,5 +1,3 @@ |
||||
package net.pokeranalytics.android.util |
||||
|
||||
import android.content.Context |
||||
|
||||
const val NULL_TEXT: String = "--" |
||||
|
||||
@ -0,0 +1,254 @@ |
||||
package net.pokeranalytics.android.util.csv |
||||
|
||||
import net.pokeranalytics.android.model.interfaces.Identifiable |
||||
import io.realm.Realm |
||||
import net.pokeranalytics.android.exceptions.PAIllegalStateException |
||||
import net.pokeranalytics.android.model.Limit |
||||
import net.pokeranalytics.android.model.TableSize |
||||
import net.pokeranalytics.android.model.TournamentType |
||||
import net.pokeranalytics.android.model.realm.* |
||||
import net.pokeranalytics.android.model.utils.DataUtils |
||||
import net.pokeranalytics.android.util.extensions.getOrCreate |
||||
import net.pokeranalytics.android.util.extensions.setHourMinutes |
||||
import org.apache.commons.csv.CSVRecord |
||||
import timber.log.Timber |
||||
import java.util.* |
||||
|
||||
abstract class PACSVDescriptor<T : Identifiable>(source: DataSource, private var isTournament: Boolean?, vararg elements: CSVField) : DataCSVDescriptor<T>(source, *elements) { |
||||
|
||||
private var sameDaySessionCount: Int = 0 |
||||
private var currentDay: String = "" |
||||
private var startInSeconds: Double = 20 * 3600.0 |
||||
|
||||
/** |
||||
* Parses a [record] and return an optional Session |
||||
*/ |
||||
protected fun parseSession(realm: Realm, record: CSVRecord): Session? { |
||||
|
||||
val isTournament = isTournament ?: false |
||||
val session = Session.newInstance(realm, isTournament, managed = false) |
||||
|
||||
var startDate: Date? = null |
||||
var endDate: Date? = null |
||||
|
||||
var isLive = true |
||||
var bankrollName = "" |
||||
var currencyCode: String? = null |
||||
var currencyRate: Double? = null |
||||
var additionalBuyins = 0.0 // rebuy + addon |
||||
|
||||
var stackingIn: Double? = null |
||||
var stackingOut: Double? = null |
||||
|
||||
this.fields.forEach { field -> |
||||
|
||||
this.fieldMapping[field]?.let { index -> |
||||
|
||||
val value = record.get(index) |
||||
when (field) { |
||||
is SessionField.Start -> { |
||||
startDate = field.parse(value) |
||||
if (source == DataSource.POKER_AGENT) { |
||||
if (currentDay == value) { |
||||
sameDaySessionCount++ |
||||
} else { |
||||
sameDaySessionCount = 0 |
||||
} |
||||
currentDay = value |
||||
} else {} |
||||
} |
||||
is SessionField.End -> { |
||||
endDate = field.parse(value) |
||||
} |
||||
is SessionField.StartTime -> { |
||||
startDate?.setHourMinutes(value) |
||||
} |
||||
is SessionField.EndTime -> { |
||||
endDate?.setHourMinutes(value) |
||||
} |
||||
is SessionField.Duration -> { |
||||
val hoursDuration = field.parse(value) ?: throw PAIllegalStateException("null duration") |
||||
|
||||
if (startDate != null) { |
||||
if (field.randomTime) { |
||||
if (sameDaySessionCount == 0) { |
||||
startInSeconds = 20 * 3600.0 |
||||
} else { |
||||
startInSeconds -= hoursDuration * 3600.0 |
||||
} |
||||
|
||||
if (startInSeconds < 0) { |
||||
startInSeconds = 20 * 3600.0 |
||||
// throw PAIllegalStateException("negative start: $startDate, start = $startInSeconds, net = ${session.result?.netResult}") |
||||
} |
||||
|
||||
val hour = (startInSeconds / 3600.0).toInt() |
||||
val minutes = ((startInSeconds - hour * 3600.0) / 60.0).toInt() |
||||
val formattedTime = "$hour:$minutes" |
||||
startDate?.setHourMinutes(formattedTime) |
||||
} |
||||
|
||||
val seconds = (hoursDuration * 3600.0).toInt() |
||||
val calendar = Calendar.getInstance() |
||||
calendar.time = startDate |
||||
calendar.add(Calendar.SECOND, seconds) |
||||
endDate = calendar.time |
||||
|
||||
} else { |
||||
throw PAIllegalStateException("start date ($startDate) + hoursDuration ($hoursDuration) required") |
||||
} |
||||
|
||||
} |
||||
is SessionField.Buyin -> { |
||||
val buyin = field.parse(value) |
||||
session.result?.buyin = buyin |
||||
if (session.type == Session.Type.TOURNAMENT.ordinal) { |
||||
session.tournamentEntryFee = buyin |
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.CashedOut -> session.result?.cashout = field.parse(value) |
||||
is SessionField.NetResult -> session.result?.netResult = field.parse(value) |
||||
is SessionField.SessionType -> { |
||||
Session.Type.getValueFromString(value)?.let { type -> |
||||
session.type = type.ordinal |
||||
} |
||||
} |
||||
is SessionField.Live -> isLive = field.parse(value) ?: false |
||||
is SessionField.NumberOfTables -> session.numberOfTables = field.parse(value) ?: 1 |
||||
is SessionField.Addon -> additionalBuyins += field.parse(value) ?: 0.0 |
||||
is SessionField.Rebuy -> additionalBuyins += field.parse(value) ?: 0.0 |
||||
is SessionField.Tips -> session.result?.tips = field.parse(value) |
||||
is SessionField.Break -> { |
||||
field.parse(value)?.let { |
||||
session.breakDuration = it.toLong() |
||||
} |
||||
} |
||||
is SessionField.LimitAndGame -> { |
||||
if (value.isNotEmpty()) { |
||||
var limitAndGame = value |
||||
for (someLimit in Limit.values()) { |
||||
if (value.startsWith(someLimit.longName)) { |
||||
session.limit = someLimit.ordinal |
||||
limitAndGame = limitAndGame.removePrefix(someLimit.longName) |
||||
break |
||||
} |
||||
} |
||||
session.game = realm.getOrCreate(limitAndGame.trim()) |
||||
|
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.Game -> { |
||||
if (value.isNotEmpty()) { |
||||
session.game = realm.getOrCreate(value) |
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.Location -> { |
||||
val trimmedValue = value.trim() |
||||
if (trimmedValue.isNotEmpty()) { |
||||
session.location = realm.getOrCreate(trimmedValue) |
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.Bankroll -> bankrollName = value |
||||
is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal |
||||
is SessionField.Comment -> session.comment = value |
||||
is SessionField.Blind -> { // 1/2 |
||||
val blinds = field.parse(value) |
||||
session.cgSmallBlind = blinds?.first |
||||
session.cgBigBlind = blinds?.second |
||||
} |
||||
is SessionField.SmallBlind -> { |
||||
val sb = field.parse(value) |
||||
if (sb != null && sb > 0.0) { |
||||
session.cgSmallBlind = sb |
||||
} else {} |
||||
} |
||||
is SessionField.BigBlind -> { |
||||
val bb = field.parse(value) |
||||
if (bb != null && bb > 0.0) { |
||||
session.cgBigBlind = bb |
||||
} else {} |
||||
} |
||||
is SessionField.TableSize -> session.tableSize = TableSize.valueForLabel(value) |
||||
is SessionField.TournamentPosition -> session.result?.tournamentFinalPosition = |
||||
field.parse(value) |
||||
is SessionField.TournamentName -> { |
||||
if (value.isNotEmpty()) { |
||||
session.tournamentName = realm.getOrCreate(value) |
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.TournamentTypeName -> session.tournamentType = |
||||
TournamentType.getValueForLabel(value)?.ordinal |
||||
is SessionField.TournamentNumberOfPlayers -> session.tournamentNumberOfPlayers = |
||||
field.parse(value) |
||||
is SessionField.TournamentEntryFee -> session.tournamentEntryFee = field.parse(value) |
||||
is SessionField.TournamentFeatures -> { |
||||
value.split(",").forEach { featureName -> |
||||
val tournamentFeature: TournamentFeature = realm.getOrCreate(featureName) |
||||
session.tournamentFeatures.add(tournamentFeature) |
||||
} |
||||
} |
||||
is SessionField.CurrencyCode -> currencyCode = value |
||||
is SessionField.CurrencyRate -> currencyRate = field.parse(value) |
||||
is SessionField.StackingIn -> { |
||||
stackingIn = field.parse(value) |
||||
} |
||||
is SessionField.StackingOut -> { |
||||
stackingOut = field.parse(value) |
||||
} |
||||
else -> { |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
if (bankrollName.isEmpty()) { |
||||
bankrollName = "Import" |
||||
} |
||||
|
||||
val bankroll = Bankroll.getOrCreate(realm, bankrollName, isLive, currencyCode, currencyRate) |
||||
session.bankroll = bankroll |
||||
|
||||
session.result?.buyin?.let { |
||||
session.result?.buyin = it + additionalBuyins |
||||
} |
||||
val net = session.result?.net |
||||
|
||||
if (startDate != null && endDate != null && net != null) { // valid session |
||||
// session already in realm, we'd love not put it in Realm before doing the check |
||||
val count = DataUtils.sessionCount(realm, startDate!!, endDate!!, net) |
||||
if (count == 0) { |
||||
|
||||
val managedSession = realm.copyToRealm(session) |
||||
managedSession.startDate = startDate |
||||
managedSession.endDate = endDate |
||||
|
||||
if (stackingIn != null && stackingIn != 0.0) { |
||||
val type = TransactionType.getByValue(TransactionType.Value.STACKING_INCOMING, realm) |
||||
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingIn!!) |
||||
this.addAdditionallyCreatedIdentifiable(transaction) |
||||
} |
||||
|
||||
if (stackingOut != null && stackingOut != 0.0) { |
||||
val type = TransactionType.getByValue(TransactionType.Value.STACKING_OUTGOING, realm) |
||||
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!) |
||||
this.addAdditionallyCreatedIdentifiable(transaction) |
||||
} |
||||
|
||||
return managedSession |
||||
} else { |
||||
Timber.d("Session already exists(count=$count): sd=$startDate, ed=$endDate, net=$net") |
||||
} |
||||
} else { |
||||
Timber.d("Can't import session: sd=$startDate, ed=$endDate, net=$net") |
||||
} |
||||
|
||||
return null |
||||
} |
||||
|
||||
} |
||||
@ -1,351 +1,55 @@ |
||||
package net.pokeranalytics.android.util.csv |
||||
|
||||
import io.realm.Realm |
||||
import net.pokeranalytics.android.exceptions.PAIllegalStateException |
||||
import net.pokeranalytics.android.model.Limit |
||||
import net.pokeranalytics.android.model.TableSize |
||||
import net.pokeranalytics.android.model.TournamentType |
||||
import net.pokeranalytics.android.model.interfaces.Identifiable |
||||
import net.pokeranalytics.android.model.realm.Bankroll |
||||
import net.pokeranalytics.android.model.realm.Session |
||||
import net.pokeranalytics.android.model.realm.Transaction |
||||
import net.pokeranalytics.android.model.realm.TransactionType |
||||
import net.pokeranalytics.android.model.utils.DataUtils |
||||
import net.pokeranalytics.android.util.extensions.getOrCreate |
||||
import net.pokeranalytics.android.util.extensions.setHourMinutes |
||||
import org.apache.commons.csv.CSVRecord |
||||
import timber.log.Timber |
||||
import java.util.* |
||||
|
||||
/** |
||||
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects |
||||
*/ |
||||
class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean?, vararg elements: CSVField) : |
||||
DataCSVDescriptor<Identifiable>(source, *elements) { |
||||
|
||||
private enum class DataType { |
||||
TRANSACTION, |
||||
SESSION; |
||||
|
||||
companion object { |
||||
|
||||
fun valueForString(type: String): DataType? { |
||||
return when (type) { |
||||
"Deposit/Payout" -> TRANSACTION |
||||
"Cash Game", "Tournament" -> SESSION |
||||
else -> null |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Parses a [record] and return an optional Session |
||||
*/ |
||||
override fun parseData(realm: Realm, record: CSVRecord): Identifiable? { |
||||
|
||||
var dataType: DataType? = null |
||||
val typeField = fields.firstOrNull { it is SessionField.SessionType } |
||||
typeField?.let { field -> |
||||
this.fieldMapping[field]?.let { index -> |
||||
val typeValue = record.get(index) |
||||
dataType = DataType.valueForString(typeValue) |
||||
} |
||||
} |
||||
|
||||
return when (dataType) { |
||||
DataType.TRANSACTION -> parseTransaction(realm, record) |
||||
else -> parseSession(realm, record) |
||||
} |
||||
class SessionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg elements: CSVField) : |
||||
PACSVDescriptor<Session>(source, isTournament, *elements) { |
||||
|
||||
override fun parseData(realm: Realm, record: CSVRecord): Session? { |
||||
return this.parseSession(realm, record) |
||||
} |
||||
|
||||
private fun parseTransaction(realm: Realm, record: CSVRecord): Transaction? { |
||||
|
||||
var date: Date? = null |
||||
var type: TransactionType? = null |
||||
var currencyCode: String? = null |
||||
var currencyRate: Double? = null |
||||
|
||||
// Poker Bankroll Tracker specifics |
||||
var buyin: Double? = null |
||||
var cashedOut: Double? = null |
||||
|
||||
fields.forEach { field -> |
||||
|
||||
val index = this.fieldMapping[field] |
||||
if (index != null) { |
||||
val value = record.get(index) |
||||
when (field) { |
||||
is SessionField.Start -> { |
||||
date = field.parse(value) |
||||
} |
||||
is SessionField.Buyin -> buyin = field.parse(value) |
||||
is SessionField.CashedOut -> cashedOut = field.parse(value) |
||||
is SessionField.CurrencyCode -> currencyCode = value |
||||
is SessionField.CurrencyRate -> currencyRate = field.parse(value) |
||||
else -> { |
||||
} |
||||
override fun toCSV(data: Session, field: CSVField): String { |
||||
val string = when (field) { |
||||
is SessionField.Start -> field.format(data.startDate) |
||||
is SessionField.End -> field.format(data.endDate) |
||||
is SessionField.Break -> field.format(data.breakDuration.toDouble()) |
||||
is SessionField.SessionType -> Session.Type.values()[data.type].value |
||||
is SessionField.Live -> field.format(data.isLive) |
||||
is SessionField.NumberOfTables -> field.format(data.numberOfTables) |
||||
is SessionField.Buyin -> field.format(data.result?.buyin) |
||||
is SessionField.CashedOut -> field.format(data.result?.cashout) |
||||
is SessionField.NetResult -> field.format(data.result?.netResult) |
||||
is SessionField.Tips -> field.format(data.result?.tips) |
||||
is SessionField.LimitType -> { |
||||
data.limit?.let { limit -> |
||||
Limit.values()[limit].longName |
||||
} |
||||
} |
||||
} |
||||
|
||||
val amount = if (buyin != null && buyin!! > 0) { |
||||
type = TransactionType.getByValue(TransactionType.Value.WITHDRAWAL, realm) |
||||
buyin!! * -1 |
||||
} else if (cashedOut != null && cashedOut!! > 0) { |
||||
type = TransactionType.getByValue(TransactionType.Value.DEPOSIT, realm) |
||||
cashedOut |
||||
} else { |
||||
null |
||||
} |
||||
|
||||
if (date != null && amount != null && type != null && currencyCode != null) { |
||||
|
||||
if (DataUtils.transactionUnicityCheck(realm, date!!, amount, type)) { |
||||
|
||||
val bankroll = Bankroll.getOrCreate( |
||||
realm, |
||||
currencyCode!!, |
||||
currencyCode = currencyCode!!, |
||||
currencyRate = currencyRate |
||||
) |
||||
return Transaction.newInstance(realm, bankroll, date!!, type, amount) |
||||
} else { |
||||
Timber.d("Transaction already exists") |
||||
} |
||||
} else { |
||||
Timber.d("Can't import transaction: date=$date, amount=$amount, type=${type?.name}") |
||||
} |
||||
|
||||
return null |
||||
} |
||||
|
||||
private var sameDaySessionCount: Int = 0 |
||||
private var currentday: String = "" |
||||
private var startInSeconds: Double = 20 * 3600.0 |
||||
|
||||
private fun parseSession(realm: Realm, record: CSVRecord): Session? { |
||||
|
||||
val isTournament = isTournament ?: false |
||||
val session = Session.newInstance(realm, isTournament, managed = false) |
||||
|
||||
var startDate: Date? = null |
||||
var endDate: Date? = null |
||||
|
||||
var isLive = true |
||||
var bankrollName = "" |
||||
var currencyCode: String? = null |
||||
var currencyRate: Double? = null |
||||
var additionalBuyins = 0.0 // rebuy + addon |
||||
|
||||
var stackingIn: Double? = null |
||||
var stackingOut: Double? = null |
||||
|
||||
fields.forEach { field -> |
||||
|
||||
this.fieldMapping[field]?.let { index -> |
||||
|
||||
val value = record.get(index) |
||||
when (field) { |
||||
is SessionField.Start -> { |
||||
startDate = field.parse(value) |
||||
if (source == DataSource.POKER_AGENT) { |
||||
if (currentday == value) { |
||||
sameDaySessionCount++ |
||||
} else { |
||||
sameDaySessionCount = 0 |
||||
} |
||||
currentday = value |
||||
} else {} |
||||
} |
||||
is SessionField.End -> { |
||||
endDate = field.parse(value) |
||||
} |
||||
is SessionField.StartTime -> { |
||||
startDate?.setHourMinutes(value) |
||||
} |
||||
is SessionField.EndTime -> { |
||||
endDate?.setHourMinutes(value) |
||||
} |
||||
is SessionField.Duration -> { |
||||
val hoursDuration = field.parse(value) ?: throw PAIllegalStateException("null duration") |
||||
|
||||
if (startDate != null) { |
||||
if (field.randomTime) { |
||||
if (sameDaySessionCount == 0) { |
||||
startInSeconds = 20 * 3600.0 |
||||
} else { |
||||
startInSeconds -= hoursDuration * 3600.0 |
||||
} |
||||
|
||||
if (startInSeconds < 0) { |
||||
startInSeconds = 20 * 3600.0 |
||||
// throw PAIllegalStateException("negative start: $startDate, start = $startInSeconds, net = ${session.result?.netResult}") |
||||
} |
||||
|
||||
val hour = (startInSeconds / 3600.0).toInt() |
||||
val minutes = ((startInSeconds - hour * 3600.0) / 60.0).toInt() |
||||
val formattedTime = "$hour:$minutes" |
||||
startDate?.setHourMinutes(formattedTime) |
||||
} |
||||
|
||||
val seconds = (hoursDuration * 3600.0).toInt() |
||||
val calendar = Calendar.getInstance() |
||||
calendar.time = startDate |
||||
calendar.add(Calendar.SECOND, seconds) |
||||
endDate = calendar.time |
||||
|
||||
} else { |
||||
throw PAIllegalStateException("start date ($startDate) + hoursDuration ($hoursDuration) required") |
||||
} |
||||
|
||||
} |
||||
is SessionField.Buyin -> { |
||||
val buyin = field.parse(value) |
||||
session.result?.buyin = buyin |
||||
if (session.type == Session.Type.TOURNAMENT.ordinal) { |
||||
session.tournamentEntryFee = buyin |
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.CashedOut -> session.result?.cashout = field.parse(value) |
||||
is SessionField.NetResult -> session.result?.netResult = field.parse(value) |
||||
is SessionField.SessionType -> { |
||||
Session.Type.getValueFromString(value)?.let { type -> |
||||
session.type = type.ordinal |
||||
} |
||||
} |
||||
is SessionField.Live -> isLive = field.parse(value) ?: false |
||||
is SessionField.NumberOfTables -> session.numberOfTables = field.parse(value) ?: 1 |
||||
is SessionField.Addon -> additionalBuyins += field.parse(value) ?: 0.0 |
||||
is SessionField.Rebuy -> additionalBuyins += field.parse(value) ?: 0.0 |
||||
is SessionField.Tips -> session.result?.tips = field.parse(value) |
||||
is SessionField.Break -> { |
||||
field.parse(value)?.let { |
||||
session.breakDuration = it.toLong() |
||||
} |
||||
} |
||||
is SessionField.LimitAndGame -> { |
||||
if (value.isNotEmpty()) { |
||||
var limitAndGame = value |
||||
for (someLimit in Limit.values()) { |
||||
if (value.startsWith(someLimit.longName)) { |
||||
session.limit = someLimit.ordinal |
||||
limitAndGame = limitAndGame.removePrefix(someLimit.longName) |
||||
break |
||||
} |
||||
} |
||||
session.game = realm.getOrCreate(limitAndGame.trim()) |
||||
|
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.Game -> { |
||||
if (value.isNotEmpty()) { |
||||
session.game = realm.getOrCreate(value) |
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.Location -> { |
||||
val trimmedValue = value.trim() |
||||
if (trimmedValue.isNotEmpty()) { |
||||
session.location = realm.getOrCreate(trimmedValue) |
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.Bankroll -> bankrollName = value |
||||
is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal |
||||
is SessionField.Comment -> session.comment = value |
||||
is SessionField.Blind -> { // 1/2 |
||||
val blinds = field.parse(value) |
||||
session.cgSmallBlind = blinds?.first |
||||
session.cgBigBlind = blinds?.second |
||||
} |
||||
is SessionField.SmallBlind -> { |
||||
val sb = field.parse(value) |
||||
if (sb != null && sb > 0.0) { |
||||
session.cgSmallBlind = sb |
||||
} else {} |
||||
} |
||||
is SessionField.BigBlind -> { |
||||
val bb = field.parse(value) |
||||
if (bb != null && bb > 0.0) { |
||||
session.cgBigBlind = bb |
||||
} else {} |
||||
} |
||||
is SessionField.TableSize -> session.tableSize = TableSize.valueForLabel(value) |
||||
is SessionField.TournamentPosition -> session.result?.tournamentFinalPosition = |
||||
field.parse(value)?.toInt() |
||||
is SessionField.TournamentName -> { |
||||
if (value.isNotEmpty()) { |
||||
session.tournamentName = realm.getOrCreate(value) |
||||
} else { |
||||
} |
||||
} |
||||
is SessionField.TournamentType -> session.tournamentType = |
||||
TournamentType.getValueForLabel(value)?.ordinal |
||||
is SessionField.TournamentNumberOfPlayers -> session.tournamentNumberOfPlayers = |
||||
field.parse(value)?.toInt() |
||||
is SessionField.TournamentEntryFee -> session.tournamentEntryFee = field.parse(value) |
||||
is SessionField.CurrencyCode -> currencyCode = value |
||||
is SessionField.CurrencyRate -> currencyRate = field.parse(value) |
||||
is SessionField.StackingIn -> { |
||||
stackingIn = field.parse(value) |
||||
} |
||||
is SessionField.StackingOut -> { |
||||
stackingOut = field.parse(value) |
||||
} |
||||
else -> { |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
if (bankrollName.isEmpty()) { |
||||
bankrollName = "Import" |
||||
} |
||||
|
||||
val bankroll = Bankroll.getOrCreate(realm, bankrollName, isLive, currencyCode, currencyRate) |
||||
session.bankroll = bankroll |
||||
|
||||
session.result?.buyin?.let { |
||||
session.result?.buyin = it + additionalBuyins |
||||
} |
||||
val net = session.result?.net |
||||
|
||||
if (startDate != null && endDate != null && net != null) { // valid session |
||||
// session already in realm, we'd love not put it in Realm before doing the check |
||||
val count = DataUtils.sessionCount(realm, startDate!!, endDate!!, net) |
||||
if (count == 0) { |
||||
|
||||
val managedSession = realm.copyToRealm(session) |
||||
managedSession.startDate = startDate |
||||
managedSession.endDate = endDate |
||||
|
||||
if (stackingIn != null && stackingIn != 0.0) { |
||||
val type = TransactionType.getByValue(TransactionType.Value.STACKING_INCOMING, realm) |
||||
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingIn!!) |
||||
this.addAdditionallyCreatedIdentifiable(transaction) |
||||
} |
||||
|
||||
if (stackingOut != null && stackingOut != 0.0) { |
||||
val type = TransactionType.getByValue(TransactionType.Value.STACKING_OUTGOING, realm) |
||||
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!) |
||||
this.addAdditionallyCreatedIdentifiable(transaction) |
||||
} |
||||
|
||||
return managedSession |
||||
} else { |
||||
Timber.d("Session already exists(count=$count): sd=$startDate, ed=$endDate, net=$net") |
||||
} |
||||
} else { |
||||
Timber.d("Can't import session: sd=$startDate, ed=$endDate, net=$net") |
||||
} |
||||
|
||||
return null |
||||
is SessionField.Game -> data.game?.name |
||||
is SessionField.TableSize -> data.tableSize?.toString() |
||||
is SessionField.Location -> data.location?.name |
||||
is SessionField.Bankroll -> data.bankroll?.name |
||||
is SessionField.CurrencyCode -> data.bankroll?.currency?.code |
||||
is SessionField.CurrencyRate -> field.format(data.bankroll?.currency?.rate) |
||||
is SessionField.SmallBlind -> field.format(data.cgSmallBlind) |
||||
is SessionField.BigBlind -> field.format(data.cgBigBlind) |
||||
is SessionField.TournamentType -> field.format(data.tournamentType) |
||||
is SessionField.TournamentName -> data.tournamentName?.name |
||||
is SessionField.TournamentFeatures -> field.format(data.tournamentFeatures) |
||||
is SessionField.TournamentEntryFee -> field.format(data.tournamentEntryFee) |
||||
is SessionField.TournamentNumberOfPlayers -> field.format(data.tournamentNumberOfPlayers) |
||||
is SessionField.TournamentPosition -> field.format(data.result?.tournamentFinalPosition) |
||||
is SessionField.Comment -> data.comment |
||||
else -> null |
||||
} |
||||
return string ?: "" |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,118 @@ |
||||
package net.pokeranalytics.android.util.csv |
||||
|
||||
import io.realm.Realm |
||||
import net.pokeranalytics.android.model.interfaces.Identifiable |
||||
import net.pokeranalytics.android.model.realm.Bankroll |
||||
import net.pokeranalytics.android.model.realm.Transaction |
||||
import net.pokeranalytics.android.model.realm.TransactionType |
||||
import net.pokeranalytics.android.model.utils.DataUtils |
||||
import org.apache.commons.csv.CSVRecord |
||||
import timber.log.Timber |
||||
import java.util.* |
||||
|
||||
/** |
||||
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects |
||||
*/ |
||||
class SessionTransactionCSVDescriptor(source: DataSource, private var isTournament: Boolean?, vararg elements: CSVField) : |
||||
PACSVDescriptor<Identifiable>(source, isTournament, *elements) { |
||||
|
||||
private enum class DataType { |
||||
TRANSACTION, |
||||
SESSION; |
||||
|
||||
companion object { |
||||
|
||||
fun valueForString(type: String): DataType? { |
||||
return when (type) { |
||||
"Deposit/Payout" -> TRANSACTION |
||||
"Cash Game", "Tournament" -> SESSION |
||||
else -> null |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Parses a [record] and return an optional Session |
||||
*/ |
||||
override fun parseData(realm: Realm, record: CSVRecord): Identifiable? { |
||||
|
||||
var dataType: DataType? = null |
||||
val typeField = fields.firstOrNull { it is SessionField.SessionType } |
||||
typeField?.let { field -> |
||||
this.fieldMapping[field]?.let { index -> |
||||
val typeValue = record.get(index) |
||||
dataType = DataType.valueForString(typeValue) |
||||
} |
||||
} |
||||
|
||||
return when (dataType) { |
||||
DataType.TRANSACTION -> parseTransaction(realm, record) |
||||
else -> parseSession(realm, record) |
||||
} |
||||
|
||||
} |
||||
|
||||
private fun parseTransaction(realm: Realm, record: CSVRecord): Transaction? { |
||||
|
||||
var date: Date? = null |
||||
var type: TransactionType? = null |
||||
var currencyCode: String? = null |
||||
var currencyRate: Double? = null |
||||
|
||||
// Poker Bankroll Tracker specifics |
||||
var buyin: Double? = null |
||||
var cashedOut: Double? = null |
||||
|
||||
fields.forEach { field -> |
||||
|
||||
val index = this.fieldMapping[field] |
||||
if (index != null) { |
||||
val value = record.get(index) |
||||
when (field) { |
||||
is SessionField.Start -> { |
||||
date = field.parse(value) |
||||
} |
||||
is SessionField.Buyin -> buyin = field.parse(value) |
||||
is SessionField.CashedOut -> cashedOut = field.parse(value) |
||||
is SessionField.CurrencyCode -> currencyCode = value |
||||
is SessionField.CurrencyRate -> currencyRate = field.parse(value) |
||||
else -> { |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
val amount = if (buyin != null && buyin!! > 0) { |
||||
type = TransactionType.getByValue(TransactionType.Value.WITHDRAWAL, realm) |
||||
buyin!! * -1 |
||||
} else if (cashedOut != null && cashedOut!! > 0) { |
||||
type = TransactionType.getByValue(TransactionType.Value.DEPOSIT, realm) |
||||
cashedOut |
||||
} else { |
||||
null |
||||
} |
||||
|
||||
if (date != null && amount != null && type != null && currencyCode != null) { |
||||
|
||||
if (DataUtils.transactionUnicityCheck(realm, date!!, amount, type)) { |
||||
|
||||
val bankroll = Bankroll.getOrCreate( |
||||
realm, |
||||
currencyCode!!, |
||||
currencyCode = currencyCode!!, |
||||
currencyRate = currencyRate |
||||
) |
||||
return Transaction.newInstance(realm, bankroll, date!!, type, amount) |
||||
} else { |
||||
Timber.d("Transaction already exists") |
||||
} |
||||
} else { |
||||
Timber.d("Can't import transaction: date=$date, amount=$amount, type=${type?.name}") |
||||
} |
||||
|
||||
return null |
||||
} |
||||
|
||||
} |
||||
@ -1,6 +1,6 @@ |
||||
#Mon Aug 26 10:00:03 CEST 2019 |
||||
#Wed May 13 12:21:50 CEST 2020 |
||||
distributionBase=GRADLE_USER_HOME |
||||
distributionPath=wrapper/dists |
||||
zipStoreBase=GRADLE_USER_HOME |
||||
zipStorePath=wrapper/dists |
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip |
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip |
||||
|
||||
Loading…
Reference in new issue