package com.kdanmobile.reader.screen.reader.mediabox

import android.animation.*
import android.content.Context
import android.graphics.Color
import android.support.constraint.ConstraintLayout
import android.support.v4.content.ContextCompat
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.View.OnClickListener
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.ImageButton
import com.kdanmobile.reader.R
import com.kdanmobile.reader.screen.reader.mediabox.common.MediaBoxHeader
import com.kdanmobile.reader.screen.reader.mediabox.shape.ShapeTabView
import com.kdanmobile.reader.screen.reader.mediabox.signature.SignatureTabView
import com.kdanmobile.reader.screen.reader.mediabox.stamp.StampTabView
import com.kdanmobile.reader.screen.reader.mediabox.textbox.TextBoxStyleView
import com.kdanmobile.reader.screen.reader.mediabox.textbox.TextBoxTabView
import kotlinx.android.synthetic.main.view_media_box.view.*
import kotlinx.android.synthetic.main.view_media_box_tab.view.*

class MediaBoxView @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
): ConstraintLayout(context, attrs, defStyleAttr) {

    private companion object {
        const val COLOR_DISMISS = Color.TRANSPARENT
        val COLOR_SHOW = Color.parseColor("#42000000")
        const val DEFAULT_DURATION_ANIMATION = 300L
    }

    enum class MediaBoxTabType {
        NONE, TEXT_BOX, SIGNATURE, STAMP, SHAPE, FORM, TEXT_BOX_STYLE
    }

    var onShowListener: Runnable? = null
    var onDismissListener: Runnable? = null
    var animationDuration = DEFAULT_DURATION_ANIMATION

    private var mediaBoxAnimator: ObjectAnimator? = null
    private var maskAnimator: ValueAnimator? = null
    private var cacheView: View? = null
    private var tabType = MediaBoxTabType.NONE
    private var selected: ImageButton? = null
    var onClickAddButtonListener: OnClickHeaderButtonListener? = null

    init {
        LayoutInflater.from(context).inflate(R.layout.view_media_box, this)
        visibility = View.INVISIBLE
        setupTabView()

        /** Set empty listener to prevent dismissing by clicking box **/
        view_mediaBox_dialog.setOnClickListener {}

        /** Move media box view to bottom of parent(hide it) **/
        val size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
        val v = view_mediaBox_dialog
        v.measure(size, size)
        v.y = v.top + v.measuredHeight.toFloat()
    }

    fun showTextBoxStyleView() {
        if (viewGroup_mediaBox_pageContainer.childCount > 0) {
            cacheView = viewGroup_mediaBox_pageContainer.getChildAt(0)
            viewGroup_mediaBox_pageContainer.removeAllViews()
        }
        val textBoxStyleView = TextBoxStyleView(context)
        val params = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
        viewGroup_mediaBox_pageContainer.addView(textBoxStyleView, params)
        textBoxStyleView.onMediaBoxHeaderClickListener = object: MediaBoxHeader.OnTitleButtonClickListener {
            override fun onTitleButtonClick() {
                onClickAddButtonListener?.onClickTextBoxStyleApplyButton(textBoxStyleView)
            }
        }
        show()
    }

    private fun showLeftSideTabView() {
        mediaBoxTabView_mediaBox_tab.visibility = View.VISIBLE
    }

    private fun hideLeftSideTabView() {
        mediaBoxTabView_mediaBox_tab.visibility = View.GONE
    }

    fun show() {
        visibility = View.VISIBLE
        setOnClickListener { dismiss(true) }
        post {
            showMaskWithAnimation()
            showMediaBoxWithAnimation()
        }
        onShowListener?.run()
    }

    fun dismiss(fromUser: Boolean = true) {
        setOnClickListener(null)
        hideMaskWithAnimation()
        hideMediaBoxWithAnimation()
        if (fromUser) {
            onDismissListener?.run()
        }
    }

    private fun showMaskWithAnimation() {
        maskAnimator?.cancel()
        val from = maskAnimator?.animatedValue ?: COLOR_DISMISS
        val to = COLOR_SHOW
        maskAnimator = ValueAnimator.ofObject(ArgbEvaluator(), from, to).apply {
            duration = DEFAULT_DURATION_ANIMATION
            interpolator = AccelerateDecelerateInterpolator()
            addUpdateListener {
                setBackgroundColor(it.animatedValue as Int)
            }
            start()
        }
    }

    private fun hideMaskWithAnimation() {
        maskAnimator?.cancel()
        val from = maskAnimator?.animatedValue ?: COLOR_SHOW
        val to = COLOR_DISMISS
        maskAnimator = ValueAnimator.ofObject(ArgbEvaluator(), from, to).apply {
            duration = DEFAULT_DURATION_ANIMATION
            interpolator = AccelerateDecelerateInterpolator()
            addUpdateListener {
                setBackgroundColor(it.animatedValue as Int)
            }
            start()
        }
    }

    private fun showMediaBoxWithAnimation() {
        mediaBoxAnimator?.cancel()
        val v = view_mediaBox_dialog
        v.visibility = View.VISIBLE
        val from = v.y
        val to = v.top.toFloat()
        val holder = PropertyValuesHolder.ofFloat("Y", from, to)
        mediaBoxAnimator = ObjectAnimator.ofPropertyValuesHolder(v, holder).apply {
            interpolator = AccelerateDecelerateInterpolator()
            duration = animationDuration
            addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationStart(animation: Animator?) {
                    super.onAnimationStart(animation)
                    if (null != cacheView) {
                        hideLeftSideTabView()
                    }
                }

                override fun onAnimationEnd(animation: Animator?) {
                    super.onAnimationEnd(animation)
                    removeListener(this)
                }
            })
            start()
        }
    }

    private fun hideMediaBoxWithAnimation() {
        mediaBoxAnimator?.cancel()
        val v = view_mediaBox_dialog
        val from = v.y
        val to = v.top.toFloat() + v.height
        val holder = PropertyValuesHolder.ofFloat("Y", from, to)
        mediaBoxAnimator = ObjectAnimator.ofPropertyValuesHolder(v, holder).apply {
            interpolator = AccelerateDecelerateInterpolator()
            duration = animationDuration
            addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator?) {
                    super.onAnimationEnd(animation)
                    removeListener(this)
                    v.visibility = View.INVISIBLE
                    this@MediaBoxView.visibility = View.GONE

                    if (null != cacheView) {
                        viewGroup_mediaBox_pageContainer.removeAllViews()
                        viewGroup_mediaBox_pageContainer.addView(cacheView)
                        cacheView = null
                        showLeftSideTabView()
                    }
                }
            })
            start()
        }
    }

    private fun setupTabView() {
        mediaBoxTabView_mediaBox_tab.onClickListenerTabTextBox = OnClickListener(this::setupTextBoxView)
        mediaBoxTabView_mediaBox_tab.onClickListenerTabSignature = OnClickListener(this::setupSignatureView)
        mediaBoxTabView_mediaBox_tab.onClickListenerTabStamp = OnClickListener(this::setupStampView)
        mediaBoxTabView_mediaBox_tab.onClickListenerTabShape = OnClickListener(this::setupShapeView)
        mediaBoxTabView_mediaBox_tab.onClickListenerTabForm = OnClickListener(this::setupFormView)

        setupTextBoxView(ib_mediaBoxTab_textBox)
    }

    private fun getButtonDrawable(tabType: MediaBoxTabType, isSelected: Boolean): Int {
        return when (tabType) {
            MediaBoxTabType.NONE, MediaBoxTabType.TEXT_BOX, MediaBoxTabType.TEXT_BOX_STYLE ->
                if (isSelected) R.drawable.ic_textbox_selected else R.drawable.ic_textbox
            MediaBoxTabType.SIGNATURE ->
                if (isSelected) R.drawable.ic_signature_selected else R.drawable.ic_signature
            MediaBoxTabType.STAMP ->
                if (isSelected) R.drawable.ic_stamp_selected else R.drawable.ic_stamp
            MediaBoxTabType.SHAPE ->
                if (isSelected) R.drawable.ic_shape_selected else R.drawable.ic_shape
            MediaBoxTabType.FORM ->
                if (isSelected) R.drawable.ic_form_selected else R.drawable.ic_form
        }
    }

    private fun setupContent(button: ImageButton, tabType: MediaBoxTabType): Boolean {
        var changed = false
        if (this.tabType != tabType) {
            selected?.setImageDrawable(ContextCompat.getDrawable(context, getButtonDrawable(this.tabType, false)))
            this.tabType = tabType
            selected = button
            button.setImageDrawable(ContextCompat.getDrawable(context, getButtonDrawable(this.tabType, true)))

            viewGroup_mediaBox_pageContainer.removeAllViews()
            changed = true
        }
        return changed
    }

    private fun setupTextBoxView(view: View) {
        val changed = setupContent(view as ImageButton, MediaBoxTabType.TEXT_BOX)
        if (changed) {
            val textBoxTabView = TextBoxTabView(context)
            val params = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
            viewGroup_mediaBox_pageContainer.addView(textBoxTabView, params)
            textBoxTabView.onMediaBoxHeaderClickListener = object: MediaBoxHeader.OnTitleButtonClickListener {
                override fun onTitleButtonClick() {
                    onClickAddButtonListener?.onClickTextBoxAddButton(textBoxTabView)
                }
            }
        }
    }

    private fun setupSignatureView(view: View) {
        val changed = setupContent(view as ImageButton, MediaBoxTabType.SIGNATURE)
        if (changed) {
            val signatureTabView = SignatureTabView(context)
            val params = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
            viewGroup_mediaBox_pageContainer.addView(signatureTabView, params)
            signatureTabView.onMediaBoxHeaderClickListener = object: MediaBoxHeader.OnTitleButtonClickListener {
                override fun onTitleButtonClick() {
                    onClickAddButtonListener?.onClickSignatureAddButton(signatureTabView)
                }
            }
        }
    }

    private fun setupStampView(view: View) {
        val changed = setupContent(view as ImageButton, MediaBoxTabType.STAMP)
        if (changed) {
            val stampTabView = StampTabView(context)
            val params = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
            viewGroup_mediaBox_pageContainer.addView(stampTabView, params)
            stampTabView.onMediaBoxHeaderClickListener = object: MediaBoxHeader.OnTitleButtonClickListener {
                override fun onTitleButtonClick() {
                    stampTabView.hideSoftKeyboard()
                    onClickAddButtonListener?.onClickStampAddButton(stampTabView)
                }
            }
        }
    }

    private fun setupShapeView(view: View) {
        val changed = setupContent(view as ImageButton, MediaBoxTabType.SHAPE)
        if (changed) {
            val shapeTabView = ShapeTabView(context)
            val params = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
            viewGroup_mediaBox_pageContainer.addView(shapeTabView, params)
            shapeTabView.onMediaBoxHeaderClickListener = object: MediaBoxHeader.OnTitleButtonClickListener {
                override fun onTitleButtonClick() {
                    onClickAddButtonListener?.onClickShapeAddButton(shapeTabView)
                }
            }
        }
    }

    private fun setupFormView(view: View) {
        //TODO implements tab view and add to viewEdit_layout_tab_content
        val changed = setupContent(view as ImageButton, MediaBoxTabType.FORM)
        if (changed) {
            LayoutInflater.from(context).inflate(R.layout.view_media_box_tab, viewGroup_mediaBox_pageContainer)
            mediaBoxTabView_mediaBox_tab.visibility = View.VISIBLE
            invalidate()
        }
    }

    interface OnClickHeaderButtonListener {
        fun onClickTextBoxAddButton(textBoxTabView: TextBoxTabView)
        fun onClickTextBoxStyleApplyButton(textBoxTabView: TextBoxTabView)
        fun onClickSignatureAddButton(signatureTabView: SignatureTabView)
        fun onClickStampAddButton(stampTabView: StampTabView)
        fun onClickShapeAddButton(shapeTabView: ShapeTabView)
    }
}