You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
poker-analytics/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt

340 lines
13 KiB

package net.pokeranalytics.android.model
import io.realm.Realm
import io.realm.Sort
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.Criteria.Bankrolls.comparison
import net.pokeranalytics.android.model.Criteria.Blinds.comparison
import net.pokeranalytics.android.model.Criteria.Games.comparison
import net.pokeranalytics.android.model.Criteria.Limits.comparison
import net.pokeranalytics.android.model.Criteria.Locations.comparison
import net.pokeranalytics.android.model.Criteria.TableSizes.comparison
import net.pokeranalytics.android.model.Criteria.TournamentFeatures.comparison
import net.pokeranalytics.android.model.Criteria.TournamentFees.comparison
import net.pokeranalytics.android.model.Criteria.TournamentNames.comparison
import net.pokeranalytics.android.model.Criteria.TournamentTypes.comparison
import net.pokeranalytics.android.model.Criteria.TransactionTypes.comparison
import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import net.pokeranalytics.android.util.enumerations.IntSearchable
import net.pokeranalytics.android.util.extensions.findById
fun List<Criteria>.combined(): List<Query> {
val comparatorList = ArrayList<List<Query>>()
this.forEach { criteria ->
comparatorList.add(criteria.queries)
}
return getCombinations(comparatorList)
}
fun getCombinations(queries: List<List<Query>>): List<Query> {
if (queries.isEmpty()) {
return listOf()
}
val mutableQueries = queries.toMutableList()
var combinations = mutableQueries.removeAt(0)
for (queryList in mutableQueries) {
val newCombinations = mutableListOf<Query>()
combinations.forEach { combinedQuery ->
queryList.forEach { queryToAdd ->
val nq = Query().merge(combinedQuery).merge(queryToAdd)
newCombinations.add(nq)
}
}
combinations = newCombinations
}
return combinations
}
sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, RowRepresentable {
abstract class RealmCriteria(uniqueIdentifier: Int) : Criteria(uniqueIdentifier) {
inline fun <reified T : NameManageable> comparison(): List<Query> {
if (this is ListCustomFields) {
val objects = mutableListOf<QueryCondition.CustomFieldListQuery>()
val realm = Realm.getDefaultInstance()
realm.findById(CustomField::class.java, this.customFieldId)?.entries?.forEach {
objects.add(QueryCondition.CustomFieldListQuery(it))
}
objects.sorted()
realm.close()
return objects.map { Query(it) }
}
return compare<QueryCondition.QueryDataCondition<NameManageable>, T>()
}
}
abstract class SimpleCriteria(private val conditions: List<QueryCondition>, uniqueIdentifier: Int) : Criteria(uniqueIdentifier) {
fun comparison(): List<Query> {
return conditions.map { Query(it) }
}
}
abstract class ListCriteria(uniqueIdentifier: Int) : Criteria(uniqueIdentifier) {
inline fun <reified T : QueryCondition.ListOfValues<S>, reified S : Comparable<S>> comparison(): List<Query> {
if (this is ValueCustomFields) {
val realm = Realm.getDefaultInstance()
val distincts = realm.where<CustomFieldEntry>().equalTo("customFields.id", this.customFieldId).findAll().sort("numericValue", Sort.ASCENDING)
realm.close()
val objects = mutableListOf<QueryCondition.CustomFieldNumberQuery>()
distincts.mapNotNull {
it.numericValue
}.distinct().forEach {value ->
val condition: QueryCondition.CustomFieldNumberQuery = when (this.customFieldType(realm)) {
CustomField.Type.AMOUNT.uniqueIdentifier -> QueryCondition.CustomFieldAmountQuery()
CustomField.Type.NUMBER.uniqueIdentifier -> QueryCondition.CustomFieldNumberQuery()
else -> throw PokerAnalyticsException.QueryValueMapUnexpectedValue
}.apply {
this.customFieldId = this@ListCriteria.customFieldId
listOfValues = arrayListOf(value)
}
objects.add(condition)
}
objects.sorted()
return objects.map { Query(it) }
}
QueryCondition.distinct<Session, T, S>()?.let {
val values = it.mapNotNull { session ->
when (this) {
is Limits -> if (session.limit is S) {
session.limit as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
is TournamentTypes -> if (session.tournamentType is S) {
session.tournamentType as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
is TableSizes -> if (session.tableSize is S) {
session.tableSize as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
is TournamentFees -> if (session.tournamentEntryFee is S) {
session.tournamentEntryFee as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
is Blinds -> if (session.blinds is S) {
session.blinds as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
else -> null
}
}.distinct()
return compareList<T, S>(values = values)
}
return listOf()
}
}
object Bankrolls : RealmCriteria(1)
object Games : RealmCriteria(2)
object TournamentNames : RealmCriteria(3)
object Locations : RealmCriteria(4)
object TournamentFeatures : RealmCriteria(5)
object TransactionTypes : RealmCriteria(6)
object Limits : ListCriteria(7)
object TableSizes : ListCriteria(8)
object TournamentTypes : ListCriteria(9)
object MonthsOfYear : SimpleCriteria(List(12) { index ->
QueryCondition.AnyMonthOfYear().apply { listOfValues = arrayListOf(index) }
}, 10)
object DaysOfWeek : SimpleCriteria(List(7) { index ->
QueryCondition.AnyDayOfWeek().apply { listOfValues = arrayListOf(index + 1) }
}, 11)
object SessionTypes : SimpleCriteria(listOf(QueryCondition.IsCash, QueryCondition.IsTournament), 12)
object BankrollTypes : SimpleCriteria(listOf(QueryCondition.IsLive, QueryCondition.IsOnline), 13)
object DayPeriods : SimpleCriteria(listOf(QueryCondition.IsWeekDay, QueryCondition.IsWeekEnd), 14)
object Years : ListCriteria(15)
object AllMonthsUpToNow : ListCriteria(16)
object Blinds : ListCriteria(17)
object TournamentFees : ListCriteria(18)
object Cash : SimpleCriteria(listOf(QueryCondition.IsCash), 19)
object Tournament : SimpleCriteria(listOf(QueryCondition.IsTournament), 20)
data class ListCustomFields(override var customFieldId: String) : RealmCriteria(21), CustomFieldCriteria
data class ValueCustomFields(override var customFieldId: String) : ListCriteria(22), CustomFieldCriteria
val queries: List<Query>
get() {
return when (this) {
is AllMonthsUpToNow -> {
val realm = Realm.getDefaultInstance()
val firstSession = realm.where<Session>().isNotNull("startDate").sort("startDate", Sort.ASCENDING).findFirst()
val lastSession = realm.where<Session>().isNotNull("startDate").sort("startDate", Sort.DESCENDING).findFirst()
realm.close()
val years: ArrayList<Query> = arrayListOf()
val firstYear = firstSession?.year ?: return years
val firstMonth = firstSession.month ?: return years
val lastYear = lastSession?.year ?: return years
val lastMonth = lastSession.month ?: return years
for (year in firstYear..lastYear) {
val currentYear = QueryCondition.AnyYear(year)
for (month in 0..11) {
if (year == firstYear && month < firstMonth) {
continue
}
if (year == lastYear && month > lastMonth) {
continue
}
val currentMonth = QueryCondition.AnyMonthOfYear(month)
val query = Query(currentMonth, currentYear)
years.add(query)
}
}
years
}
else -> {
return this.queryConditions
}
}
}
val queryConditions: List<Query>
get() {
return when (this) {
is Bankrolls -> comparison<Bankroll>()
is Games -> comparison<Game>()
is TournamentFeatures -> comparison<TournamentFeature>()
is TournamentNames -> comparison<TournamentName>()
is Locations -> comparison<Location>()
is TransactionTypes -> comparison<TransactionType>()
is SimpleCriteria -> comparison()
is Limits -> comparison<QueryCondition.AnyLimit, Int>()
is TournamentTypes -> comparison<QueryCondition.AnyTournamentType, Int>()
is TableSizes -> comparison<QueryCondition.AnyTableSize, Int>()
is TournamentFees -> comparison<QueryCondition.TournamentFee, Double>()
is Years -> {
val years = arrayListOf<Query>()
val realm = Realm.getDefaultInstance()
val lastSession = realm.where<Session>().isNotNull("startDate").sort("startDate", Sort.DESCENDING).findFirst()
val yearNow = lastSession?.year ?: return years
realm.where<Session>().isNotNull("startDate").sort("year", Sort.ASCENDING).findFirst()?.year?.let {
for (index in 0..(yearNow - it)) {
val yearCondition = QueryCondition.AnyYear().apply {
listOfValues = arrayListOf(it + index)
}
years.add(Query(yearCondition))
}
}
realm.close()
years
}
is Blinds -> comparison<QueryCondition.AnyBlind, String>()
is ListCustomFields -> comparison<CustomFieldEntry>()
is ValueCustomFields -> {
val realm = Realm.getDefaultInstance()
val queries = when (this.customFieldType(realm)) {
CustomField.Type.AMOUNT.uniqueIdentifier -> comparison<QueryCondition.CustomFieldAmountQuery, Double >()
CustomField.Type.NUMBER.uniqueIdentifier -> comparison<QueryCondition.CustomFieldNumberQuery, Double >()
else -> throw PokerAnalyticsException.QueryTypeUnhandled
}
realm.close()
queries
}
else -> throw PokerAnalyticsException.QueryTypeUnhandled
}
}
override val resId: Int?
get() {
return when (this) {
Bankrolls -> R.string.bankroll
Games -> R.string.game
TournamentNames -> R.string.tournament_name
Locations -> R.string.location
TournamentFeatures -> R.string.tournament_feature
Limits -> R.string.limit
TableSizes -> R.string.table_size
TournamentTypes -> R.string.tournament_type
MonthsOfYear -> R.string.month_of_the_year
DaysOfWeek -> R.string.day_of_the_week
SessionTypes -> R.string.cash_or_tournament
BankrollTypes -> R.string.live_or_online
DayPeriods -> R.string.weekdays_or_weekend
Years -> R.string.year
AllMonthsUpToNow -> R.string.month
Blinds -> R.string.blind
TournamentFees -> R.string.entry_fees
// is ListCustomFields -> this.customField.resId
// is ValueCustomFields -> this.customField.resId
else -> null
}
}
companion object : IntSearchable<Criteria> {
inline fun <reified S : QueryCondition.QueryDataCondition<NameManageable>, reified T : NameManageable> compare(): List<Query> {
val objects = mutableListOf<S>()
val realm = Realm.getDefaultInstance()
realm.where<T>().findAll().forEach {
val condition = (QueryCondition.getInstance<T>() as S).apply {
setObject(it)
}
objects.add(condition)
}
objects.sorted()
realm.close()
return objects.map { Query(it) }
}
inline fun <reified S : QueryCondition.ListOfValues<T>, T : Any> compareList(values: List<T>): List<Query> {
val objects = mutableListOf<S>()
values.forEach {
val condition = (S::class.java.newInstance()).apply {
listOfValues = arrayListOf(it)
}
objects.add(condition)
}
objects.sorted()
return objects.map { Query(it) }
}
// SavableEnum
override fun valuesInternal(): Array<Criteria> {
return all.toTypedArray()
}
val all: List<Criteria>
get() {
return listOf(
Bankrolls, Games, TournamentNames, Locations,
TournamentFeatures, Limits, TableSizes, TournamentTypes,
MonthsOfYear, DaysOfWeek, SessionTypes,
BankrollTypes, DayPeriods, Years,
AllMonthsUpToNow, Blinds, TournamentFees
)
}
}
}
interface CustomFieldCriteria {
var customFieldId: String
fun customField(realm: Realm) : CustomField {
return realm.findById(this.customFieldId) ?: throw PAIllegalStateException("Custom field not found")
}
fun customFieldType(realm: Realm): Int {
return this.customField(realm).type
}
}