package com.kdanmobile.reader.screen.signature

import android.content.Context
import android.graphics.*
import android.graphics.Paint.Cap
import android.support.v4.content.ContextCompat
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View


class SignatureDrawView : View {

    private lateinit var paint: Paint
    private var currentPath: Path? = null
    private val datas = ArrayList<SignaturePathData>()
    var onSignatureDrawListener: OnSignatureDrawListener? = null

    var paintColor: Int = android.R.color.black
    var strokeWidth: Float = 10f

    constructor(context: Context) : super(context) {
        initView()
    }

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

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

    private fun initView() {
        paint = Paint()
        paint.isAntiAlias = true
        paint.style = Paint.Style.STROKE
        paint.strokeCap = Cap.ROUND
        paint.color = ContextCompat.getColor(context, paintColor)
        paint.strokeWidth = strokeWidth
    }

    fun clear() {
        datas.clear()
        invalidate()
        onSignatureDrawListener?.onClearSignature()
    }

    fun getBitmap(): Bitmap {
        val bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)
        draw(Canvas(bitmap))
        return bitmap
    }

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

        for (data in datas) {
            paint.color = data.color
            paint.strokeWidth = data.strokeWidth
            canvas?.drawPath(data.path, paint)
        }
    }

    private var pointList = ArrayList<PointF>()

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (null != event) {
            val actionIndex = event.actionIndex
            val pointerId = event.getPointerId(actionIndex)
            if (pointerId == 0) {
                val x = event.getX(actionIndex)
                val y = event.getY(actionIndex)
                when (event.action) {
                    MotionEvent.ACTION_DOWN -> {
                        currentPath = Path()
                        datas.add(SignaturePathData(currentPath!!, paintColor, strokeWidth))
                        currentPath?.moveTo(x, y)
                        currentPath?.lineTo(x, y)
                        onSignatureDrawListener?.onStartSignature()
                        pointList.add(PointF(x, y))
                    }
                    MotionEvent.ACTION_MOVE -> {
                        var last = pointList.last()
                        pointList.clear()
                        pointList.add(last)
                        val tolerance = 2.5
                        for (i in 0 until event.historySize) {
                            val point = PointF(event.getHistoricalX(i), event.getHistoricalY(i))
                            last = pointList.last()
                            if (Math.abs(point.x - last.x) > tolerance || Math.abs(point.y - last.y) > tolerance) {
                                pointList.add(point)
                            }
                        }
                        pointList.remove(pointList.first())
                        pointList.add(PointF(x, y))
                        var size = pointList.size
                        var count = 0
                        while (size >= 3) {
                            val x0 = pointList[count].x
                            val y0 = pointList[count].y
                            val x1 = pointList[count + 1].x
                            val y1 = pointList[count + 1].y
                            val x2 = pointList[count + 2].x
                            val y2 = pointList[count + 2].y
                            currentPath?.cubicTo(x0, y0, x1, y1, x2, y2)
                            size -= 3
                            count += 3
                        }
                        when (size) {
                            1 -> currentPath?.lineTo(x, y)
                            2 -> currentPath?.quadTo(pointList[count].x, pointList[count].y, x, y)
                            else -> {}
                        }
                    }
                    MotionEvent.ACTION_UP -> {
                        pointList.clear()
                        currentPath = null
                    }
                }
                invalidate()
            }
        }

        return true
    }

    interface OnSignatureDrawListener {
        fun onClearSignature()

        fun onStartSignature()
    }

    data class SignaturePathData(val path: Path, val color: Int, val strokeWidth: Float)
}