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.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 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 : RowRepresentable { abstract class RealmCriteria : Criteria() { inline fun comparison(): List { return compare, T>() } } abstract class SimpleCriteria(private val conditions: List) : Criteria() { fun comparison(): List { return conditions.map { Query(it) } } } abstract class ListCriteria : Criteria() { inline fun , reified S : Comparable> comparison(): List { 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() object Games : RealmCriteria() object TournamentNames : RealmCriteria() object Locations : RealmCriteria() object TournamentFeatures : RealmCriteria() object TransactionTypes : RealmCriteria() object Limits : ListCriteria() object TableSizes : ListCriteria() object TournamentTypes : ListCriteria() object MonthsOfYear : SimpleCriteria(List(12) { index -> QueryCondition.AnyMonthOfYear().apply { listOfValues = arrayListOf(index) } }) object DaysOfWeek : SimpleCriteria(List(7) { index -> QueryCondition.AnyDayOfWeek().apply { listOfValues = arrayListOf(index + 1) } }) object SessionTypes : SimpleCriteria(listOf(QueryCondition.IsCash, QueryCondition.IsTournament)) object BankrollTypes : SimpleCriteria(listOf(QueryCondition.IsLive, QueryCondition.IsOnline)) object DayPeriods : SimpleCriteria(listOf(QueryCondition.IsWeekDay, QueryCondition.IsWeekEnd)) object Years : ListCriteria() object AllMonthsUpToNow : ListCriteria() object Blinds : ListCriteria() object TournamentFees : ListCriteria() object Cash : SimpleCriteria(listOf(QueryCondition.IsCash)) object Tournament : SimpleCriteria(listOf(QueryCondition.IsTournament)) 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() 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 else -> null } } companion object { 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 ) } } }