package golf.handicap.hibernate import dmo.fs.utils.ColorUtilConstants import dmo.fs.utils.Err import golf.handicap.Golfer import golf.handicap.hibernate.db.PopulateGolferScores import golf.handicap.hibernate.db.PopulateGolferScores.Companion.RatingKey import golf.handicap.hibernate.db.PopulateCourse.Companion.CourseRating import io.reactivex.rxjava3.observables.GroupedObservable import io.smallrye.mutiny.Uni import io.vertx.core.json.JsonArray import io.vertx.core.json.JsonObject import io.vertx.mutiny.core.Promise import org.hibernate.reactive.mutiny.Mutiny import java.math.BigDecimal import java.math.RoundingMode import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.* import java.util.logging.Logger class HandicapHibernate { companion object { val LOGGER: Logger = Logger.getLogger(HandicapHibernate::class.java.name) } private var diffKeys = Array(20) { " " } private var diffScores = FloatArray(20) { -100f } private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") private var usedClass: Used? = null var dateTime: Date? = null var index = intArrayOf(0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10) var multiple = .96.toFloat() var used: MutableMap = HashMap() var key: String = String() fun getHandicap(golfer: Golfer, session: Mutiny.Session): Uni> { val handicapPromise = Promise.promise>() val averageSlope = 113 val golferScores = PopulateGolferScores() var numberOfScores = -1 var adjusted: Float var rating: Float var slope: Float var difference: Float var handicapDifferential: Float var handicap: BigDecimal val latestTee: MutableMap = HashMap() golferScores.getGolferScores(golfer, session).onItemOrFailure().invoke { map, err -> if (err != null) { LOGGER.severe("${Err.displayErr(76)} -- ${err.message} -- $map") } if (map.isEmpty()) { latestTee["handicap"] = 0.0f handicapPromise.complete(latestTee) } else { val dataArray: JsonArray = map["array"] as JsonArray val objects = dataArray.iterator() var i = 0 if (!(map["array"] as JsonArray).isEmpty) { do { val jsonObject: JsonObject = objects.next() as JsonObject if (jsonObject.getValue(RatingKey.ADJUSTED.entry) != null) { // val adjust = jsonObject.getString(RatingKey.ADJUSTED.entry).toInt() adjusted = jsonObject.getString(RatingKey.ADJUSTED.entry).toFloat() rating = jsonObject.getString(RatingKey.RATING.entry).toFloat() slope = jsonObject.getString(RatingKey.SLOPE.entry).toFloat() difference = adjusted - rating handicapDifferential = averageSlope * difference / slope // Used to calculate Net Score if (i == 0) { latestTee[CourseRating.ADJUSTED.entry] = adjusted latestTee[CourseRating.RATING.entry] = rating latestTee[CourseRating.SLOPE.entry] = slope latestTee[CourseRating.PAR.entry] = jsonObject.getString(RatingKey.PAR.entry).toInt() } var foundZero = false for (x in 0..19) { if (diffScores[x] == -100.0f) { diffScores[x] = handicapDifferential foundZero = true break } } if (!foundZero && handicapDifferential < diffScores[19]) { diffScores[19] = handicapDifferential } Arrays.sort(diffScores) val localDateTime = LocalDateTime.parse(jsonObject.getString(RatingKey.TIME.entry)) key = handicapDifferential.toString() + '\t' + formatter.format( localDateTime ) key = if (key.indexOf('.') == 1) "0$key" else key diffKeys[i] = key used[key] = Used( jsonObject.getString(RatingKey.PIN.entry), jsonObject.getString(RatingKey.SEQ.entry).toInt(), jsonObject.getString(RatingKey.TIME.entry) ) if (numberOfScores < 19) numberOfScores++ i++ } } while (objects.hasNext()) Arrays.sort(diffKeys) handicap = calculateHandicap(numberOfScores) golfer.handicap = handicap.toDouble() golferScores.setGolferHandicap(golfer, session).onItemOrFailure().invoke { _, err -> if (err != null) { LOGGER.severe("${Err.displayErr(90)} ${err.message}") } var iterated = 0 var rowsUpdated = 0 usedClass = used[diffKeys[19]] golferScores.clearUsed(usedClass!!.pin, session).onItemOrFailure().invoke { count, err -> if (err != null) { LOGGER.severe("${Err.displayErr(91)}${err.message}") } rowsUpdated += count GroupedObservable.fromIterable(diffKeys.reversed().toMutableList()) .doOnError { err -> err.printStackTrace() handicapPromise.complete(latestTee) throw RuntimeException(err.message) }.doOnEach { diffKeyN -> var diffKey = diffKeyN.value if (diffKey == null) { diffKey = "" } usedClass = used[diffKey] if (usedClass != null && usedClass!!.used && diffKey != "") { golferScores.setUsed( usedClass!!.pin, usedClass!!.course!!, usedClass!!.teeTime, session ).onItemOrFailure().invoke { usedCount, err -> if (err != null) { LOGGER.severe( String.format( Err.displayErr(92), ColorUtilConstants.RED, err.message, ColorUtilConstants.RESET ) ) } iterated++ rowsUpdated += usedCount latestTee["handicap"] = handicap.toFloat() if (iterated > diffKeys.size) { handicapPromise.complete(latestTee) } } .subscribeAsCompletionStage() } else { iterated++ if (iterated > diffKeys.size) { latestTee["handicap"] = handicap.toFloat() handicapPromise.complete(latestTee) } } }.subscribe() }.subscribeAsCompletionStage() }.subscribeAsCompletionStage() } else { latestTee["handicap"] = 0.0.toFloat() handicapPromise.complete(latestTee) } } }.subscribeAsCompletionStage() return handicapPromise.future() } private fun calculateHandicap(numberOfScores: Int): BigDecimal { if (diffScores[15] == -100.0f) return BigDecimal(0.0) var total = 0.0.toFloat() var i = 0 val j = index[numberOfScores] while (i < j) { total += diffScores[19 - numberOfScores + i] setUsed(diffKeys[19 - numberOfScores + i]) i++ } total = total / index[numberOfScores] * multiple return BigDecimal(total.toString()).setScale(1, RoundingMode.DOWN) } private fun setUsed(diffKey: String) { usedClass = used[diffKey] if (usedClass != null) { usedClass!!.used = true used[diffKey] = usedClass as Used } } inner class Used(var pin: String?, var course: Int?, var teeTime: String) { var used = false override fun toString(): String { return StringBuffer().append(pin).append(" ").append(course).append(" ") .append(teeTime).append(" ").append(used) .toString() } } }