# MeasurementsLineChartRenderer.kt

    /*
     * The MIT License
     *
     * Original work sponsored and donated by The Danish Health Data Authority (http://www.sundhedsdatastyrelsen.dk)
     *
     * Copyright (C) 2021 The Danish Health Data Authority (http://www.sundhedsdatastyrelsen.dk)
     *
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy of
     * this software and associated documentation files (the "Software"), to deal in
     * the Software without restriction, including without limitation the rights to
     * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     * of the Software, and to permit persons to whom the Software is furnished to do
     * so, subject to the following conditions:
     *
     *
     * The above copyright notice and this permission notice shall be included in all
     * copies or substantial portions of the Software.
     *
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     */

    package dk.nsp.mingraviditet.ui.main.journal.sections.measurements.chart.renderers

    import android.graphics.Bitmap
    import android.graphics.Canvas
    import android.graphics.Paint
    import android.os.Build
    import com.github.mikephil.charting.animation.ChartAnimator
    import com.github.mikephil.charting.data.Entry
    import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider
    import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
    import com.github.mikephil.charting.renderer.LineChartRenderer
    import com.github.mikephil.charting.utils.Transformer
    import com.github.mikephil.charting.utils.ViewPortHandler

    class MeasurementsLineChartRenderer(
        chart: LineDataProvider?,
        animator: ChartAnimator?,
        viewPortHandler: ViewPortHandler?,
        private val shadowColor: Int
    ) : LineChartRenderer(chart, animator, viewPortHandler) {

        private val circlePointToPixelBuffer = FloatArray(2)

        private val circleShadowRadius = 4f
        private val circleShadowXOffset = 0f
        private val circleShadowYOffset = 1f

        private val circleHolePaint by lazy { Paint(Paint.ANTI_ALIAS_FLAG) }

        private val circlePaint by lazy {
            Paint(circleHolePaint).apply {
                setShadowLayer(
                    circleShadowRadius,
                    circleShadowXOffset,
                    circleShadowYOffset,
                    shadowColor
                )
            }
        }

        override fun drawCircles(canvas: Canvas?) {
            canvas ?: return
            val lineDataSets = mChart.lineData?.dataSets ?: return

            // Reset the point to pixel buffer
            circlePointToPixelBuffer[0] = 0f
            circlePointToPixelBuffer[1] = 0f

            lineDataSets.forEach { lineDataSet ->

                // Update the circle hole color, which is the same for the whole dataset
                circleHolePaint.color = lineDataSet.circleHoleColor

                val transformer = mChart.getTransformer(lineDataSet.axisDependency)

                // Generate bitmaps for data set colors, to not generate a new one each for each point
                val bitmaps = (0 until lineDataSet.circleColorCount).map { index ->
                    // Update the circle color
                    circlePaint.color = lineDataSet.getCircleColor(index)

                    getCircleBitmap(
                        lineDataSet.circleRadius,
                        lineDataSet.circleHoleRadius,
                        circlePaint,
                        circleHolePaint
                    )
                }

                (0 until lineDataSet.entryCount).forEach { i ->
                    lineDataSet.getEntryForIndex(i)?.let {
                        val bitmap = bitmaps[i % bitmaps.size]

                        drawCircleForEntry(
                            canvas,
                            it,
                            bitmap,
                            transformer
                        )
                    }
                }
            }
        }

        /**
         * Draws a circle with a hole on the [canvas] by transforming the data from [entry] to pixels on the canvas
         * using [LineDataProvider.getTransformer] for the transformation according to the [ILineDataSet.getAxisDependency].
         */
        private fun drawCircleForEntry(
            canvas: Canvas,
            entry: Entry,
            bitmap: Bitmap,
            transformer: Transformer
        ) {
            circlePointToPixelBuffer[0] = entry.x
            circlePointToPixelBuffer[1] = entry.y

            // Converts the data points to actual pixel values and replaces then in the given float array
            transformer.pointValuesToPixel(circlePointToPixelBuffer)

            val pixelPosX = circlePointToPixelBuffer[0]
            val pixelPosY = circlePointToPixelBuffer[1]

            val bitmapCenterX = bitmap.height / 2f
            val bitmapCenterY = bitmap.width / 2f

            canvas.drawBitmap(
                bitmap,
                pixelPosX - bitmapCenterX,
                pixelPosY - bitmapCenterY,
                null
            )
        }

        private fun getCircleBitmap(
            circleRadius: Float,
            circleHoleRadius: Float,
            circlePaint: Paint,
            circleHolePaint: Paint
        ): Bitmap {
            // Create a bitmap that can fit the circle and a potential shadow
            val shadowLayerRadius = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                circlePaint.shadowLayerRadius
            } else {
                0f
            }
            val bitmapSize: Int = (circleRadius * 2.1 + shadowLayerRadius * 2).toInt()
            //
            val bitmapCenterX = bitmapSize / 2f
            val bitmapCenterY = bitmapSize / 2f

            val circleBitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888)
            val bitmapCanvas = Canvas(circleBitmap)

            // Draw the "background" part of the circle
            bitmapCanvas.drawCircle(
                bitmapCenterX,
                bitmapCenterY,
                circleRadius,
                circlePaint
            )

            // Draw the "circle hole"
            bitmapCanvas.drawCircle(
                bitmapCenterX,
                bitmapCenterY,
                circleHoleRadius,
                circleHolePaint
            )

            return circleBitmap
        }
    }