package com.kdanmobile.kmpdfkit.pdfcommon

import android.content.Context
import android.graphics.*
import com.kdanmobile.kmpdfkit.annotation.Annotation
import com.kdanmobile.kmpdfkit.form.pushbutton.PushButtonActionInfo
import com.kdanmobile.kmpdfkit.globaldata.Config
import com.kdanmobile.kmpdfkit.globaldata.KMPDFAnnotEditMode
import com.kdanmobile.kmpdfkit.manager.KMPDFFactory
import com.kdanmobile.kmpdfkit.manager.listener.KMPDFModifyNoteCallback
import com.kdanmobile.kmpdfkit.rsa.PermissionConfig
import com.kdanmobile.reader.ReflectionHelper

open class ModifyKMPDFPageView(
        context: Context,
        filePickerSupport: FilePicker.FilePickerSupport,
        kmpdfFactory: KMPDFFactory,
        parentSize: Point
) : KMPDFPageView(context, filePickerSupport, kmpdfFactory, parentSize) {

    private var mSelectedTextAnnotationIndex: Int
        get() = ReflectionHelper.getPrivateValue(this@ModifyKMPDFPageView, "mSelectedTextAnnotationIndex", KMPDFPageView::class.java) as? Int ?: 0
        set(value) = ReflectionHelper.setPrivateValue(this@ModifyKMPDFPageView, "mSelectedTextAnnotationIndex", value, KMPDFPageView::class.java)

    private var mSelectedAnnotationIndex: Int
        get() = ReflectionHelper.getPrivateValue(this@ModifyKMPDFPageView, "mSelectedAnnotationIndex", KMPDFPageView::class.java) as? Int ?: 0
        set(value) = ReflectionHelper.setPrivateValue(this@ModifyKMPDFPageView, "mSelectedAnnotationIndex", value, KMPDFPageView::class.java)

    private var modifyingAnnotIndex: Int
        get() = ReflectionHelper.getPrivateValue(this@ModifyKMPDFPageView, "modifyingAnnotIndex", KMPDFPageView::class.java) as? Int ?: 0
        set(value) = ReflectionHelper.setPrivateValue(this@ModifyKMPDFPageView, "modifyingAnnotIndex", value, KMPDFPageView::class.java)

    private var mWidgetAreas: Array<RectF>?
        get() = ReflectionHelper.getPrivateValue(this@ModifyKMPDFPageView, "mWidgetAreas", KMPDFPageView::class.java) as? Array<RectF>
        set(value) = ReflectionHelper.setPrivateValue(this@ModifyKMPDFPageView, "mWidgetAreas", value, KMPDFPageView::class.java)


    override fun passClickEvent(x: Float, y: Float): Hit {
        val scale = mSourceScale * width.toFloat() / mSize.x.toFloat()
        val docRelX = (x - left.toFloat()) / scale
        val docRelY = (y - top.toFloat()) / scale
        var hit = false

        val mCore = ReflectionHelper.getPrivateValue(this, "mCore", KMPDFPageView::class.java) as? KMPDFCore

        var i: Int
        if (mAnnotations != null && !Config.cropMode) {
            i = mAnnotations.size - 1
            while (i >= 0) {
                if (mAnnotations[i].contains(docRelX, docRelY)) {
                    hit = true
                    break
                }
                i--
            }

            if (hit) {
                if (mAnnotations[i].type != Annotation.Type.HIGHLIGHT && mAnnotations[i].type != Annotation.Type.UNDERLINE && mAnnotations[i].type != Annotation.Type.SQUIGGLY && mAnnotations[i].type != Annotation.Type.STRIKEOUT && mAnnotations[i].type != Annotation.Type.INK) {
                    setSelectBox(null as RectF?)
                    closeBubbleMenu()
                }

                when (mAnnotations[i].type) {
                    Annotation.Type.HIGHLIGHT, Annotation.Type.UNDERLINE, Annotation.Type.SQUIGGLY, Annotation.Type.STRIKEOUT, Annotation.Type.INK -> {
                        mSelectedAnnotationIndex = i
                        mSelectedTextAnnotationIndex = mSelectedAnnotationIndex
                        selectMarkupType = mAnnotations[i].type
                        closeBubbleMenu()
                        closeMagnifier()
                        setSelectBox(mAnnotations[i])
                        if (kmpdfFactory != null && kmpdfFactory.kmpdfAnnotEditMode != null) {
                            if (mAnnotations[i].type == Annotation.Type.INK) {
                                kmpdfFactory.kmpdfAnnotEditMode.pdfAnnotEditMode = KMPDFAnnotEditMode.Mode.INK_MODIFY
                            } else {
                                kmpdfFactory.kmpdfAnnotEditMode.pdfAnnotEditMode = KMPDFAnnotEditMode.Mode.MARKUP_MODIFY
                            }
                        }

                        return Hit.Annotation
                    }
                    Annotation.Type.FREETEXT -> {
                        mSelectedAnnotationIndex = i
                        modifyingAnnotIndex = mSelectedAnnotationIndex
                        if (kmpdfFactory != null && kmpdfFactory.kmpdfAnnotEditMode != null && createMoveableFreeText(mAnnotations[mSelectedAnnotationIndex])) {
                            kmpdfFactory.kmpdfAnnotEditMode.pdfAnnotEditMode = KMPDFAnnotEditMode.Mode.FREETEXT_MODIFY
                            modifyingAnnotation(mPageNumber, modifyingAnnotIndex)
                        }

                        return Hit.Annotation
                    }
                    Annotation.Type.SQUARE, Annotation.Type.CIRCLE -> {
                        mSelectedAnnotationIndex = i
                        modifyingAnnotIndex = mSelectedAnnotationIndex
                        if (kmpdfFactory != null && kmpdfFactory.kmpdfAnnotEditMode != null && modifySquareOrCircleAnnot(mAnnotations[mSelectedAnnotationIndex], mSelectedAnnotationIndex)) {
                            kmpdfFactory.kmpdfAnnotEditMode.pdfAnnotEditMode = KMPDFAnnotEditMode.Mode.SHAPE_MODIFY
                            modifyingAnnotation(mPageNumber, mSelectedAnnotationIndex)
                        }

                        return Hit.Annotation
                    }
                    Annotation.Type.LINE -> {
                        mSelectedAnnotationIndex = i
                        modifyingAnnotIndex = mSelectedAnnotationIndex
                        if (kmpdfFactory != null && kmpdfFactory.kmpdfAnnotEditMode != null && modifyLineOrArrow(mAnnotations[mSelectedAnnotationIndex], mSelectedAnnotationIndex)) {
                            kmpdfFactory.kmpdfAnnotEditMode.pdfAnnotEditMode = KMPDFAnnotEditMode.Mode.SHAPE_MODIFY
                            modifyingAnnotation(mPageNumber, mSelectedAnnotationIndex)
                        }

                        return Hit.Annotation
                    }
                    Annotation.Type.STAMP -> {
                        mSelectedAnnotationIndex = i
                        if (kmpdfFactory != null && kmpdfFactory.kmpdfAnnotEditMode != null && modifyStampAnnotation(mAnnotations[mSelectedAnnotationIndex])) {
                            kmpdfFactory.kmpdfAnnotEditMode.pdfAnnotEditMode = KMPDFAnnotEditMode.Mode.STAMP_MODIFY
                            modifyingAnnotation(mPageNumber, mSelectedAnnotationIndex)
                        }

                        return Hit.Annotation
                    }
                    Annotation.Type.WIDGET -> {
                        mSelectedWidgetAnnotationIndex = i
                        widgetArea = mAnnotations[i]
                    }
                    Annotation.Type.LINK -> return Hit.Nothing
                    Annotation.Type.TEXT -> {
                        if (kmpdfFactory != null && kmpdfFactory.kmpdfAnnotEditMode != null && mCore != null && kmpdfFactory.kmpdfOperateNoteCallback != null) {
                            val kmpdfModifyNoteCallback = object : KMPDFModifyNoteCallback {
                                override fun modifyNoteAnnot(content: String): Boolean {
                                    mCore.modifyNoteAnnotation(mPageNumber, i, null, content)
                                    return false
                                }

                                override fun deleteNoteAnnot(): Boolean {
                                    deleteSelectedAnnotation(i)
                                    return false
                                }
                            }
                            ReflectionHelper.setPrivateValue(this@ModifyKMPDFPageView, "kmpdfModifyNoteCallback", kmpdfModifyNoteCallback, KMPDFPageView::class.java)

                            kmpdfFactory.kmpdfOperateNoteCallback.onKMClickNote(mCore.getNoteAnnotContent(mPageNumber, i), kmpdfModifyNoteCallback)
                            return Hit.Annotation
                        }

                        return Hit.Annotation
                    }
                }
            }
        }

        mSelectedAnnotationIndex = -1
        setSelectBox(null)
        closeBubbleMenu()
        closeMagnifier()
        if (mCore != null && mCore.javascriptSupported()) {
            mWidgetAreas?.also {
                i = 0
                while (i < it.size && !hit) {
                    if (it[i].contains(docRelX, docRelY)) {
                        widgetArea = it[i]
                        hit = true
                    }
                    ++i
                }
            }

            if (hit) {
                val mPassClick = object : AsyncTask<Void, Void, PassClickResult>() {
                    override fun doInBackground(vararg arg0: Void): PassClickResult? {
                        return mCore.passClickEvent(mPageNumber, docRelX, docRelY)
                    }

                    override fun onPostExecute(result: PassClickResult?) {
                        if (result != null) {
                            if (result.changed) {
                                val changeReporter = ReflectionHelper.getPrivateValue(this, "changeReporter", KMPDFPageView::class.java) as? Runnable
                                changeReporter?.run()
                            }

                            result.acceptVisitor(object : PassClickResultVisitor() {
                                override fun visitPushButton(result: PassClickResultPushButton) {
                                    if (PermissionConfig.allowsFormWidget) {
                                        val invokePushButtonAction = ReflectionHelper.getPrivateMethod("invokePushButtonAction", KMPDFPageView::class.java, PushButtonActionInfo::class.java)
                                        invokePushButtonAction.invoke(this@ModifyKMPDFPageView, result.pushButtonActionInfo)
                                    }
                                }

                                override fun visitText(result: PassClickResultText) {
                                    if (PermissionConfig.allowsFillForms) {
                                        ReflectionHelper.setPrivateValue(this@ModifyKMPDFPageView, "mFormTextContent", result.text, KMPDFPageView::class.java)
                                        val createFormText = ReflectionHelper.getPrivateMethod("createFormText", KMPDFPageView::class.java)
                                        createFormText.invoke(this@ModifyKMPDFPageView)
                                    }
                                }

                                override fun visitChoice(result: PassClickResultChoice) {
                                    if (PermissionConfig.allowsFillForms) {
                                        val invokeChoiceDialog = ReflectionHelper.getPrivateMethod("invokeChoiceDialog", KMPDFPageView::class.java, Array<String>::class.java)
                                        invokeChoiceDialog.invoke(this@ModifyKMPDFPageView, result.options)
                                    }
                                }

                                override fun visitSignature(result: PassClickResultSignature) {
                                    if (PermissionConfig.allowsFillForms) {
                                        val warnNoSignatureSupport = ReflectionHelper.getPrivateMethod("warnNoSignatureSupport", KMPDFPageView::class.java)
                                        val invokeSigningDialog = ReflectionHelper.getPrivateMethod("invokeSigningDialog", KMPDFPageView::class.java)
                                        val invokeSignatureCheckingDialog = ReflectionHelper.getPrivateMethod("invokeSignatureCheckingDialog", KMPDFPageView::class.java)
                                        when (result.state) {
                                            SignatureState.NoSupport -> warnNoSignatureSupport.invoke(this@ModifyKMPDFPageView)
                                            SignatureState.Unsigned -> invokeSigningDialog.invoke(this@ModifyKMPDFPageView)
                                            SignatureState.Signed -> invokeSignatureCheckingDialog.invoke(this@ModifyKMPDFPageView)
                                        }

                                    }
                                }
                            })
                        }
                    }
                }
                ReflectionHelper.setPrivateValue(this@ModifyKMPDFPageView, "mPassClick", mPassClick, KMPDFPageView::class.java)

                mPassClick.execute(*arrayOfNulls(0))
                return Hit.Widget
            } else {
                return Hit.Nothing
            }
        } else {
            return Hit.Nothing
        }
    }
}