/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.egg.paint

import android.content.Context
import android.content.res.Resources
import android.graphics.*
import android.provider.Settings
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.MotionEvent
import android.view.View
import android.view.WindowInsets
import java.util.concurrent.TimeUnit
import android.util.Log
import android.provider.Settings.System

import org.json.JSONObject

fun hypot(x: Float, y: Float): Float {
    return Math.hypot(x.toDouble(), y.toDouble()).toFloat()
}

fun invlerp(x: Float, a: Float, b: Float): Float {
    return if (b > a) {
        (x - a) / (b - a)
    } else 1.0f
}

public class Painting : View, SpotFilter.Plotter {
    companion object {
        val FADE_MINS = TimeUnit.MINUTES.toMillis(3) // about how long a drawing should last
        val ZEN_RATE = TimeUnit.SECONDS.toMillis(2)  // how often to apply the fade
        val ZEN_FADE = Math.max(1f, ZEN_RATE / FADE_MINS * 255f)

        val FADE_TO_WHITE_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
                1f, 0f, 0f, 0f, ZEN_FADE,
                0f, 1f, 0f, 0f, ZEN_FADE,
                0f, 0f, 1f, 0f, ZEN_FADE,
                0f, 0f, 0f, 1f, 0f
        )))

        val FADE_TO_BLACK_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
                1f, 0f, 0f, 0f, -ZEN_FADE,
                0f, 1f, 0f, 0f, -ZEN_FADE,
                0f, 0f, 1f, 0f, -ZEN_FADE,
                0f, 0f, 0f, 1f, 0f
        )))

        val INVERT_CF = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
                -1f, 0f, 0f, 0f, 255f,
                0f, -1f, 0f, 0f, 255f,
                0f, 0f, -1f, 0f, 255f,
                0f, 0f, 0f, 1f, 0f
        )))

        val TOUCH_STATS = "touch.stats" // Settings.System key
    }

    var devicePressureMin = 0f; // ideal value
    var devicePressureMax = 1f; // ideal value

    var zenMode = true
        set(value) {
            if (field != value) {
                field = value
                removeCallbacks(fadeRunnable)
                if (value && isAttachedToWindow) {
                    handler.postDelayed(fadeRunnable, ZEN_RATE)
                }
            }
        }

    var bitmap: Bitmap? = null
    var paperColor : Int = 0xFFFFFFFF.toInt()

    private var _paintCanvas: Canvas? = null
    private val _bitmapLock = Object()
    
    private var _drawPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var _lastX = 0f
    private var _lastY = 0f
    private var _lastR = 0f
    private var _insets: WindowInsets? = null

    private var _brushWidth = 100f

    private var _filter = SpotFilter(10, 0.5f, 0.9f, this)

    private val fadeRunnable = object : Runnable {
        private val pt = Paint()
        override fun run() {
            val c = _paintCanvas
            if (c != null) {
                pt.colorFilter =
                    if (paperColor.and(0xFF) > 0x80)
                        FADE_TO_WHITE_CF
                    else
                        FADE_TO_BLACK_CF

                synchronized(_bitmapLock) {
                    c.drawBitmap(bitmap, 0f, 0f, pt)
                }
                invalidate()
            }
            postDelayed(this, ZEN_RATE)
        }
    }

    constructor(context: Context) : super(context) {
        init(null, 0)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init(attrs, 0)
    }

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
        init(attrs, defStyle)
    }

    private fun init(attrs: AttributeSet?, defStyle: Int) {
        loadDevicePressureData()
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()

        setupBitmaps()

        if (zenMode) {
            handler.postDelayed(fadeRunnable, ZEN_RATE)
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        setupBitmaps()
    }

    override fun onDetachedFromWindow() {
        if (zenMode) {
            removeCallbacks(fadeRunnable)
        }
        super.onDetachedFromWindow()
    }

    fun onTrimMemory() {
    }

    override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
        _insets = insets
        if (insets != null && _paintCanvas == null) {
            setupBitmaps()
        }
        return super.onApplyWindowInsets(insets)
    }

    private fun powf(a: Float, b: Float): Float {
        return Math.pow(a.toDouble(), b.toDouble()).toFloat()
    }

    override fun plot(s: MotionEvent.PointerCoords) {
        val c = _paintCanvas
        if (c == null) return
        synchronized(_bitmapLock) {
            var x = _lastX
            var y = _lastY
            var r = _lastR
            val newR = Math.max(1f, powf(adjustPressure(s.pressure), 2f).toFloat() * _brushWidth)

            if (r >= 0) {
                val d = hypot(s.x - x, s.y - y)
                if (d > 1f && (r + newR) > 1f) {
                    val N = (2 * d / Math.min(4f, r + newR)).toInt()

                    val stepX = (s.x - x) / N
                    val stepY = (s.y - y) / N
                    val stepR = (newR - r) / N
                    for (i in 0 until N - 1) { // we will draw the last circle below
                        x += stepX
                        y += stepY
                        r += stepR
                        c.drawCircle(x, y, r, _drawPaint)
                    }
                }
            }

            c.drawCircle(s.x, s.y, newR, _drawPaint)
            _lastX = s.x
            _lastY = s.y
            _lastR = newR
        }
    }

    private fun loadDevicePressureData() {
        try {
            val touchDataJson = Settings.System.getString(context.contentResolver, TOUCH_STATS)
            val touchData = JSONObject(
                    if (touchDataJson != null) touchDataJson else "{}")
            if (touchData.has("min")) devicePressureMin = touchData.getDouble("min").toFloat()
            if (touchData.has("max")) devicePressureMax = touchData.getDouble("max").toFloat()
            if (devicePressureMin < 0) devicePressureMin = 0f
            if (devicePressureMax < devicePressureMin) devicePressureMax = devicePressureMin + 1f
        } catch (e: Exception) {
        }
    }

    private fun adjustPressure(pressure: Float): Float {
        if (pressure > devicePressureMax) devicePressureMax = pressure
        if (pressure < devicePressureMin) devicePressureMin = pressure
        return invlerp(pressure, devicePressureMin, devicePressureMax)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        val c = _paintCanvas
        if (event == null || c == null) return super.onTouchEvent(event)

        /*
        val pt = Paint(Paint.ANTI_ALIAS_FLAG)
        pt.style = Paint.Style.STROKE
        pt.color = 0x800000FF.toInt()
        _paintCanvas?.drawCircle(event.x, event.y, 20f, pt)
        */

        when (event.actionMasked) {
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                _filter.add(event)
                _filter.finish()
                invalidate()
            }

            MotionEvent.ACTION_DOWN -> {
                _lastR = -1f
                _filter.add(event)
                invalidate()
            }

            MotionEvent.ACTION_MOVE -> {
                _filter.add(event)

                invalidate()
            }
        }

        return true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        bitmap?.let {
            canvas.drawBitmap(bitmap, 0f, 0f, _drawPaint);
        }
    }

    // public api
    fun clear() {
        bitmap = null
        setupBitmaps()
        invalidate()
    }

    fun sampleAt(x: Float, y: Float): Int {
        val localX = (x - left).toInt()
        val localY = (y - top).toInt()
        return bitmap?.getPixel(localX, localY) ?: Color.BLACK
    }

    fun setPaintColor(color: Int) {
        _drawPaint.color = color
    }

    fun getPaintColor(): Int {
        return _drawPaint.color
    }

    fun setBrushWidth(w: Float) {
        _brushWidth = w
    }

    fun getBrushWidth(): Float {
        return _brushWidth
    }

    private fun setupBitmaps() {
        val dm = DisplayMetrics()
        display.getRealMetrics(dm)
        val w = dm.widthPixels
        val h = dm.heightPixels
        val oldBits = bitmap
        var bits = oldBits
        if (bits == null || bits.width != w || bits.height != h) {
            bits = Bitmap.createBitmap(
                    w,
                    h,
                    Bitmap.Config.ARGB_8888
            )
        }
        if (bits == null) return

        val c = Canvas(bits)

        if (oldBits != null) {
            if (oldBits.width < oldBits.height != bits.width < bits.height) {
                // orientation change. let's rotate things so they fit better
                val matrix = Matrix()
                if (bits.width > bits.height) {
                    // now landscape
                    matrix.postRotate(-90f)
                    matrix.postTranslate(0f, bits.height.toFloat())
                } else {
                    // now portrait
                    matrix.postRotate(90f)
                    matrix.postTranslate(bits.width.toFloat(), 0f)
                }
                if (bits.width != oldBits.height || bits.height != oldBits.width) {
                    matrix.postScale(
                            bits.width.toFloat()/oldBits.height,
                            bits.height.toFloat()/oldBits.width)
                }
                c.matrix = matrix
            }
            // paint the old artwork atop the new
            c.drawBitmap(oldBits, 0f, 0f, _drawPaint)
            c.matrix = Matrix()
        } else {
            c.drawColor(paperColor)
        }

        bitmap = bits
        _paintCanvas = c
    }

    fun invertContents() {
        val invertPaint = Paint()
        invertPaint.colorFilter = INVERT_CF
        synchronized(_bitmapLock) {
            _paintCanvas?.drawBitmap(bitmap, 0f, 0f, invertPaint)
        }
        invalidate()
    }
}

