|
|
|
|
@ -1,13 +1,18 @@ |
|
|
|
|
package net.pokeranalytics.android.model.utils |
|
|
|
|
|
|
|
|
|
import io.realm.Realm |
|
|
|
|
import io.realm.RealmModel |
|
|
|
|
import io.realm.RealmQuery |
|
|
|
|
import io.realm.RealmResults |
|
|
|
|
import net.pokeranalytics.android.exceptions.ModelException |
|
|
|
|
import net.pokeranalytics.android.model.realm.FlatTimeInterval |
|
|
|
|
import net.pokeranalytics.android.model.realm.Session |
|
|
|
|
import net.pokeranalytics.android.model.realm.SessionSet |
|
|
|
|
import net.pokeranalytics.android.util.extensions.findById |
|
|
|
|
import net.pokeranalytics.android.util.extensions.max |
|
|
|
|
import net.pokeranalytics.android.util.extensions.min |
|
|
|
|
import timber.log.Timber |
|
|
|
|
import java.util.* |
|
|
|
|
|
|
|
|
|
class CorruptSessionSetException(message: String) : Exception(message) |
|
|
|
|
|
|
|
|
|
@ -17,12 +22,25 @@ class CorruptSessionSetException(message: String) : Exception(message) |
|
|
|
|
*/ |
|
|
|
|
object SessionSetManager { |
|
|
|
|
|
|
|
|
|
var sessions: RealmResults<Session> |
|
|
|
|
var sessions: RealmResults<Session>? = null |
|
|
|
|
|
|
|
|
|
private val sessionIdsToProcess = mutableSetOf<String>() |
|
|
|
|
|
|
|
|
|
private var start: Date? = null |
|
|
|
|
private var end: Date? = null |
|
|
|
|
|
|
|
|
|
fun configure() {} // launch init |
|
|
|
|
|
|
|
|
|
fun startChanged(session: Session, date: Date?) { |
|
|
|
|
this.start = min(this.start, date) |
|
|
|
|
this.sessionIdsToProcess.add(session.id) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun endChanged(session: Session, date: Date?) { |
|
|
|
|
this.end = max(this.end, date) |
|
|
|
|
this.sessionIdsToProcess.add(session.id) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun sessionDateChanged(session: Session) { |
|
|
|
|
this.sessionIdsToProcess.add(session.id) |
|
|
|
|
} |
|
|
|
|
@ -31,11 +49,12 @@ object SessionSetManager { |
|
|
|
|
|
|
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
|
|
|
|
|
|
this.sessions = realm.where(Session::class.java).findAllAsync() |
|
|
|
|
this.sessions.addChangeListener { _, _ -> |
|
|
|
|
if (this.sessionIdsToProcess.isNotEmpty()) { |
|
|
|
|
sessions = realm.where(Session::class.java).findAllAsync() |
|
|
|
|
sessions?.addChangeListener { _, _ -> |
|
|
|
|
if (this.start != null && this.end != null) { |
|
|
|
|
realm.executeTransactionAsync { asyncRealm -> |
|
|
|
|
processSessions(asyncRealm) |
|
|
|
|
cleanUp() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -43,21 +62,38 @@ object SessionSetManager { |
|
|
|
|
realm.close() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun cleanUp() { |
|
|
|
|
this.start = null |
|
|
|
|
this.end = null |
|
|
|
|
// this.sessionIdsToProcess.clear() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun processSessions(realm: Realm) { |
|
|
|
|
|
|
|
|
|
Timber.d("***** processSessions, process count = ${sessionIdsToProcess.size}") |
|
|
|
|
// Timber.d("***** processSessions, process count = ${sessionIdsToProcess.size}") |
|
|
|
|
|
|
|
|
|
for (sessionId in this.sessionIdsToProcess) { |
|
|
|
|
realm.findById<Session>(sessionId)?.let { session -> |
|
|
|
|
if (session.startDate != null && session.endDate != null) { |
|
|
|
|
updateTimeline(session) |
|
|
|
|
} else if (session.sessionSet != null) { |
|
|
|
|
removeFromTimeline(session) |
|
|
|
|
} |
|
|
|
|
val start = this.start |
|
|
|
|
val end = this.end |
|
|
|
|
|
|
|
|
|
val sessions = sessionIdsToProcess.mapNotNull { realm.findById<Session>(it) } |
|
|
|
|
for (session in sessions) { |
|
|
|
|
|
|
|
|
|
// Session Sets |
|
|
|
|
val startDate = session.startDate |
|
|
|
|
val endDate = session.endDate |
|
|
|
|
if (startDate != null && endDate != null) { |
|
|
|
|
updateTimeline(session) |
|
|
|
|
} else if (session.sessionSet != null) { |
|
|
|
|
removeFromTimeline(session) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// FlatTimeIntervals |
|
|
|
|
if (start != null && end != null) { |
|
|
|
|
processFlatTimeInterval(realm, start, end) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.sessionIdsToProcess.clear() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
@ -76,25 +112,37 @@ object SessionSetManager { |
|
|
|
|
throw ModelException("End date should never be null here") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
val sessionSets = this.matchingSets(session) |
|
|
|
|
cleanupSessionSets(session, sessionSets) |
|
|
|
|
val start = session.startDate!! |
|
|
|
|
val end = session.endDate!! |
|
|
|
|
|
|
|
|
|
// val sessionId = session.id |
|
|
|
|
// realm.executeTransactionAsync { asyncRealm -> |
|
|
|
|
// asyncRealm.findById<Session>(sessionId)?.let { s -> |
|
|
|
|
// val sessionSets = this.matchingSets(session) |
|
|
|
|
// cleanupSessionSets(session, sessionSets) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
val sessionSets = this.matchingData<SessionSet>(session.realm, start, end) |
|
|
|
|
cleanupSessionSets(session, sessionSets) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun matchingSets(session: Session): RealmResults<SessionSet> { |
|
|
|
|
val realm = session.realm |
|
|
|
|
val endDate = session.endDate!! // tested above |
|
|
|
|
val startDate = session.startDate!! |
|
|
|
|
|
|
|
|
|
val query: RealmQuery<SessionSet> = realm.where(SessionSet::class.java) |
|
|
|
|
// private fun matchingSets(session: Session): RealmResults<SessionSet> { |
|
|
|
|
// val realm = session.realm |
|
|
|
|
// val endDate = session.endDate!! // tested above |
|
|
|
|
// val startDate = session.startDate!! |
|
|
|
|
// |
|
|
|
|
// val query: RealmQuery<SessionSet> = realm.where(SessionSet::class.java) |
|
|
|
|
// |
|
|
|
|
// query |
|
|
|
|
// .lessThanOrEqualTo("startDate", startDate) |
|
|
|
|
// .greaterThanOrEqualTo("endDate", startDate) |
|
|
|
|
// .or() |
|
|
|
|
// .lessThanOrEqualTo("startDate", endDate) |
|
|
|
|
// .greaterThanOrEqualTo("endDate", endDate) |
|
|
|
|
// .or() |
|
|
|
|
// .greaterThanOrEqualTo("startDate", startDate) |
|
|
|
|
// .lessThanOrEqualTo("endDate", endDate) |
|
|
|
|
// |
|
|
|
|
// return query.findAll() |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
private inline fun <reified T : RealmModel> matchingData(realm: Realm, startDate: Date, endDate: Date): RealmResults<T> { |
|
|
|
|
|
|
|
|
|
val query: RealmQuery<T> = realm.where(T::class.java) |
|
|
|
|
|
|
|
|
|
query |
|
|
|
|
.lessThanOrEqualTo("startDate", startDate) |
|
|
|
|
@ -127,7 +175,7 @@ object SessionSetManager { |
|
|
|
|
sessionSets.deleteAllFromRealm() |
|
|
|
|
|
|
|
|
|
allImpactedSessions.forEach { impactedSession -> |
|
|
|
|
val sets = matchingSets(impactedSession) |
|
|
|
|
val sets = matchingData<SessionSet>(impactedSession.realm, impactedSession.startDate!!, impactedSession.endDate!!) |
|
|
|
|
this.updateTimeFrames(sets, impactedSession) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -249,4 +297,155 @@ object SessionSetManager { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun processFlatTimeInterval(realm: Realm, start: Date, end: Date) { |
|
|
|
|
|
|
|
|
|
val sessions = matchingData<Session>(realm, start, end) |
|
|
|
|
val intervalsStore = IntervalsStore(sessions.toSet()) |
|
|
|
|
|
|
|
|
|
intervalsStore.intervals.forEach { it.deleteFromRealm() } |
|
|
|
|
|
|
|
|
|
val intervals = SessionInterval.intervalMap(intervalsStore.sessions) |
|
|
|
|
|
|
|
|
|
for (interval in intervals) { |
|
|
|
|
|
|
|
|
|
val sortedDates = interval.dates.sorted() |
|
|
|
|
for (i in (0 until sortedDates.size - 1)) { |
|
|
|
|
|
|
|
|
|
val s = sortedDates[i] |
|
|
|
|
val e = sortedDates[i + 1] |
|
|
|
|
|
|
|
|
|
val matchingSessions = interval.sessions.filter { |
|
|
|
|
val sd = it.startDate |
|
|
|
|
val ed = it.endDate |
|
|
|
|
(sd != null && ed != null && sd <= s && ed >= e) |
|
|
|
|
} |
|
|
|
|
if (matchingSessions.isNotEmpty()) { |
|
|
|
|
Timber.d("**** Create FTI: $s - $e") |
|
|
|
|
val fti = FlatTimeInterval() |
|
|
|
|
fti.startDate = s |
|
|
|
|
fti.endDate = e |
|
|
|
|
matchingSessions.forEach { it.flatTimeIntervals.add(fti) } |
|
|
|
|
realm.insertOrUpdate(fti) |
|
|
|
|
} else { |
|
|
|
|
Timber.w("The FTI has no sessions") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class IntervalsStore(sessions: Set<Session>) { |
|
|
|
|
|
|
|
|
|
var start: Date = Date() |
|
|
|
|
var end: Date = Date(0L) |
|
|
|
|
|
|
|
|
|
val intervals = mutableSetOf<FlatTimeInterval>() |
|
|
|
|
|
|
|
|
|
val sessions = mutableSetOf<Session>() |
|
|
|
|
|
|
|
|
|
private val sessionIds: MutableSet<String> = mutableSetOf() |
|
|
|
|
|
|
|
|
|
init { |
|
|
|
|
processSessions(sessions) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun processSessions(sessions: Set<Session>) { |
|
|
|
|
this.sessions.addAll(sessions) |
|
|
|
|
for (session in sessions) { |
|
|
|
|
loadIntervals(session) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun loadIntervals(session: Session) { |
|
|
|
|
|
|
|
|
|
if (sessionIds.contains(session.id)) { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
session.startDate?.let { this.start = min(this.start, it) } |
|
|
|
|
session.endDate?.let { this.end = max(this.end, it) } |
|
|
|
|
|
|
|
|
|
this.sessionIds.add(session.id) |
|
|
|
|
|
|
|
|
|
for (fti in session.flatTimeIntervals) { |
|
|
|
|
this.intervals.add(fti) |
|
|
|
|
|
|
|
|
|
fti.sessions?.let { sessions -> |
|
|
|
|
for (s in sessions) { |
|
|
|
|
loadIntervals(s) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class SessionInterval(session: Session) { |
|
|
|
|
|
|
|
|
|
var start: Date |
|
|
|
|
var end: Date? |
|
|
|
|
|
|
|
|
|
var sessions: MutableSet<Session> = mutableSetOf() |
|
|
|
|
val dates: MutableSet<Date> = mutableSetOf() |
|
|
|
|
|
|
|
|
|
val duration: Long |
|
|
|
|
get() { |
|
|
|
|
val endDate = end ?: Date() |
|
|
|
|
return endDate.time - start.time |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
init { |
|
|
|
|
this.start = session.startDate!! |
|
|
|
|
this.end = session.endDate |
|
|
|
|
|
|
|
|
|
this.addSession(session) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun addSession(session: Session) { |
|
|
|
|
this.sessions.add(session) |
|
|
|
|
|
|
|
|
|
session.startDate?.let { this.dates.add(it) } |
|
|
|
|
session.endDate?.let { endDate -> |
|
|
|
|
this.dates.add(endDate) |
|
|
|
|
if (endDate > end) { |
|
|
|
|
end = endDate |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
companion object { |
|
|
|
|
|
|
|
|
|
fun intervalMap(sessions: Set<Session>): List<SessionInterval> { |
|
|
|
|
|
|
|
|
|
val sorted = sessions.sortedBy { it.startDate } |
|
|
|
|
val intervals = mutableListOf<SessionInterval>() |
|
|
|
|
|
|
|
|
|
sorted.firstOrNull()?.let { firstSession -> |
|
|
|
|
|
|
|
|
|
var currentInterval = SessionInterval(firstSession) |
|
|
|
|
intervals.add(currentInterval) |
|
|
|
|
|
|
|
|
|
for (session in sessions.drop(1)) { |
|
|
|
|
val start = session.startDate!! |
|
|
|
|
val currentEnd = currentInterval.end |
|
|
|
|
if (currentEnd != null && start > currentEnd) { |
|
|
|
|
val interval = SessionInterval(session) |
|
|
|
|
currentInterval = interval |
|
|
|
|
intervals.add(interval) |
|
|
|
|
} else { |
|
|
|
|
currentInterval.addSession(session) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
intervals.forEach { |
|
|
|
|
Timber.d("s = ${it.start}, e = ${it.end}") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return intervals |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |