package com.wdkl.ncs.android.lib.widget

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.*
import android.os.Looper
import android.text.TextPaint
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import com.wdkl.ncs.android.lib.R

class ProgressView :View{

    private var mPaint: Paint? = null
    private var mTextPaint: TextPaint? = null

    private var mRadius: Int
    private var mBorderColor: Int
    private var mProgressColor: Int = 0
    private var mProgressDescColor: Int
    private var mMax: Int = 0
    private var mProgress: Int = 0
    private var mBorderWidth: Int
    private var mIsShowDesc: Boolean = false
    private var mHaveChangeColor: Boolean = false

    private val DEFAULT_MAX = 10
    private val DEFAULT_PROGRESS = 0
    var changeColor = arrayOf("#CDFDCB", "#65FDCC", "#65FDCC", "#55CA7C", "#55CA7C", "#52CD53", "#52CD53", "#52CD53", "#3D9A5C", "#3D9A5C")

    private val DEFAULT_RADIUS = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, 5f, resources.displayMetrics).toInt()
    private val DEFAULT_BORDER_COLOR = Color.parseColor("#FD0005")
    private val DEFAULT_PROGRESS_COLOR = Color.parseColor("#77D178")
    private val DEFAULT_PROGRESS_DESC_COLOR = Color.parseColor("#000000")
    private val DEFAULT_BORDER_WIDTH = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f, resources.displayMetrics).toInt()
    private val DEFAULT_ISSHOWDESC = true

    private var mWidth: Int = 0
    private var mHeight: Int = 0
    private var mTextBounds: Rect? = null
    private var mProgressDesc: String? = ""

    private var mOnFinishedListener: OnFinishedListener? = null
    private var mOnAnimationEndListener: OnAnimationEndListener? = null

    constructor(context: Context): this(context, null)

    constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.ProgressView)
        mMax = a.getInt(R.styleable.ProgressView_max, DEFAULT_MAX)
        mProgress = a.getInt(R.styleable.ProgressView_progress, DEFAULT_PROGRESS)
        mRadius = a.getDimension(R.styleable.ProgressView_progressRadius, DEFAULT_RADIUS.toFloat()).toInt()
        mBorderColor = a.getColor(R.styleable.ProgressView_borderColor, DEFAULT_BORDER_COLOR)
        mProgressColor = a.getColor(R.styleable.ProgressView_progressColor, DEFAULT_PROGRESS_COLOR)
        mProgressDescColor = a.getColor(R.styleable.ProgressView_progressDescColor, DEFAULT_PROGRESS_DESC_COLOR)
        mBorderWidth = a.getDimension(R.styleable.ProgressView_borderWidth, DEFAULT_BORDER_WIDTH.toFloat()).toInt()
        mProgressDesc = a.getString(R.styleable.ProgressView_progressDesc)
        mIsShowDesc = a.getBoolean(R.styleable.ProgressView_isShowDesc, DEFAULT_ISSHOWDESC)
        mHaveChangeColor = a.getBoolean(R.styleable.ProgressView_haveChangeColor, true)
        a.recycle()
        init()
    }

    private fun init() {
        mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mTextBounds = Rect()
        mTextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)
        mTextPaint!!.textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12f, resources.displayMetrics)
        mTextPaint!!.color = mProgressDescColor
    }

    /**
     * 设置结束监听
     *
     * @param onFinishedListener
     */
    fun setOnFinishedListener(onFinishedListener: OnFinishedListener) {
        mOnFinishedListener = onFinishedListener
    }

    /**
     * 设置进度停止监听
     *
     * @param onAnimationEndListener
     */
    fun setOnAnimationEndListener(onAnimationEndListener: OnAnimationEndListener) {
        mOnAnimationEndListener = onAnimationEndListener
    }

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

    override fun onDraw(canvas: Canvas) {
        drawBorder(canvas)
        drawProgress(canvas)
        if (mIsShowDesc) drawProgressDesc(canvas)
    }

    private fun drawBorder(canvas: Canvas) {
        mPaint!!.reset()
        mPaint!!.style = Paint.Style.STROKE
        mPaint!!.strokeJoin = Paint.Join.MITER
        mPaint!!.isAntiAlias = true
        mPaint!!.color = mBorderColor
        mPaint!!.strokeWidth = mBorderWidth.toFloat()

        val left = mBorderWidth / 2
        val top = mBorderWidth / 2
        val right = mWidth - mBorderWidth / 2
        val bottom = mHeight - mBorderWidth / 2

        val path = Path()
        path.moveTo((left + mRadius).toFloat(), top.toFloat())
        path.lineTo((right - mRadius).toFloat(), top.toFloat())
        path.arcTo(RectF((right - 2 * mRadius).toFloat(), top.toFloat(), right.toFloat(), (top + 2 * mRadius).toFloat()), -90f, 90f)
        path.lineTo(right.toFloat(), (bottom - mRadius).toFloat())
        path.arcTo(RectF((right - 2 * mRadius).toFloat(), (bottom - 2 * mRadius).toFloat(), right.toFloat(), bottom.toFloat()), 0f, 90f)
        path.lineTo((left + mRadius).toFloat(), bottom.toFloat())
        path.arcTo(RectF(left.toFloat(), (bottom - 2 * mRadius).toFloat(), (left + 2 * mRadius).toFloat(), bottom.toFloat()), 90f, 90f)
        path.lineTo(left.toFloat(), (top + mRadius).toFloat())
        path.arcTo(RectF(left.toFloat(), top.toFloat(), (left + 2 * mRadius).toFloat(), (top + 2 * mRadius).toFloat()), 180f, 90f)
        path.close()
        canvas.drawPath(path, mPaint!!)
    }

    private fun drawProgress(canvas: Canvas) {

        mPaint!!.reset()
        mPaint!!.style = Paint.Style.FILL
        mPaint!!.isAntiAlias = true
        mPaint!!.color = mProgressColor
        mPaint!!.strokeWidth = mBorderWidth.toFloat()

        val left = mBorderWidth * .5f
        val top = mBorderWidth * .5f
        val right = mWidth - mBorderWidth * .5f
        val bottom = mHeight - mBorderWidth * .5f

        val path = Path()
        path.moveTo(left, top + mRadius)
        val scale = mProgress * 1f / mMax / (mRadius * 1f / (right - left))
        val scale2 = mProgress * 1f / mMax / ((right - mRadius) * 1f / (right - left))
        if (scale <= 1) {
            val a = scale * mRadius
            val angle = Math.acos(((mRadius - a) / mRadius).toDouble())
            path.arcTo(RectF(left, top, left + 2 * mRadius, top + 2 * mRadius), 180f, (angle * 180 / Math.PI).toFloat())
            val y = (Math.pow(Math.pow(mRadius.toDouble(), 2.0) - Math.pow((a - mRadius).toDouble(), 2.0), 0.5) + bottom - mRadius).toFloat()
            path.lineTo(left + a, y)
            path.arcTo(RectF(left, bottom - 2 * mRadius, left + 2 * mRadius, bottom), 180 - (angle * 180 / Math.PI).toFloat(),
                    (angle * 180 / Math.PI).toFloat())
            path.close()
            canvas.drawPath(path, mPaint!!)
        } else if (scale2 <= 1) {
            path.arcTo(RectF(left, top, left + 2 * mRadius, top + 2 * mRadius), 180f, 90f)
            path.lineTo(left + mProgress * 1f / mMax * (right - left), top)
            path.lineTo(left + mProgress * 1f / mMax * (right - left), bottom)
            path.lineTo(left + mRadius, bottom)
            path.arcTo(RectF(left, bottom - 2 * mRadius, left + 2 * mRadius, bottom), 90f, 90f)
            path.close()
            canvas.drawPath(path, mPaint!!)
        } else {
            val a = mProgress * 1f / mMax * (right - left) - (right - mRadius)
            val angle = Math.asin((a / mRadius).toDouble())
            path.arcTo(RectF(left, top, left + 2 * mRadius, top + 2 * mRadius), 180f, 90f)
            path.lineTo(right - mRadius, top)
            path.arcTo(RectF(right - 2 * mRadius, top, right, top + 2 * mRadius), -90f, (angle * 180 / Math.PI).toFloat())
            val y = Math.pow(Math.pow(mRadius.toDouble(), 2.0) - Math.pow(a.toDouble(), 2.0), .5) + top.toDouble() + mRadius.toDouble()

            path.lineTo(right - mRadius + a, y.toFloat())
            path.arcTo(RectF(right - 2 * mRadius, bottom - 2 * mRadius,
                    right, bottom), (90 - angle * 180 / Math.PI).toFloat(),
                    (angle * 180 / Math.PI).toFloat())
            path.lineTo(left + mRadius, bottom)
            path.arcTo(RectF(left, bottom - 2 * mRadius,
                    left + 2 * mRadius, bottom), 90f, 90f)
            path.close()

            canvas.drawPath(path, mPaint!!)
        }
    }

    private fun drawProgressDesc(canvas: Canvas) {
        var finalProgressDesc = ""
        if (100 == mMax) {
            finalProgressDesc = "$mProgressDesc$mProgress %"
        } else {
            finalProgressDesc = "$mProgressDesc$mProgress/$mMax"
        }
        mTextPaint!!.getTextBounds(finalProgressDesc, 0, finalProgressDesc.length, mTextBounds)
        canvas.drawText(finalProgressDesc, (mWidth / 2.0 - mTextBounds!!.width() / 2.0).toInt().toFloat(), (mHeight / 2.0 - (mTextPaint!!.ascent() + mTextPaint!!.descent()) / 2.0f).toInt().toFloat(), mTextPaint!!)
    }


    private fun setProgress(progress: Int) {

        mProgress = if (progress > mMax) mMax else progress
        invalidateView()

        if (mProgress >= mMax && mOnFinishedListener != null) {
            mOnFinishedListener!!.onFinish()
        }

    }

    /**
     * 得到ProgressBar的最大进度
     *
     * @return
     */
    fun getMax(): Int {
        return mMax
    }

    /**
     * 获取当前ProgressBar的进度
     *
     * @return
     */
    fun getProgress(): Int {
        return mProgress
    }

    fun setMaxProgress(max: Int) {
        this.mMax = if (max < 0) 0 else max
        invalidateView()
    }

    fun setProgressDesc(desc: String) {
        mProgressDesc = desc
        invalidateView()
    }

    /**
     * 设置当前进度条的进度(默认动画时间1.5s)
     *
     * @param progress
     */
    fun setCurProgress(progress: Int) {
        if (mHaveChangeColor) {
            setProgressColor(getProgressChangeColor(progress.toFloat() / mMax.toFloat()))
        } else {
            setProgressColor(DEFAULT_PROGRESS_COLOR)
        }
        val animator = ObjectAnimator.ofInt(this, "progress", progress).setDuration(0)
        animator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                super.onAnimationEnd(animation)
                if (mOnAnimationEndListener != null) {
                    mOnAnimationEndListener!!.onAnimationEnd()
                }
            }
        })
        animator.start()
    }

    /**
     * 设置当前进度条的进度
     *
     * @param progress 目标进度
     * @param duration 动画时长
     */
    fun setCurProgress(progress: Int, duration: Long) {
        if (mHaveChangeColor) {
            setProgressColor(getProgressChangeColor(progress.toFloat() / mMax.toFloat()))
        } else {
            setProgressColor(DEFAULT_PROGRESS_COLOR)
        }
        val animator = ObjectAnimator.ofInt(this, "progress", progress).setDuration(duration)
        animator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                super.onAnimationEnd(animation)
                if (mOnAnimationEndListener != null) {
                    mOnAnimationEndListener!!.onAnimationEnd()
                }
            }
        })
        animator.start()
    }

    private fun getProgressChangeColor(percentage: Float): Int {
        if (0 < percentage && percentage <= 0.1) {
            return Color.parseColor(changeColor[0])
        } else if (0.1 < percentage && percentage <= 0.2) {
            return Color.parseColor(changeColor[1])
        } else if (0.2 < percentage && percentage <= 0.3) {
            return Color.parseColor(changeColor[2])
        } else if (0.3 < percentage && percentage <= 0.4) {
            return Color.parseColor(changeColor[3])
        } else if (0.4 < percentage && percentage <= 0.5) {
            return Color.parseColor(changeColor[4])
        } else if (0.5 < percentage && percentage <= 0.6) {
            return Color.parseColor(changeColor[5])
        } else if (0.6 < percentage && percentage <= 0.7) {
            return Color.parseColor(changeColor[6])
        } else if (0.7 < percentage && percentage <= 0.8) {
            return Color.parseColor(changeColor[7])
        } else if (0.8 < percentage && percentage <= 0.9) {
            return Color.parseColor(changeColor[8])
        } else if (0.9 < percentage && percentage <= 1.0) {
            return Color.parseColor(changeColor[9])
        }
        return DEFAULT_PROGRESS_COLOR
    }

    /**
     * 设置ProgressBar的颜色
     *
     * @param color
     */
    fun setProgressColor(color: Int) {
        mProgressColor = color
        invalidateView()
    }

    /**
     * 设置是否显示当前进度
     *
     * @param isShowDesc true:显示
     */
    fun setIsShowDesc(isShowDesc: Boolean) {
        mIsShowDesc = isShowDesc
        invalidateView()
    }

    /**
     * 设置是否需要颜色渐变
     */
    fun setHaveChangeColor(haveChangeColor: Boolean) {
        mHaveChangeColor = haveChangeColor
        invalidateView()
    }

    private fun invalidateView() {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            invalidate()
        } else {
            postInvalidate()
        }
    }

    interface OnFinishedListener {
        fun onFinish()
    }

    interface OnAnimationEndListener {
        fun onAnimationEnd()
    }
}