package com.kdanmobile.reader.screen.contextmenu

import android.content.Context
import android.graphics.Color
import android.graphics.Point
import android.graphics.PointF
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.StateListDrawable
import android.os.Build
import android.support.v4.content.ContextCompat
import android.support.v7.widget.MyRoundRectDrawableWithShadow
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import com.kdanmobile.kmpdfkit.annotation.freeText.view.KMPDFFreeTextEditView
import com.kdanmobile.kmpdfkit.manager.KMPDFFactory
import com.kdanmobile.kmpdfkit.manager.controller.*
import com.kdanmobile.kmpdfkit.manager.listener.KMPDFContextMenuCallback
import com.kdanmobile.reader.R
import com.kdanmobile.reader.utils.DensityUtil

open class MyKMPDFContextMenuCallback(private val kmpdfFactory: KMPDFFactory?) : KMPDFContextMenuCallback {

    private var popupWindow: PopupWindow? = null

    private var textBoxContextMenuActionListener: TextBoxContextMenuActionListener? = null

    open fun onLongPress() {}

    override fun onDismissContextMenu(type: KMPDFContextMenuCallback.ContextMenuType?, view: View?) {
        dismissPopupWindow()
    }

    override fun onShowContextMenu(type: KMPDFContextMenuCallback.ContextMenuType?, view: View?) {
        if (null != view && null == popupWindow) {

            //  create context menu depended on ContextMenuType
            val context = view.context!!
            val contentView = when (type) {
                KMPDFContextMenuCallback.ContextMenuType.Markup -> createMarkupContextMenuView(context)
                KMPDFContextMenuCallback.ContextMenuType.INK -> createInkContextMenuView(context)
                KMPDFContextMenuCallback.ContextMenuType.SelectText -> createSelectTextContextMenuView(context)
                KMPDFContextMenuCallback.ContextMenuType.Shape -> createShapeContextMenuView(context)
                KMPDFContextMenuCallback.ContextMenuType.Freetext -> createTextBoxContextMenuView(context)
                KMPDFContextMenuCallback.ContextMenuType.Signature -> createSignatureContextMenuView(context)
                KMPDFContextMenuCallback.ContextMenuType.Stamp -> createStampContextMenuView(context)
                KMPDFContextMenuCallback.ContextMenuType.LongPress -> createLongPressContextMenuView(context)
                else -> LinearLayout(context)
            }

            //  LongPress on TextBox
            if (type == KMPDFContextMenuCallback.ContextMenuType.Freetext) {
                if (view is KMPDFFreeTextEditView) {
                    view.setOnLoogPressListener {
                        dismissPopupWindow()
                    }
                }
            }

            val position = computeDisplayPosition(context, type, view, contentView)

            popupWindow = PopupWindow(contentView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, true)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                popupWindow?.elevation = context.resources.getDimension(R.dimen.reader_context_menu_window_elevation)
            } else {
                setElevationBelowAndroidKitKat(context, contentView)
            }
            popupWindow?.isOutsideTouchable = false
            popupWindow?.isFocusable = false
            popupWindow?.showAtLocation(view, Gravity.LEFT or Gravity.TOP, position.x, position.y)
        }
    }

    private fun computeDisplayPosition(context: Context, type: KMPDFContextMenuCallback.ContextMenuType?, view: View, contentView: View): Point {
        //  get the size of context menu
        contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
        val windowWidth = contentView.measuredWidth
        val windowHeight = contentView.measuredHeight

        //  get position y offset and margin of context menu
        val margin = context.resources.getDimensionPixelSize(R.dimen.reader_context_menu_window_position_margin)
        val offset = context.resources.getDimensionPixelSize(when (type) {
            KMPDFContextMenuCallback.ContextMenuType.Markup,
            KMPDFContextMenuCallback.ContextMenuType.INK -> R.dimen.reader_context_menu_window_position_offset_markup
            KMPDFContextMenuCallback.ContextMenuType.SelectText -> R.dimen.reader_context_menu_window_position_offset_select_text
            KMPDFContextMenuCallback.ContextMenuType.Shape,
            KMPDFContextMenuCallback.ContextMenuType.Freetext,
            KMPDFContextMenuCallback.ContextMenuType.Signature,
            KMPDFContextMenuCallback.ContextMenuType.Stamp -> R.dimen.reader_context_menu_window_position_offset_annotation
            else -> R.dimen.reader_context_menu_window_position_offset
        })

        //  get location of view
        val anchorLoc = arrayOf(0, 0).toIntArray()
        view.getLocationOnScreen(anchorLoc)

        //  compute the position of context menu
        val screenHeight = DensityUtil.getScreenHeightPx(context)
        val screenWidth = DensityUtil.getScreenWidthPx(context)
        val topPositionY = anchorLoc[1] - windowHeight - offset
        val bottomPositionY = anchorLoc[1] + view.height + offset
        val leftPositionX = anchorLoc[0] - windowWidth - offset
        val rightPositionX = anchorLoc[0] + view.width + offset

        //  determine the final position of context menu
        val positionY = when {
            topPositionY - margin > 0 -> topPositionY                                                               //  top
            screenHeight - windowHeight - bottomPositionY - margin > 0 -> bottomPositionY                           //  bottom
            else -> (topPositionY + bottomPositionY) / 2                                                            //  center
        }
        val positionX = when {
            positionY == topPositionY || positionY == bottomPositionY -> (leftPositionX + rightPositionX) / 2       //  center
            leftPositionX - margin > 0 -> leftPositionX                                                             //  left
            screenWidth - windowWidth - rightPositionX - margin > 0 -> rightPositionX                               //  right
            else -> (leftPositionX + rightPositionX) / 2                                                            //  center
        }

        return Point(positionX, positionY)
    }

    private fun dismissPopupWindow() {
        popupWindow?.dismiss()
        popupWindow = null
    }

    private fun setElevationBelowAndroidKitKat(context: Context, view: View) {
        val elevation = context.resources.getDimension(R.dimen.reader_context_menu_window_elevation)
        val drawable = MyRoundRectDrawableWithShadow(context.resources, Color.TRANSPARENT, 0f, elevation, elevation)
        setViewBackground(view, drawable)
    }

    private fun setViewBackground(view: View, drawable: Drawable) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            view.background = drawable
        } else {
            view.setBackgroundDrawable(drawable)
        }
    }

    private fun createTextBoxSelector(context: Context, topLeft: Boolean, topRight: Boolean, bottomRight: Boolean, bottomLeft: Boolean): Drawable {
        val radius = context.resources.getDimension(R.dimen.reader_context_menu_text_box_radius)
        val topLeftRadius = if (topLeft) PointF(radius, radius) else PointF()
        val topRightRadius = if (topRight) PointF(radius, radius) else PointF()
        val bottomRightRadius = if (bottomRight) PointF(radius, radius) else PointF()
        val bottomLeftRadius = if (bottomLeft) PointF(radius, radius) else PointF()
        val cornerRadii = floatArrayOf(topLeftRadius.x, topLeftRadius.y, topRightRadius.x, topRightRadius.y, bottomRightRadius.x, bottomRightRadius.y, bottomLeftRadius.x, bottomLeftRadius.y)

        val normalDrawable = GradientDrawable()
        normalDrawable.cornerRadii = cornerRadii
        normalDrawable.setColor(ContextCompat.getColor(context, R.color.reader_contextMenu_bgNormal))
        val pressedDrawable = GradientDrawable()
        pressedDrawable.cornerRadii = cornerRadii
        pressedDrawable.setColor(ContextCompat.getColor(context, R.color.reader_contextMenu_bgPressed))
        val drawable = StateListDrawable()
        drawable.addState(intArrayOf(android.R.attr.state_pressed), pressedDrawable)
        drawable.addState(intArrayOf(android.R.attr.state_enabled), normalDrawable)
        return drawable
    }

    private fun createMarkupContextMenuView(context: Context): View {
        /** Just set HIGH_LIGHT then highlight, strike, underline will be triggered. **/
        /** WTF !!!!!!!!!!! **/
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val contentView = layoutInflater.inflate(R.layout.view_context_menu_normal, null)
        contentView.findViewById<TextView>(R.id.btnDelete_contextMenu).setOnClickListener {
            val kmpdfMarkupController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.MARKER_UP) as KMPDFMarkupController?
            kmpdfMarkupController?.deleteMarkupAnnotView()
            dismissPopupWindow()
        }
        return contentView
    }

    private fun createInkContextMenuView(context: Context): View {
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val contentView = layoutInflater.inflate(R.layout.view_context_menu_normal, null)
        contentView.findViewById<TextView>(R.id.btnDelete_contextMenu).setOnClickListener {
            val kmpdfInkController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.INK) as KMPDFInkController?
            kmpdfInkController?.deleteInkAnnotView()
            dismissPopupWindow()
        }
        return contentView
    }

    private fun createSelectTextContextMenuView(context: Context): View {
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val contentView = layoutInflater.inflate(R.layout.view_context_menu_select_text, null)

        val btnCopy = contentView.findViewById<TextView>(R.id.btnCopy_contextMenu)
        val btnHighlight = contentView.findViewById<TextView>(R.id.btnHighlight_contextMenu)
        val btnUnderline = contentView.findViewById<TextView>(R.id.btnUnderline_contextMenu)
        val btnStrikeout = contentView.findViewById<TextView>(R.id.btnStrikeout_contextMenu)

        setViewBackground(btnCopy, createTextBoxSelector(context, true, false, false, true))
        setViewBackground(btnHighlight, createTextBoxSelector(context, false, false, false, false))
        setViewBackground(btnUnderline, createTextBoxSelector(context, false, false, false, false))
        setViewBackground(btnStrikeout, createTextBoxSelector(context, false, true, true, false))

        val kmpdfSelectTextController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.SELECT_TEXT) as KMPDFSelectTextController?
        btnCopy.setOnClickListener {
            kmpdfSelectTextController?.copySelectedText()
            dismissPopupWindow()
        }
        btnHighlight.setOnClickListener {
            kmpdfSelectTextController?.highlightSelectedText()
            dismissPopupWindow()
        }
        btnUnderline.setOnClickListener {
            kmpdfSelectTextController?.underlineSelectedText()
            dismissPopupWindow()
        }
        btnStrikeout.setOnClickListener {
            kmpdfSelectTextController?.strikeoutSelectedText()
            dismissPopupWindow()
        }
        return contentView
    }

    private fun createShapeContextMenuView(context: Context): View {
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val contentView = layoutInflater.inflate(R.layout.view_context_menu_normal, null)
        contentView.findViewById<TextView>(R.id.btnDelete_contextMenu).setOnClickListener {
            val kmpdfShapeAnnotController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.SHAPE) as KMPDFShapeAnnotController?
            kmpdfShapeAnnotController?.deleteShapeAnnotView()
            dismissPopupWindow()
        }
        return contentView
    }

    private fun createTextBoxContextMenuView(context: Context): View {
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val contentView = layoutInflater.inflate(R.layout.view_context_menu_textbox, null)

        val btnDelete = contentView.findViewById<TextView>(R.id.btnDelete_contextMenu)
        val btnStyle = contentView.findViewById<TextView>(R.id.btnStyle_contextMenu)
        val btnEdit = contentView.findViewById<TextView>(R.id.btnEdit_contextMenu)
        val btnCopy = contentView.findViewById<TextView>(R.id.btnCopy_contextMenu)

        setViewBackground(btnDelete, createTextBoxSelector(context, true, false, false, true))
        setViewBackground(btnStyle, createTextBoxSelector(context, false, false, false, false))
        setViewBackground(btnEdit, createTextBoxSelector(context, false, false, false, false))
        setViewBackground(btnCopy, createTextBoxSelector(context, false, true, true, false))

        btnDelete.setOnClickListener {
            textBoxContextMenuActionListener?.onDelete()
            dismissPopupWindow()
        }
        btnStyle.setOnClickListener {
            textBoxContextMenuActionListener?.onEditStyle()
            dismissPopupWindow()
        }
        btnEdit.setOnClickListener {
            textBoxContextMenuActionListener?.onEditText()
            dismissPopupWindow()
        }
        btnCopy.setOnClickListener {
            textBoxContextMenuActionListener?.onCopy()
            dismissPopupWindow()
        }
        return contentView
    }

    private fun createSignatureContextMenuView(context: Context): View {
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val contentView = layoutInflater.inflate(R.layout.view_context_menu_signature, null)

        val btnDelete = contentView.findViewById<TextView>(R.id.btnDelete_contextMenu)
        val btnAdd = contentView.findViewById<TextView>(R.id.btnAdd_contextMenu)

        setViewBackground(btnDelete, createTextBoxSelector(context, true, false, false, true))
        setViewBackground(btnAdd, createTextBoxSelector(context, false, true, true, false))

        val kmpdfSignatureController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.SIGNATURE) as KMPDFSignatureController?
        btnDelete.setOnClickListener {
            kmpdfSignatureController?.deleteSignatureAnnotView()
            dismissPopupWindow()
        }
        btnAdd.setOnClickListener {
            kmpdfSignatureController?.saveSignatureAnnot()
            dismissPopupWindow()
        }
        return contentView
    }

    private fun createStampContextMenuView(context: Context): View {
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val contentView = layoutInflater.inflate(R.layout.view_context_menu_normal, null)
        contentView.findViewById<TextView>(R.id.btnDelete_contextMenu).setOnClickListener {
            val kmpdfStampController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.STAMP) as KMPDFStampController?
            kmpdfStampController?.deleteStampAnnotView()
            dismissPopupWindow()
        }
        return contentView
    }

    private fun createLongPressContextMenuView(context: Context): View {
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val contentView = layoutInflater.inflate(R.layout.view_context_menu_long_press, null)
        contentView.findViewById<TextView>(R.id.btnPaste_contextMenu).setOnClickListener {
            val kmpdfLongPressCreateAnnotController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.LONGCLICK) as KMPDFLongPressCreateAnnotController?
            kmpdfLongPressCreateAnnotController?.longPress_Paste()
            onLongPress()
            dismissPopupWindow()
        }
        return contentView
    }

    fun setTextBoxContextMenuActions(listener: TextBoxContextMenuActionListener) {
        textBoxContextMenuActionListener = listener
    }
}