/*
 * ********************************************************************************************************************
 *
 *               iFHS7.
 *              ;BBMBMBMc                  rZMBMBR              BMB
 *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
 *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
 *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
 *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
 *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
 *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
 *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
 *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
 *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
 *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
 *         i0BM: SWKHKGO  MBDv
 *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
 *              ,  XMW  ..
 *                  r                                                                     All rights reserved.
 *
 * ********************************************************************************************************************
 */

package com.sybotan.android.graphy

import android.graphics.*
import android.util.Log
import com.sybotan.android.base.extensions.adjusted
import com.sybotan.android.graphy.data.SLineF
import com.sybotan.android.graphy.enums.SGraphyItemFlag
import com.sybotan.android.graphy.items.SGraphyImageItem
import com.sybotan.android.graphy.items.SGraphyLineItem
import com.sybotan.android.graphy.items.SGraphyRectItem
import com.sybotan.android.graphy.utils.MatrixTools
import com.sybotan.base.extensions.toJson

/**
 * SGraphy图形引擎场景类
 *
 * @author  庞利祥(sybotan@126.com)
 */
open class SGraphyScene {

    /**
     * 类对象
     */
    companion object {
        private val TAG = SGraphyScene::class.java.name
    }

    /** 根节点 */
    private val rootNode: SGraphyItem by lazy {
        val item = SGraphyItem()
        item.scene = this
        item.flags.add(SGraphyItemFlag.ItemIsFocusable)
        item
    }
    /** 当前被锁定的item */
    var grabItem: SGraphyItem? = null
    /** 指向scene被加载到的视图 */
    var view: SGraphyView? = null

    /**
     * 绘制场景
     *
     * @param   canvas      画布
     * @param   rect        更新绘制区域
     */
    open fun drawScene(canvas: Canvas, rect: RectF) {
        rootNode.onPaint(canvas, rect)
        return
    } // Function paint()

    /**
     * 绘制背景
     *
     * @param   canvas      画布
     * @param   rect        更新绘制区域
     */
    open fun drawBackground(canvas: Canvas, rect: RectF) {
        canvas.drawColor(Color.WHITE)
        return
    } // Function drawBackground()

    /**
     * 绘制前景
     *
     * @param   canvas      画布
     * @param   rect        更新区域
     */
    open fun drawForeground(canvas: Canvas, rect: RectF) {
        return
    } // Function drawBackground()

    /**
     * 添加item对象到场景。
     *
     * @param   item        添加的对象
     */
    fun addItem(item: SGraphyItem) {
        item.parent = rootNode
        return
    } // Function addItem()

    /**
     * 添加图片item对象到场景
     *
     * @param   image       图片
     * @return  添加的SGraphyImageItem对象
     */
    fun addImageItem(image: Bitmap): SGraphyImageItem {
        val item = SGraphyImageItem(image)
        addItem(item)
        return item
    } // Function addImageItem()

    /**
     * 添加线段item对象到场景
     *
     * @param   line        线段
     * @return  添加的SGraphyLineItem对象
     */
    fun addLineItem(line: SLineF): SGraphyLineItem {
        val item = SGraphyLineItem(line)
        addItem(item)
        return item
    } // Function addLineItem()

    /**
     * 添加线段item对象到场景
     *
     * @param   x1          端点1的x坐标
     * @param   y1          端点1的y坐标
     * @param   x2          端点2的x坐标
     * @param   y2          端点2的y坐标
     * @return  添加的SGraphyLineItem对象
     */
    fun addLineItem(x1: Float, y1: Float, x2: Float, y2: Float): SGraphyLineItem {
        val item = SGraphyLineItem(x1, y1, x2, y2)
        addItem(item)
        return item
    } // Function addLineItem()

    /**
     * 添加矩item对象到场景
     *
     * @param   rect        矩形
     * @return  添加的SGraphyRectItem对象
     */
    fun addRectItem(rect: RectF): SGraphyRectItem {
        val item = SGraphyRectItem(rect)
        addItem(item)
        return item
    } // Function addRectItem()

    /**
     * 添加矩item对象到场景
     *
     * @param   left        左坐标
     * @param   top         顶坐标
     * @param   right       右坐标
     * @param   bottom      底坐标
     * @return  添加的SGraphyRectItem对象
     */
    fun addRectItem(left: Float, top: Float, right: Float, bottom: Float): SGraphyRectItem {
        val item = SGraphyRectItem(left, top, right, bottom)
        addItem(item)
        return item
    } // Function addRectItem()

    /**
     * 从场景中移除Item。
     *
     * @param   item        被移除的对象
     */
    fun removeItem(item: SGraphyItem) {
        item.parent = null
        return
    } // Function removeItem()

    /**
     * 返回场景的item边界。即所有item边界的并集。
     *
     * @return  场景的item边界。
     */
    fun worldRect(): RectF {
        val rect = RectF()

        for (item in rootNode.children) {        // 依次取item列中的所有item。将所有item的边界做并焦处理。
            rect.union(item.boundingRect().adjusted(item.pos))
        }

        return rect
    } // Function worldsRect()

    /**
     * 更新
     */
    fun update() {
        Log.d(TAG, "update")
        return
    } // Function update()

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 手势相关操作
    /**
     * 用户按下屏幕就会触发.
     *
     * @param   e       按下手势事件。
     * @return  如果事件被处理返回 true , 否则返回 false 。
     */
    open fun onDown(e: SMotionEvent): Boolean {
        if (null != grabItem) {     // 如果当前锁定item不为空
            return true
        }

        return rootNode.onDown(e)
    } // Function onDown()

    /**
     * 用户释放屏幕触发.
     *
     * @param   e       释放手势事件。
     * @return  如果事件被处理返回 true , 否则返回 false 。
     */
    open fun onSingleTapUp(e: SMotionEvent): Boolean {
        Log.e("手势scene",e.toJson())
        if (null != grabItem) {     // 如果当前锁定item不为空
            val ie = toGrabItemMotionEvent(grabItem!!, e)
            return grabItem!!.onSingleTapUp(ie)
        }

        return rootNode.onSingleTapUp(e)
    } // Function onSingleTapUp()

    /**
     *
     * @param   e       手势事件。
     * @return  如果事件被处理返回 true , 否则返回 false 。
     */
    fun onShowPress(e: SMotionEvent): Boolean {
        if (null != grabItem) {     // 如果当前锁定item不为空
            val ie = toGrabItemMotionEvent(grabItem!!, e)
            grabItem!!.onShowPress(ie)
            return true
        }

        return rootNode.onShowPress(e)
    } // Function onShowPress()

    /**
     * 长按触摸屏超过一定时间。
     *
     * @param   e       长按手势事件。
     * @return  如果事件被处理返回 true , 否则返回 false 。
     */
    open fun onLongPress(e: SMotionEvent): Boolean {
        if (null != grabItem) {     // 如果当前锁定item不为空
            val ie = toGrabItemMotionEvent(grabItem!!, e)
            return grabItem!!.onLongPress(ie)
        }

        return rootNode.onLongPress(e)
    } // Function onLongPress()
    /**
     * 用户按下触摸屏，并拖动。
     *
     * @param   e1          第1个 ACTION_DOWN 手势事件
     * @param   e2          最后一个 ACTION_MOVE 手势事件
     * @param   distanceX   X轴上的移动距离，单位：像素
     * @param   distanceY   Y轴上的移动距离，单位：像素
     * @return  如果事件被处理返回 true , 否则返回 false 。
     */
    open fun onScroll(e1: SMotionEvent, e2: SMotionEvent, distanceX: Float, distanceY: Float): Boolean {
        if (null != grabItem) {     // 如果当前锁定item不为空
            val ie1 = toGrabItemMotionEvent(grabItem!!, e1)
            val ie2 = toGrabItemMotionEvent(grabItem!!, e2)
            val distance = toGrabItemDistance(grabItem!!, distanceX, distanceY)
            return grabItem!!.onScroll(ie1, ie2, distance.x, distance.y)
        }

        return rootNode.onScroll(e1, e2, distanceX, distanceY)
    } // Function onScroll()

    /**
     * 用户按下触摸屏、快速移动后松开。即滑动操作。
     *
     * @param   e1          第1个 ACTION_DOWN 手势事件
     * @param   e2          最后一个 ACTION_MOVE 手势事件
     * @param   velocityX   X轴上的移动速度，像素/秒
     * @param   velocityY   Y轴上的移动速度，像素/秒
     * @return  如果事件被处理返回 true , 否则返回 false 。
     */
    open fun onFling(e1: SMotionEvent, e2: SMotionEvent, velocityX: Float, velocityY: Float): Boolean {
        if (null != grabItem) {     // 如果当前锁定item不为空
            val ie1 = toGrabItemMotionEvent(grabItem!!, e1)
            val ie2 = toGrabItemMotionEvent(grabItem!!, e2)
            val velocity = toGrabItemDistance(grabItem!!, velocityX, velocityY)
            return grabItem!!.onFling(ie1, ie2, velocity.x, velocity.y)
        }

        return rootNode.onFling(e1, e2, velocityX, velocityY)
    } // Function onFling()

    /**
     * 转换场景事件坐标到指定Item坐标事件
     *
     * @param   item        指定的item对象
     * @param   e           场景事件
     * @return  item事件
     */
    private fun toGrabItemMotionEvent(item: SGraphyItem, e: SMotionEvent): SMotionEvent {
        val se = SMotionEvent(e)
        se.matrix = Matrix()
        if (this.view != null ){
            se.matrix.postTranslate(this.view!!.pos.x, this.view!!.pos.y);
            se.matrix.postScale(this.view!!.scale, this.view!!.scale)
            se.matrix.postRotate(this.view!!.rotate)
        }
        se.matrix.postConcat(item.scene2itemMattrix())
        val matrix = Matrix()
        se.matrix.invert(matrix)
        val matrixTransform = MatrixTools.matrixTransform(matrix, se.x, se.y)
        se.x = matrixTransform.x
        se.y = matrixTransform.y
//        val p = item.mapFromScene(e.x, e.y)
//        se.setLocation(p.x, p.y)
        return se
    } // Function toItemMotionEvent()

    /**
     * 转换场景中的变化距到指定Item中的距离变化
     *
     * @param   item        指定的item对象
     * @param   distanceX   X轴向上的距
     * @param   distanceY   X轴向上的距
     * @return  item事件
     */
    private fun toGrabItemDistance(item: SGraphyItem, distanceX: Float, distanceY: Float): PointF {
        val p = PointF(distanceX, distanceY)
        val list = item.itemPath()
        for (child in list) {
            p.x = p.x / child.scale.x
            p.y = p.y / child.scale.y
        }
        return p
    } // Function toGrabItemDistance()

} // Class SGraphyScene