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.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.FilterHelper 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 fun List.combined(): List { val comparatorList = ArrayList>() this.forEach { criteria -> comparatorList.add(criteria.queries) } return getCombinations(comparatorList) } fun getCombinations(queries: List>): List { if (queries.size == 0) { return listOf() } val mutableQueries = queries.toMutableList() var combinations = mutableQueries.removeAt(0) for (queryList in mutableQueries) { val newCombinations = mutableListOf() 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 comparison(): List { if (this is ListCustomFields) { val objects = mutableListOf() val realm = Realm.getDefaultInstance() realm.where().equalTo("customField.id", this.customField.id).findAll().forEach { objects.add(QueryCondition.CustomFieldListQuery(it)) } objects.sorted() realm.close() return objects.map { Query(it) } } return compare, T>() } } abstract class SimpleCriteria(private val conditions: List, uniqueIdentifier: Int) : Criteria(uniqueIdentifier) { fun comparison(): List { return conditions.map { Query(it) } } } abstract class ListCriteria(uniqueIdentifier: Int) : Criteria(uniqueIdentifier) { inline fun , reified S : Comparable> comparison(): List { if (this is ValueCustomFields) { val realm = Realm.getDefaultInstance() val distincts = realm.where().equalTo("customField.id", this.customField.id).distinct("value").findAll().sort("value", Sort.ASCENDING) realm.close() val objects = mutableListOf() distincts.distinct().forEach { val condition: QueryCondition.CustomFieldNumberQuery = QueryCondition.CustomFieldNumberQuery().apply { this.customFieldId = this@ListCriteria.customField.id listOfValues = arrayListOf(it.value) } objects.add(condition) objects.sorted() return objects.map { Query(it) } } } QueryCondition.distinct()?.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(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(var customField: CustomField) : RealmCriteria(21) data class ValueCustomFields(var customField: CustomField) : ListCriteria(22) val queries: List get() { return when (this) { is AllMonthsUpToNow -> { val realm = Realm.getDefaultInstance() val firstSession = realm.where().sort("startDate", Sort.ASCENDING).findFirst() val lastSession = realm.where().sort("startDate", Sort.DESCENDING).findFirst() realm.close() val years: ArrayList = 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(currentYear, currentMonth) years.add(query) } } years } else -> { return this.queryConditions } } } val queryConditions: List get() { return when (this) { is Bankrolls -> comparison() is Games -> comparison() is TournamentFeatures -> comparison() is TournamentNames -> comparison() is Locations -> comparison() is TransactionTypes -> comparison() is SimpleCriteria -> comparison() is Limits -> comparison() is TournamentTypes -> comparison() is TableSizes -> comparison() is TournamentFees -> comparison() is Years -> { val years = arrayListOf() val realm = Realm.getDefaultInstance() val lastSession = realm.where().sort("startDate", Sort.DESCENDING).findFirst() val yearNow = lastSession?.year ?: return years realm.where().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() is ListCustomFields -> comparison() 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 { inline fun , reified T : NameManageable> compare(): List { val objects = mutableListOf() val realm = Realm.getDefaultInstance() realm.where().findAll().forEach { val condition = (QueryCondition.getInstance() as S).apply { setObject(it) } objects.add(condition) } objects.sorted() realm.close() return objects.map { Query(it) } } inline fun , T : Any> compareList(values: List): List { val objects = mutableListOf() values.forEach { val condition = (S::class.java.newInstance()).apply { listOfValues = arrayListOf(it) } objects.add(condition) } objects.sorted() return objects.map { Query(it) } } val all: List get() { return listOf( Bankrolls, Games, TournamentNames, Locations, TournamentFeatures, Limits, TableSizes, TournamentTypes, MonthsOfYear, DaysOfWeek, SessionTypes, BankrollTypes, DayPeriods, Years, AllMonthsUpToNow, Blinds, TournamentFees ) } // SavableEnum override fun valuesInternal(): Array { return all.toTypedArray() } } }