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 |
package net.pokeranalytics.android.util |
||||||
|
|
||||||
import android.content.Context |
|
||||||
|
|
||||||
const val NULL_TEXT: String = "--" |
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 |
package net.pokeranalytics.android.util.csv |
||||||
|
|
||||||
import io.realm.Realm |
import io.realm.Realm |
||||||
import net.pokeranalytics.android.exceptions.PAIllegalStateException |
|
||||||
import net.pokeranalytics.android.model.Limit |
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.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 org.apache.commons.csv.CSVRecord |
||||||
import timber.log.Timber |
|
||||||
import java.util.* |
|
||||||
|
|
||||||
/** |
/** |
||||||
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects |
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects |
||||||
*/ |
*/ |
||||||
class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean?, vararg elements: CSVField) : |
class SessionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg elements: CSVField) : |
||||||
DataCSVDescriptor<Identifiable>(source, *elements) { |
PACSVDescriptor<Session>(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) |
|
||||||
} |
|
||||||
|
|
||||||
|
override fun parseData(realm: Realm, record: CSVRecord): Session? { |
||||||
|
return this.parseSession(realm, record) |
||||||
} |
} |
||||||
|
|
||||||
private fun parseTransaction(realm: Realm, record: CSVRecord): Transaction? { |
override fun toCSV(data: Session, field: CSVField): String { |
||||||
|
val string = when (field) { |
||||||
var date: Date? = null |
is SessionField.Start -> field.format(data.startDate) |
||||||
var type: TransactionType? = null |
is SessionField.End -> field.format(data.endDate) |
||||||
var currencyCode: String? = null |
is SessionField.Break -> field.format(data.breakDuration.toDouble()) |
||||||
var currencyRate: Double? = null |
is SessionField.SessionType -> Session.Type.values()[data.type].value |
||||||
|
is SessionField.Live -> field.format(data.isLive) |
||||||
// Poker Bankroll Tracker specifics |
is SessionField.NumberOfTables -> field.format(data.numberOfTables) |
||||||
var buyin: Double? = null |
is SessionField.Buyin -> field.format(data.result?.buyin) |
||||||
var cashedOut: Double? = null |
is SessionField.CashedOut -> field.format(data.result?.cashout) |
||||||
|
is SessionField.NetResult -> field.format(data.result?.netResult) |
||||||
fields.forEach { field -> |
is SessionField.Tips -> field.format(data.result?.tips) |
||||||
|
is SessionField.LimitType -> { |
||||||
val index = this.fieldMapping[field] |
data.limit?.let { limit -> |
||||||
if (index != null) { |
Limit.values()[limit].longName |
||||||
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 -> { |
|
||||||
} |
|
||||||
} |
} |
||||||
} |
} |
||||||
} |
is SessionField.Game -> data.game?.name |
||||||
|
is SessionField.TableSize -> data.tableSize?.toString() |
||||||
val amount = if (buyin != null && buyin!! > 0) { |
is SessionField.Location -> data.location?.name |
||||||
type = TransactionType.getByValue(TransactionType.Value.WITHDRAWAL, realm) |
is SessionField.Bankroll -> data.bankroll?.name |
||||||
buyin!! * -1 |
is SessionField.CurrencyCode -> data.bankroll?.currency?.code |
||||||
} else if (cashedOut != null && cashedOut!! > 0) { |
is SessionField.CurrencyRate -> field.format(data.bankroll?.currency?.rate) |
||||||
type = TransactionType.getByValue(TransactionType.Value.DEPOSIT, realm) |
is SessionField.SmallBlind -> field.format(data.cgSmallBlind) |
||||||
cashedOut |
is SessionField.BigBlind -> field.format(data.cgBigBlind) |
||||||
} else { |
is SessionField.TournamentType -> field.format(data.tournamentType) |
||||||
null |
is SessionField.TournamentName -> data.tournamentName?.name |
||||||
} |
is SessionField.TournamentFeatures -> field.format(data.tournamentFeatures) |
||||||
|
is SessionField.TournamentEntryFee -> field.format(data.tournamentEntryFee) |
||||||
if (date != null && amount != null && type != null && currencyCode != null) { |
is SessionField.TournamentNumberOfPlayers -> field.format(data.tournamentNumberOfPlayers) |
||||||
|
is SessionField.TournamentPosition -> field.format(data.result?.tournamentFinalPosition) |
||||||
if (DataUtils.transactionUnicityCheck(realm, date!!, amount, type)) { |
is SessionField.Comment -> data.comment |
||||||
|
else -> null |
||||||
val bankroll = Bankroll.getOrCreate( |
} |
||||||
realm, |
return string ?: "" |
||||||
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 |
|
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
@ -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 |
distributionBase=GRADLE_USER_HOME |
||||||
distributionPath=wrapper/dists |
distributionPath=wrapper/dists |
||||||
zipStoreBase=GRADLE_USER_HOME |
zipStoreBase=GRADLE_USER_HOME |
||||||
zipStorePath=wrapper/dists |
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