import {
  Component,
  ElementRef,
  ViewChild,
  OnInit,
  Input,
  OnDestroy,
  HostListener
  
} from "@angular/core";

import {
  MySprite,
  RichText,
  getMinScale,
  ShapeRect,
  ShapeCircle,
  tweenChange,
  randomSortByArr,
  Label,
  showPopParticle,
  moveItem,
  removeItemFromArr,
  rotateItem,
  hideItem,
  showItem,
  ShapeRectNew,
  scaleItem,
  showBlingBling,
  waterWave,
  jelly,
  getAngleByPos,
  getPosDistance,
  shake
} from "./Unit";

import { localImages, localAudios, multiSizeBackground} from "./resources";

import { Cartoon } from './Cartoon'
import { Subject } from "rxjs";
import { debounceTime, map, takeWhile, retry } from "rxjs/operators";
import * as _ from "lodash";
import TWEEN from "@tweenjs/tween.js";
import { demoData } from '../../assets/default/formData/DataKey_JM04_3.js'

const zIndexMap = {
  mainBackground: 0,
  zhangyu: 100,
  button: 110,
  popup: 105
}

@Component({
  selector: "app-play",
  templateUrl: "./play.component.html",
  styleUrls: ["./play.component.scss"]
})

export class PlayComponent implements OnInit, OnDestroy {
  
  g_cartoon = new Cartoon()

  // ------------  全局数据  ------------
  g_topElementContainer; // 用于装载装饰元素 气球 星星等
  g_stage; //中心舞台
  // g_background_color = "#rgb(0,0,0,0)"
  g_background_color = "#FFFFFF"
  g_enableMapDown = true; // 触摸使能
  g_enableMapUp = true; // 抬起使能
  g_enableMapMove = true; // 移动ss使能
  g_canvasLeft;
  g_canvasTop;
  g_animationId: any;
  g_mapScale = 1; // 缩放比例
  g_KEY = "DataKey_JM04_3";
  g_canvasWidth = 2388;
  g_canvasHeight = 1688;
  g_canvasBaseW = 2388;
  g_canvasBaseH = 1688;
  g_winResizeEventStream = new Subject();
  g_clickX; // 点击坐标 X
  g_clickY; // 点击坐标 Y
  g_ctx; // canvas 实例
  g_data; // 数据
  g_formData; // 核心表单数据
  g_teacherFlag = false; // 默认角色
  g_currentUser;
  g_firstTouch = true;
  g_partTitle_x = null;
  g_mainTitle_x = null;
  // ------------------------------------

  // ------------  私有数据  ------------
  m_mapDownQueue = {} //按下事件处理队列
  m_mapDownArray = [] //按下事件处理队列
  m_mapDownObject = []

  m_mapUpQueue = {} //抬起事件处理队列
  m_mapUpArray = [] //抬起事件处理队列
  m_mapUpObject = []

  m_mapDragQueue = {} //拖拽事件处理队列
  m_mapDragArray = [] //拖拽事件处理队列
  m_mapDragObject = []

  m_mapMoveArray = [] //移动事件处理队列
  m_mapMoveObject = []
  m_endPageArr;
  m_showPetalFlag;
  m_elementPetalArr;
  m_showElementPetalFlag;
  m_PetalImage = "_scrap-pic-"  // 飘落动画
  m_renderArr // 渲染队列
  m_renderObject = [];
  m_frontCurtainArr = []; // 前置幕布
  m_defaultZindex = 0;
  m_setTimeoutIDs = [];
  m_setIntervalIDs = [];
  m_moveAsstantIntervalId = null;

  g_currentDragElementID: any = null; // 当前拖动的动画元件
  g_dragFirstClickY: any;
  g_dragFirstClickX: any;
  g_enableDragDistance: number = 20 * this.g_mapScale;
  g_enableDragging: any;
  g_maskLayerZindex = 100;
  // ------------------------------------
  

  // ------------  游戏逻辑数据  ------------
  m_openShift: boolean = false;
  m_blockGroup = null;
  m_allBlocks = [];
  m_currentInput = "";
  m_currentQuestionIndex = 0;
  m_hasActiveBlock = false;
  m_hasErrorLetter = false;
  m_currentInputIndex = 0;
  m_submitedTimes = 0;
  m_wordLetterInputCatch = [];
  m_canInput = true;
  m_totalScrollHeight = 0;
  m_questionIndexArray = [];
  m_endGame = false;
  m_resultSaved = [];
  // ------------------------------------


  // ------------  消息  ------------
  
  // ------------------------------------


  // ------------  调试变量  ------------
  g_EnableStageRuler = false; // 使能舞台背景格尺
  g_ForceChangeDefaultRole = false // 强制当前角色为默认角色
  g_EnableTestSendEvent = false // 发送模拟Web数据
  g_showLeftCornerTest= false // 测试左上角图标
  // ------------------------------------


  // 当数据加载完毕后，执行
  systemReady(){
    this.setLeftCornerTest()
    this.initGame()
  }
  
  // 屏幕尺寸变化后执行
  handleScreenResize(){
    this.cleanSystemVar()
    this.cleanGameVar();
    this.setLeftCornerTest();
    this.disableMoveAsstant();
    this.initSystem();
    this.initGame()
  }

  // 映射预加载图片[网路]资源 返回包含图片路径的数组
  mapToImageArray(contentObj){
    let array = []
    return array
  }

  // 映射预加载音频[网路]资源 返回包含音频路径的数组
  mapToAduioArray(contentObj){
    let array = []
    // contentObj.long_audio.audio_url && array.push(contentObj.long_audio.audio_url)
    return array
  }

  // 重置长音频
  resetLongAudio() {

  }

  // ------------------------------------------------------------------------------
  // 游戏核心处理区
  // ------------------------------------------------------------------------------
  // ------------------------------------------------------------------------------
  // 
  // 
  // 
  // ------------------------------------------------------------------------------
  // ------------------------------------------------------------------------------

  initGame(){
    console.log(this.g_formData);
    this.initBackground();
    this.initTitle();
    this.initQuestion();
    this.initKeyboard();
    this.initSubmit();
    this.initOutputWindow();
    this.initCheckPannel();
    this.initSlider();
    this.switchQuestion(0, 0);
    this.showHideMore(false)

    window.addEventListener("message", (e)=> {
      let msgData = e.data;
      if(msgData.action === "is_show_more") {
        const data = JSON.parse(msgData.data);
        this.showHideMore(data.isShowMore)
      }
    })
  }

  cleanGameVar(){
    this.m_openShift = false;
    this.m_blockGroup = null;
    this.m_allBlocks = [];
    this.m_currentInput = "";
    this.m_currentQuestionIndex = 0;
    this.m_hasActiveBlock = false;
    this.m_hasErrorLetter = false;
    this.m_currentInputIndex = 0;
    this.m_submitedTimes = 0;
    this.m_wordLetterInputCatch = [];
    this.m_canInput = true;
    this.m_totalScrollHeight = 0;
    this.m_questionIndexArray = [];
    this.m_endGame = false;
    this.m_resultSaved = [];
  }

  startGame(){

  }

  restartGame(){
    // this.cleanGameVar()
    this.startGame();
    this.switchQuestion(0, 0);
  }

  initBackground() {
    let color = this.g_cartoon.createCartoonElementShapeRect("background_color", this.g_canvasWidth, this.g_canvasHeight, "#fefdf9");
    color.ref.x =0;
    color.ref.y = 0;
    this.render(color.ref)

    let mask =  this.g_cartoon.createCartoonElementImageFunc("background_mask", "bg_main_mask", (w, h)=>{
      return {
        sx: this.g_canvasWidth / 2 / w,
        sy: this.g_canvasHeight / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 + this.g_canvasWidth / 4,
        y: this.g_canvasHeight / 2
      }
    })
    this.render(mask.ref)
  }

  initTitle() {
    let text =  this.g_cartoon.createCartoonElementLabelFunc("main-title", this.g_formData.title.mainText, "Aileron-Black", "#000000", 88, (w, h)=>{
      return {
        x: 160 * this.g_mapScale + w * this.g_mapScale / 2,
        y: 65 * this.g_mapScale,
      }
    })
    text.ref.fontWeight = 900
    text.ref.fontColor = "#3e9b31";
    if(text.ref.width > 1440) {
      text.ref.setScaleXY(this.g_mapScale * 1440/text.ref.width);
      text.ref.x = 160 * this.g_mapScale + 1440 * this.g_mapScale / 2;
    } else {
      text.ref.setScaleXY(this.g_mapScale);
    }
    this.render(text.ref)
  }

  initQuestion() {
    let element =  this.g_cartoon.createCartoonElementImageFunc("question_container", "bg_question", (w, h)=>{
      return {
        sx: 2048*this.g_mapScale / w,
        sy: 240*this.g_mapScale / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2,
        y: 247 * this.g_mapScale + (240*this.g_mapScale) / 2
      }
    })

    let btnNext =  this.g_cartoon.createCartoonElementImageFunc("question_next", "btn_next", (w, h)=>{
      return {
        sx: 136 / w,
        sy: 136 / h,
      }
    }, (w, h)=>{
      return {
        x: 1010,
        y: 0
      }
    })

    let btnNextShadow =  this.g_cartoon.createCartoonElementImageFunc("question_next_shadow", "buttonShadow", (w, h)=>{
      return {
        sx: 169 / w,
        sy: 166 / h,
      }
    }, (w, h)=>{
      return {
        x: 1010,
        y: 35
      }
    })
    btnNext.active = (status) => {
      btnNext.ref.visible = status;
      btnNextShadow.ref.visible = status;
    }

    let btnPre =  this.g_cartoon.createCartoonElementImageFunc("question_pre", "btn_pre", (w, h)=>{
      return {
        sx: 136 / w,
        sy: 136 / h,
      }
    }, (w, h)=>{
      return {
        x: -1010,
        y: 0
      }
    })

    let btnPreShadow =  this.g_cartoon.createCartoonElementImageFunc("question_pre_shadow", "buttonShadow", (w, h)=>{
      return {
        sx: 169 / w,
        sy: 166 / h,
      }
    }, (w, h)=>{
      return {
        x: -1010,
        y: 35
      }
    })
    btnPre.active = (status) => {
      btnPre.ref.visible = status;
      btnPreShadow.ref.visible = status;
    }

    let labelIndex = this.g_cartoon.createCartoonElementLabelFunc("question_index", "", "Aileron-Bold", "#3e9b31", 56, (w, h)=>{
      return {
        x: 0,
        y: -110,
      }
    })
    labelIndex.ref.text = "Across 1"

    let questionText = this.g_cartoon.createCartoonElementLabelFunc("question_text", "", "DroidSansFallback", "#FFFFFF", 64, (w, h)=>{
      return {
        x: 0,
        y: 10,
      }
    })
    questionText.ref.text = "a fish whose head look like those of a horse"

    element.out = (callback)=> {
      return tweenChange(element.ref, {y: -1000}, 1, ()=>{
        callback && callback()
      })
    }

    this.subscribeMapDownEvent(btnNext.id, async ()=>{
      if(this.m_endGame || (this.m_currentQuestionIndex >= this.g_formData.dataArray.length -1)) {
        this.g_enableMapDown = true;
        return;
      }
      this.switchQuestion(this.m_currentQuestionIndex, this.m_currentQuestionIndex + 1);
      await this.buttonPressAnimation(btnNext.id, btnNextShadow.id)
      this.g_enableMapDown = true;
    })
    
    this.subscribeMapDownEvent(btnPre.id, async ()=>{
      if(this.m_endGame || (this.m_currentQuestionIndex - 1)<0) {
        this.g_enableMapDown = true;
        return;
      }
      this.switchQuestion(this.m_currentQuestionIndex, this.m_currentQuestionIndex - 1);
      await this.buttonPressAnimation(btnPre.id, btnPreShadow.id)
      this.g_enableMapDown = true;
    })

    this.m_questionIndexArray = []
    let acrossCount = 0;
    let downCount = 0;
    this.g_formData.dataArray.forEach(item => {
      if(item.direction == "Across") {
        this.m_questionIndexArray.push(`Across ${++acrossCount}`)
      } else {
        this.m_questionIndexArray.push(`Down ${++downCount}`)
      }
    });

    element.ref.addChild(labelIndex.ref)
    element.ref.addChild(questionText.ref)
    element.ref.addChild(btnNextShadow.ref)
    element.ref.addChild(btnPreShadow.ref)
    element.ref.addChild(btnNext.ref)
    element.ref.addChild(btnPre.ref)
    this.render(element.ref)
  }

  initKeyboard() {
    const createWord = (letter, x, y) => {
      let container = this.g_cartoon.createCartoonElementImageFunc(`key_${letter}_click`, "bg_letter_target", (w, h)=>{
        return {
          sx: 80 / w,
          sy: 80 / h,
        }
      }, (w, h)=>{
        return {
          x: x,
          y: y
        }
      })

      let text = this.g_cartoon.createCartoonElementLabelFunc(`key_${letter}`, letter, "Aileron-Black", "#3e9b31", 80, (w, h)=>{
        return {
          x: 0,
          y: 0,
        }
      })
      container.ref.addChild(text.ref);
      return container
    }

    let element =  this.g_cartoon.createCartoonElementImageFunc("keyboard_container", "bg_container", (w, h)=>{
      return {
        sx: 855*this.g_mapScale / w,
        sy: 820*this.g_mapScale / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 + 855*this.g_mapScale / 2 + 118 * this.g_mapScale,
        y: this.g_canvasHeight / 2 + 150*this.g_mapScale
      }
    })

    element.out = (callback)=> {
      return tweenChange(element.ref, {x: this.g_canvasWidth + 1000}, 1, ()=>{
        callback && callback()
      })
    }

    let letttes = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
    let allLetterRefs = []
    let baseX = -855 / 2;
    let baseY = -820 / 2;
    for(let i=1; i<=letttes.length; i++) {
      let le = createWord(letttes[i-1], baseX, baseY)
      this.subscribeMapDownEvent(le.id, async ()=>{
        if(this.m_endGame || !this.m_canInput) {
          this.g_enableMapDown = true;
          return 
        }
        this.g_cartoon.playAudio("sm_letterClick")
        let target = this.g_cartoon.getCartoonElement(this.m_currentInput)
        if(this.m_openShift) {
          target.setContentText(letttes[i-1].toUpperCase())
        } else {
          target.setContentText(letttes[i-1].toLocaleLowerCase())
        }
        this.buttonPressAnimation(le.id)
        this.g_enableMapDown = true;
        this.jumpToNextActive(this.m_currentQuestionIndex);
      })
      allLetterRefs.push(le.ref.children[1])
      element.ref.addChild(le.ref)
      if(i%6==0) {
        baseX = -855 / 2;
        baseY += 80 + 98;
      } else {
        baseX += 80 + 85;
      }
    }
    
    // shfit按键
    let btnShift =  this.g_cartoon.createCartoonElementImageFunc("keyboard_shfit", "btn_shift", (w, h)=>{
      return {
        sx: 420 / w,
        sy: 128 / h,
      }
    }, (w, h)=>{
      return {
        x: baseX + 350,
        y: baseY
      }
    })
    let btnShiftShadow =  this.g_cartoon.createCartoonElementImageFunc("keyboard_shfit_shadow", "btn_shift_shadow", (w, h)=>{
      return {
        sx: 428 / w,
        sy: 141 / h,
      }
    }, (w, h)=>{
      return {
        x: baseX + 350,
        y: baseY + 50
      }
    })
    element.ref.addChild(btnShiftShadow.ref)
    element.ref.addChild(btnShift.ref)
    this.subscribeMapDownEvent(btnShift.id, async ()=>{
      if(this.m_endGame) {
        this.g_enableMapDown = true;
        return;
      }
      this.g_cartoon.playAudio("sm_switch")
      this.m_openShift = !this.m_openShift;
      if(this.m_openShift) {
        allLetterRefs.forEach(le=>{
          le.text = le.text.toUpperCase()
        })
      } else {
        allLetterRefs.forEach(le=>{
          le.text = le.text.toLocaleLowerCase()
        })
      }
      await this.buttonPressAnimation(btnShift.id, btnShiftShadow.id);
      this.g_enableMapDown = true;
    })

    this.render(element.ref)
  }

  initOutputWindow() {
    const createBlock = (letter, questionIndex, li, x, y, width=80, height=80)=> {
      let container = this.g_cartoon.createCartoonElementImageFunc(`block_${questionIndex}_${li}`, "bg_letter_target", (w, h)=>{
        return {
          sx: 80 / w * width / 80,
          sy: 80 / h * height / 80,
        }
      }, (w, h)=>{
        return {
          x: x,
          y: y
        }
      })

      let text = this.g_cartoon.createCartoonElementLabelFunc(`block_${questionIndex}_${li}_letter`, "", "Aileron-Black", "#FFFFFF", 52, (w, h)=>{
        return {
          x: 0,
          y: 2,
        }
      })
      
      let bgInit = this.g_cartoon.createCartoonElementImageFunc(`block_${questionIndex}_${li}_container_init`, "bg_block_init", (w, h)=>{
        return {
          sx: 80 / w,
          sy: 80 / h,
        }
      }, (w, h)=>{
        return {
          x: 0,
          y: 0
        }
      })
      bgInit.ref.alpha = 0;

      let bgDisable = this.g_cartoon.createCartoonElementImageFunc(`block_${questionIndex}_${li}_container_disable`, "bg_block_disable", (w, h)=>{
        return {
          sx: 80 / w,
          sy: 80 / h,
        }
      }, (w, h)=>{
        return {
          x: 0,
          y: 0
        }
      })
      bgDisable.ref.alpha = 0;

      let bgRight = this.g_cartoon.createCartoonElementImageFunc(`block_${questionIndex}_${li}_container_right`, "bg_block_right", (w, h)=>{
        return {
          sx: 80 / w,
          sy: 80 / h,
        }
      }, (w, h)=>{
        return {
          x: 0,
          y: 0
        }
      })
      bgRight.ref.alpha = 0;

      let bgFocus = this.g_cartoon.createCartoonElementImageFunc(`block_${questionIndex}_${li}_container_focus`, "bg_block_focus", (w, h)=>{
        return {
          sx: 80 / w,
          sy: 80 / h,
        }
      }, (w, h)=>{
        return {
          x: 0,
          y: 0
        }
      })
      bgFocus.ref.alpha = 0;

      let bgWrong = this.g_cartoon.createCartoonElementImageFunc(`block_${questionIndex}_${li}_container_wrong`, "bg_block_wrong", (w, h)=>{
        return {
          sx: 80 / w,
          sy: 80 / h,
        }
      }, (w, h)=>{
        return {
          x: 0,
          y: 0
        }
      })
      bgWrong.ref.alpha = 0;

      container.ref.addChild(bgInit.ref)
      container.ref.addChild(bgDisable.ref)
      container.ref.addChild(bgRight.ref)
      container.ref.addChild(bgFocus.ref)
      container.ref.addChild(bgWrong.ref)
      container.ref.addChild(text.ref);

      container.isCorrect = false;
      container.switchStatus = (status) => {
        switch(status) {
          case "init": 
            bgInit.ref.alpha = 1;
            bgDisable.ref.alpha = 0;
            bgRight.ref.alpha = 0;
            bgFocus.ref.alpha = 0;
            bgWrong.ref.alpha = 0;
            text.ref.fontColor = "#b17d5a";
            break;
          case "disable": 
            bgInit.ref.alpha = 0;
            bgDisable.ref.alpha = 1;
            bgRight.ref.alpha = 0;
            bgFocus.ref.alpha = 0;
            bgWrong.ref.alpha = 0;
            text.ref.fontColor = "#b17d5a";
            break;
          case "right": 
            bgInit.ref.alpha = 0;
            bgDisable.ref.alpha = 0;
            bgRight.ref.alpha = 1;
            bgFocus.ref.alpha = 0;
            bgWrong.ref.alpha = 0;
            text.ref.fontColor = "#ffffff"
            break;
          case "focus": 
            bgInit.ref.alpha = 0;
            bgDisable.ref.alpha = 0;
            bgRight.ref.alpha = 0;
            bgFocus.ref.alpha = 1;
            bgWrong.ref.alpha = 0;
            text.ref.fontColor = "#ffffff";
            break;
          case "wrong": 
            bgInit.ref.alpha = 0;
            bgDisable.ref.alpha = 0;
            bgRight.ref.alpha = 0;
            bgFocus.ref.alpha = 0;
            bgWrong.ref.alpha = 1;
            text.ref.fontColor = "#ffffff";
            break;
        }
      }

      container.activeStatus = false
      container.active = (status=false) => {
        container.activeStatus = status
        if(status) {
          container.switchStatus("focus")
        } else {
          container.switchStatus("right")
        }
        if(status) {
          this.m_currentInput = `block_${questionIndex}_${li}`;
        }
      }
  
      container.canSetActive = () => {
        if(container.isCorrect) {
          return false;
        }
        return true
      }
      
      container.modified = false;
      container.setContentText = (letter) => {
        text.ref.text = letter?letter:"";
        if(!this.checkAllFill()) {
          let btnSub = this.g_cartoon.getCartoonElement("button_submit")
          btnSub.switchActive(true)
        }
        container.modified = true;
      }
  
      container.getContentText = () => {
        return text.ref.text?text.ref.text:"";
      }

      container.getRightLetter = () => {
        return letter?letter:"";
      }
  
      container.checkStatus = (withRed=false, groupIndex) => {
        // container.active(false);
        if(letter != container.getContentText()) {
          this.m_hasErrorLetter = true;
          if(this.m_currentQuestionIndex == groupIndex) {
            if(!this.m_hasActiveBlock) {
              container.switchStatus("focus");
              this.m_hasActiveBlock = true;
              this.m_currentQuestionIndex = groupIndex;
              container.active(true)
            } else {
              container.switchStatus("wrong");
            }
          } else {
            container.switchStatus("wrong");
          }
        } else {
          container.isCorrect = true;
          if(this.m_currentQuestionIndex == groupIndex) {
            container.switchStatus("right")
          } else {
            container.switchStatus("disable")
          }
        }
      }
  
      container.blockDisabl = false;
      container.checkWhenSwitchQuestion = (withRed, fromIndex, groupIndex, contentSaved?) => {
        // container.active(false);
        if(groupIndex!= this.m_currentQuestionIndex) { 
          if(container.getContentText() == "") {
            // container.switchStatus("init")
          } else {
            if(this.m_submitedTimes == 0) {
              if(!container.blockDisable) {
                container.switchStatus("disable")
              } else {
              }
            } else {
              if(container.isCorrect || container.modified) {
                container.switchStatus("disable")
              } else {
                container.switchStatus("wrong")
              }
            }
          }
        } else {
          if(this.m_submitedTimes == 0 ) {
            container.switchStatus("right")
            if(!this.m_hasActiveBlock) {
              this.m_hasActiveBlock = true;
              container.active(true)
              container.blockDisable = true;
            }
          } else {
            if(container.isCorrect || container.modified) {
              container.switchStatus("right")
            } else {
              container.switchStatus("wrong")
            }
            if(!this.m_hasActiveBlock && !container.isCorrect) {
              this.m_hasActiveBlock = true;
              container.active(true)
            }
          }
          
        }
      }

      this.subscribeMapDownEvent(container.id, ()=>{
        if(this.m_endGame) {
          this.g_enableMapDown = true;
          return
        }
        if(this.m_currentQuestionIndex != questionIndex) {
          this.switchQuestion(this.m_currentQuestionIndex, questionIndex)
        } else {
          if(container.canSetActive()) {
            if(this.m_currentInput) {
              let currentAcitveNode = this.g_cartoon.getCartoonElement(this.m_currentInput)
              currentAcitveNode.active(false)
              this.m_currentInputIndex = li
            }
            container.active(true);
          }
        }
        this.g_enableMapDown = true;
      })
      return container
    }

    let element =  this.g_cartoon.createCartoonElementImageFunc("output_container", "bg_container_left", (w, h)=>{
      return {
        sx: 900*this.g_mapScale / w,
        sy: 900*this.g_mapScale / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 - 900*this.g_mapScale / 2 - 32*this.g_mapScale,
        y: this.g_canvasHeight / 2 + 150*this.g_mapScale
      }
    })

    let rolNum = this.g_formData.grid.length;
    let colNum = this.g_formData.grid[0].length;

    if(rolNum==17) {
      element.ref.x -= 150 * this.g_mapScale
    } else if(rolNum==15) {
      element.ref.x -= 120 * this.g_mapScale
    } else if(rolNum==12) {
      element.ref.x -= 80 * this.g_mapScale
    } else if(rolNum==9) {
      element.ref.x -= 60 * this.g_mapScale
    }

    let width = 900;
    let height = 900;

    let sX = -1*width/2 + width/colNum/2
    let sY =  - height/2 + height/rolNum/2
    
    let step = (width/colNum)<(height/rolNum)?(width/colNum):(height/rolNum) + 8;

    this.m_blockGroup = new Array(this.g_formData.dataArray.length);
    
    for(let i=0; i<this.g_formData.dataArray.length; i++) {
      this.m_blockGroup[i] = []
    }

    let indexArr = new Array(this.g_formData.dataArray.length).fill(0)
    let existId = []
    for(let j=0; j<rolNum; j++) {
      for(let i=0; i<colNum; i++) {
        if(this.g_formData.grid[j][i].index != "") {
          let qi = this.g_formData.grid[j][i].index.join("-")
          let newBlock = createBlock(this.g_formData.grid[j][i].text, qi, indexArr[qi]++, sX+i*step, sY+j*step, 900/colNum-5, 900/colNum-5)
          this.m_allBlocks.push(newBlock)
          element.ref.addChild(newBlock.ref)
          qi.split("-").forEach(qqi => {
            this.m_blockGroup[qqi].push(newBlock)
          });
          // let qi = this.g_formData.grid[j][i].index
        }
      }
    }
    this.render(element.ref)
  }

  initCheckPannel() {
    // let element = this.g_cartoon.createCartoonElementImageFunc(`checkpannel_container`, "btn_submit", (w, h)=>{
    //   return {
    //     sx: 888 * this.g_mapScale / w,
    //     sy: 160 * this.g_mapScale / h,
    //   }
    // }, (w, h)=>{
    //   return {
    //     x: this.g_canvasWidth / 2 + 855 * this.g_mapScale / 2 + 118 * this.g_mapScale,
    //     y: this.g_canvasHeight / 2 + 700 * this.g_mapScale
    //   }
    // })
    let element = this.g_cartoon.createCartoonElementShapeRect("checkpannel_container", this.g_canvasWidth / 2, this.g_canvasHeight, "#FFF")
    element.ref.x = this.g_canvasWidth / 2;
    element.ref.y = this.g_canvasHeight + 1000;
    element.ref.alpha = 0;

    element.in = (callback) => {
      this.g_cartoon.playAudio("sm_checkin");
      return tweenChange(element.ref, {y: 0}, 1, ()=> {
        callback && callback()
      })
    }

    // 背景 上：canvas高-中  中：985 下：canvas高-中-上
    let bgMiddle = this.g_cartoon.createCartoonElementImageFunc(`checkpannel_bg_middle`, "bg_check_middle", (w, h)=>{
      return {
        sx: 1194 * this.g_mapScale / w,
        sy: 985 * this.g_mapScale / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 4,
        y: this.g_canvasHeight / 2
      }
    })
    element.ref.addChild(bgMiddle.ref)

    let bgTop = this.g_cartoon.createCartoonElementImageFunc(`checkpannel_bg_top`, "bg_check_top", (w, h)=>{
      return {
        sx: 1194 * this.g_mapScale / w,
        sy: (this.g_canvasHeight - 985 * this.g_mapScale) / 2 / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 4,
        y: (this.g_canvasHeight - 985 * this.g_mapScale) / 4
      }
    })
    element.ref.addChild(bgTop.ref)

    let bBottom = this.g_cartoon.createCartoonElementImageFunc(`checkpannel_bg_bottom`, "bg_check_bottom", (w, h)=>{
      return {
        sx: 1194 * this.g_mapScale / w,
        sy: (this.g_canvasHeight - 985 * this.g_mapScale) / 2 / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 4,
        y: this.g_canvasHeight - (this.g_canvasHeight - 985 * this.g_mapScale) / 4
      }
    })
    element.ref.addChild(bBottom.ref)

    let bgMiddleMask = this.g_cartoon.createCartoonElementImageFunc(`checkpannel_bg_middle_mask`, "bg_check_middle_mask", (w, h)=>{
      return {
        sx: 1194 * this.g_mapScale  / w,
        sy: 985 * this.g_mapScale / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 4,
        y: this.g_canvasHeight / 2
      }
    })
    element.ref.addChild(bgMiddleMask.ref)

    let checkMiddle = this.g_cartoon.createCartoonElementImageFunc(`checkpannel_checnk_middle`, "check_middle", (w, h)=>{
      return {
        sx: 1,
        sy: 1,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: 0
      }
    })
    bgMiddle.ref.addChild(checkMiddle.ref)

    let checkTop = this.g_cartoon.createCartoonElementImageFunc(`checkpannel_checnk_top`, "check_top", (w, h)=>{
      return {
        sx: 1,
        sy: 186 / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: -985/2 - 186 / 2
      }
    })
    bgMiddleMask.ref.addChild(checkTop.ref)

    // let labelText = this.g_cartoon.createCartoonElementLabel("Chenck_label_title", "Check", "Aileron-Black", "#FFFFFF", 60)
    // checkTop.ref.addChild(labelText.ref);

    let checkBottom = this.g_cartoon.createCartoonElementImageFunc(`checkpannel_checnk_bottom`, "check_bottom", (w, h)=>{
      return {
        sx: 1,
        sy: 79 / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: 985/2 + 79 / 2
      }
    })
    bgMiddleMask.ref.addChild(checkBottom.ref)

    let btnMore = this.g_cartoon.createCartoonElementImageFunc(`button_more_info`, "btn_submit_outline", (w, h)=>{
      return {
        sx: 888 / w,
        sy: 160 / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: 180
      }
    })

    let textSubmit =  this.g_cartoon.createCartoonElementLabelFunc("button_submit_text", "更多练习", "Aileron-Bold", "#FFFFFF", 64, (w, h)=>{
      return {
        x: 0,
        y: 0,
      }
    })
    btnMore.ref.addChild(textSubmit.ref)

    let btnMoreShadow =  this.g_cartoon.createCartoonElementImageFunc("btn_submit_shadow_more", "btn_submit_shadow", (w, h)=>{
      return {
        sx: 941 / w,
        sy: 216 / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: 180 + 50
      }
    })

    checkBottom.ref.addChild(btnMoreShadow.ref)
    checkBottom.ref.addChild(btnMore.ref)

    this.subscribeMapDownEvent(btnMore.id, async ()=>{
      this.g_cartoon.playAudio("sm_moreinfo")
      await this.buttonPressAnimation(btnMore.id, btnMoreShadow.id)
      window.parent.postMessage( {action: 'temp_show_more', data: ""}, "*")
      this.g_enableMapDown = true;
    })

    // 滚动面板
    let scrollContent = this.g_cartoon.createCartoonElementShapeRect("check_scroll_pannel", 880, 985 * 5, "#FFFFFF");
    scrollContent.ref.y = -985 / 2
    scrollContent.ref.x = -880 / 2
    scrollContent.ref.alpha = 0;
    checkMiddle.ref.addChild(scrollContent.ref)
    this.render(element.ref)

    let clickSY = null;
    let baseY = null;
    scrollContent.canScroll = true;
    scrollContent.topY = -985 / 2
    scrollContent.currentY = 0;
    scrollContent.windowHeight = 985;
    this.subscribeMapDragEvent(scrollContent.id, ()=>{
      if(!scrollContent.canScroll) {
        this.g_enableMapUp = true;
        this.g_enableMapDown = true;
        return;
      }
      clickSY = this.g_clickY;
      baseY = scrollContent.ref.y;
    }, ()=>{
      if(!scrollContent.canScroll) {
        return
      }
      let dis = (clickSY - this.g_clickY) / this.g_mapScale;
      let _t = scrollContent.topY - (scrollContent.currentY - scrollContent.windowHeight) - scrollContent.ref.height
      if(scrollContent.topY <= (baseY - dis)) {
        // console.log("已经滚动到顶部")
        scrollContent.ref.y = scrollContent.topY
      } else {
        if((baseY - dis) <= _t) {
          // console.log("已经滚动到底部")
          scrollContent.ref.y = _t
        } else {
          // console.log("滚动")
          scrollContent.ref.y = baseY - dis
        }
      }

      let total = scrollContent.topY - _t;
      let current = scrollContent.topY - scrollContent.ref.y
      let progress = Math.floor(current / total * 100) / 100;
      if(progress<0) {
        progress = 0
      }
      if(progress>1) {
        progress = 1
      }
      this.g_cartoon.getCartoonElement("slider-background").initSlider(scrollContent.windowHeight, this.m_totalScrollHeight, progress)
    }, ()=>{
      this.g_enableMapUp = true;
      this.g_enableMapDown = true;
    })
  }

  showHideMore(status) {
    let btn = this.g_cartoon.getCartoonElement("button_more_info")
    let btnShadow = this.g_cartoon.getCartoonElement("btn_submit_shadow_more")
    if(status) {
      btn.ref.scaleX = btn.initScaleX;
      btnShadow.ref.scaleX = btnShadow.initScaleX;
    } else {
      btn.ref.scaleX = 0;
      btnShadow.ref.scaleX = 0;
    }
  }

  sendResult() {
    // console.log(JSON.stringify(this.m_resultSaved))
    window.parent.postMessage( {action: 'temp_send_result', data: JSON.stringify(this.m_resultSaved)}, "*")
  }

  getResult() {
    let resultDataStr = []
    this.m_blockGroup.forEach(group => {
      let rightLetters = "";
      let currentLetters = "";
      group.forEach(block => {
        rightLetters += block.getRightLetter();
        currentLetters += block.getContentText();
      });
      resultDataStr.push({
        rightLetters, currentLetters
      })
    });
    // console.log(JSON.stringify(resultDataStr))
    return resultDataStr
  }

  initSlider() {
    const updateSlider = (len) => {
      let top = this.g_cartoon.getCartoonElement("slider-top");
      let body = this.g_cartoon.getCartoonElement("slider-body");
      let bottom = this.g_cartoon.getCartoonElement("slider-bottom");
      body.update(len);
      top.update();
      bottom.update();
    }

    const setProgress = (scale) => {
      sliderBG.currentProgress = scale;
      // let scrollPannel = this.g_cartoon.getCartoonElement("check_scroll_pannel")
      let totalHeight = LineHeight;
      let pix = totalHeight / sliderBG.fullHeight; // 整体高度的一个单位 对应多少滚动条高度
      let empty = (sliderBG.fullHeight - sliderBG.winHeight) * scale * pix; // 需要滚动的高度 乘以 进度  再换算成滚动条的高度
      let top = this.g_cartoon.getCartoonElement("slider-top");
      let body = this.g_cartoon.getCartoonElement("slider-body");
      let bottom = this.g_cartoon.getCartoonElement("slider-bottom");
      body.ref.y = -LineHeight / 2 + empty + body.ref.scaleY * sliderBodyHeight / 2 + sliderTopHeight;

      top.update();
      bottom.update();

      // scrollPannel.ref.y = 78 * this.g_mapScale - (scrollPannel.currentY - (this.g_canvasHeight - 78 * this.g_mapScale)) * sliderBG.currentProgress;
    }

    // 
    const LineHeight = 985;
    const LineWidth = 10;
    const sliderTopHeight = 5;
    const sliderBodyHeight = 5;
    const sliderBottomHeight = 5;
    const offSetY = 0;

    let sliderBG = this.g_cartoon.createCartoonElementImageFunc("slider-background", "bgSlider", (w, h)=>{
      return {
        sx: LineWidth / w,
        sy: LineHeight / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: 0
      }
    })

    // sliderBG.ref.scaleX = 0;
    sliderBG.isShow = false;
    sliderBG.show = () => {
      if(!sliderBG.isShow) {
        sliderBG.isShow = true;
        tweenChange(sliderBG.ref, {scaleX: sliderBG.initScaleX}, 0.05)
      }
    }
    sliderBG.hide = () => {
      tweenChange(sliderBG.ref, {scaleX: 0},  0.05)
    }
    sliderBG.initSlider = (windowHeight, fullHeight, current) => {
      sliderBG.winHeight = windowHeight;
      sliderBG.fullHeight = fullHeight;
      let totalHeight = LineHeight;
      let pix = totalHeight / fullHeight;
      let fillHeight = windowHeight * pix
      updateSlider(fillHeight)
      setProgress(current)
    }
    sliderBG.winHeight = 0;
    sliderBG.fullHeight = 0;
    sliderBG.pix = 0;
    sliderBG.currentProgress = 0;

    sliderBG.getCurrentProgress = () => {
      let emptyTop = (sliderTop.ref.y - 2) + 271;
      let emptyDown = LineHeight / 2 - (sliderBottom.ref.y + 2)
      let scale = emptyTop / (emptyTop + emptyDown)
      let progress = Math.floor(scale * 100) / 100
      return progress>0?progress:0
    }

    let sliderTop = this.g_cartoon.createCartoonElementImageFunc("slider-top", "slider_top", (w, h)=>{
      return {
        sx: LineWidth / w,
        sy: sliderTopHeight / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: sliderTopHeight / 2
      }
    })
    sliderTop.update = () => {
      let y = sliderBody.ref.y
      let box = sliderBody.ref.getBoundingBox()
      y -= box.height / 2 / this.g_mapScale + sliderTopHeight / 2;
      if(y<(-LineHeight / 2)) {
        // console.log("滑动已到最上", y)
        return false;
      } else {
        sliderTop.ref.y = y;
        return true;
      }
    }

    let sliderBody = this.g_cartoon.createCartoonElementImageFunc("slider-body", "slider_body", (w, h)=>{
      return {
        sx: LineWidth / w,
        sy: sliderBodyHeight / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: 0
      }
    })
    sliderBody.update = (len) => {
      let y = sliderTop.ref.y + sliderTop.ref.height
      sliderBody.ref.scaleY = len / sliderBodyHeight
      y += len / 2;
      sliderBody.ref.y = y
    }
    sliderBody.toEnd = () => {
      let box = sliderBody.ref.getBoundingBox()
      sliderBottom.ref.y = LineHeight / 2
      sliderBody.ref.y = sliderBottom.ref.y - box.height / 2 / this.g_mapScale - 2;
      sliderTop.update();
    }
    sliderBody.toTop = () => {
      let box = sliderBody.ref.getBoundingBox()
      sliderTop.ref.y = -LineHeight / 2
      sliderBody.ref.y = sliderTop.ref.y + box.height / 2 / this.g_mapScale + 2;
      sliderBottom.update();
    }

    let sliderBottom = this.g_cartoon.createCartoonElementImageFunc("slider-bottom", "slider_bottom", (w, h)=>{
      return {
        sx: LineWidth / w,
        sy: sliderBottomHeight / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: sliderBottomHeight / 2
      }
    })
    sliderBottom.update = () => {
      let y = sliderBody.ref.y
      let box = sliderBody.ref.getBoundingBox()
      y += box.height / 2 / this.g_mapScale + sliderBottomHeight / 2;
      
      if(y>LineHeight / 2) {
        // console.log("滑动已到最下", y)
        return false;
      } else {
        sliderBottom.ref.y = y
        return true;
      }
    }
    sliderBG.ref.addChild(sliderBody.ref)
    sliderBG.ref.addChild(sliderBottom.ref)
    sliderBG.ref.addChild(sliderTop.ref)

    let checkMiddle = this.g_cartoon.getCartoonElement("checkpannel_checnk_middle");
    checkMiddle.ref.addChild(sliderBG.ref)
    sliderBG.ref.x = checkMiddle.ref.width / 2 - 30 * this.g_mapScale;
    sliderBG.ref.y = 0;
    
    // let clickSY = 0
    // let baseY = 0;
    // const scrollPannel = this.g_cartoon.getCartoonElement("scroll-pannel")
    
    // this.subscribeMapDragEvent(sliderBody.id, ()=>{
    //   clickSY = this.g_clickY;
    //   baseY = sliderBody.ref.y
    // }, ()=>{
    //   let dis = clickSY - this.g_clickY
    //   let savedY = sliderBody.ref.y
    //   sliderBody.ref.y = baseY - dis
    //   let crTop = sliderTop.update()
    //   let crBottom = sliderBottom.update()
    //   if(!crTop) {
    //     sliderBody.toTop()
    //     sliderTop.update();
    //     sliderBottom.update();
    //   }
    //   if(!crBottom) {
    //     sliderBody.toEnd();
    //     sliderTop.update();
    //     sliderBottom.update();
    //   }
      
    //   scrollPannel.ref.y = 52 * this.g_mapScale - (scrollPannel.currentY - (this.g_canvasHeight - 52 * this.g_mapScale)) * sliderBG.getCurrentProgress()
    // }, ()=>{
    //   this.g_enableMapUp = true;
    //   this.g_enableMapDown = true;
    // })
  }

  showCheckPannel(checkResult) {
    const creatItem = (withSplit, data) => {
      let heightData = {
        text: 0,
        textLineNum: 0,
        word: 0,
        right: 0,
        line: 0,
        textRef: null,
        wordRef: null,
        rightRef: null,
        lineRef: null
      }

      let scrollContent = this.g_cartoon.getCartoonElement("check_scroll_pannel")
      let text = this.g_cartoon.createCartoonElementLabel("text", data.text, "DroidSansFallback", "#FFFFFF", 48)
      text.ref.textAlign = "left";
      text.ref.warpLineHeight = 64;
      text.ref.maxSingalLineWidth = 750;
      text.ref.refreshSize();
      text.ref.x = 0
      if(text.ref.lineNum == 0) {
        text.ref.warpLineHeight = 0;
        text.ref.maxSingalLineWidth = 0;
        text.ref.refreshSize();
      }
      heightData.textRef = text.ref;
      heightData.textLineNum = text.ref.lineNum
      heightData.text = (text.ref.lineNum + 1) * 64
      scrollContent.ref.addChild(text.ref)

      let wordColorBG = this.g_cartoon.createCartoonElementShapeRect("wordColorBG", 360, 64, data.right?"#007b3e":"#d71818");
      wordColorBG.ref.radius = 16
      heightData.wordRef = wordColorBG.ref
      heightData.word = 64;

      let maxLen = data.word.length
      let fs = 48
      if(maxLen <= 14) {
        fs = 48
      } else if(maxLen <= 18) {
        fs = 36
      } else if(maxLen <= 20) {
        fs = 24
      } else {
        fs = 20
      }
      let word = this.g_cartoon.createCartoonElementLabel("text-label", data.word, "Aileron-Bold", "#FFFFFF", fs)
      word.ref.x = 360 / 2
      word.ref.y = 64 / 2 + 5
      wordColorBG.ref.addChild(word.ref);
      scrollContent.ref.addChild(wordColorBG.ref)

      if(!data.right) {
        let ele = this.g_cartoon.createCartoonElementImageFunc(`err`, "bg_wrong_ans", (w, h)=>{
          return {
            sx: 797 / w,
            sy: 120 / h,
          }
        }, (w, h)=>{
          return {
            x: scrollContent.ref.width / 2 - 28,
            y: 0
          }
        })
        heightData.rightRef = ele.ref

        let word = this.g_cartoon.createCartoonElementLabel("text-label", data.rightWord, "Aileron-Bold", "#ffe9b1", 52)
        word.ref.x = -797 / 2 + 120 + word.ref.width / 2
        word.ref.y = 0
        ele.ref.addChild(word.ref)

        heightData.right = 120;
        scrollContent.ref.addChild(ele.ref)
      }

      if(withSplit) {
        let splitLine = this.g_cartoon.createCartoonElementImageFunc(`splitline`, "check_pannel_split_line", (w, h)=>{
          return {
            sx: 880 / w,
            sy: 10 / h,
          }
        }, (w, h)=>{
          return {
            x: 880 / 2,
            y: 0
          }
        })
        heightData.line = 10;
        heightData.lineRef = splitLine.ref
        scrollContent.ref.addChild(splitLine.ref);
      }
      return heightData
    }
    
    let scrollContent = this.g_cartoon.getCartoonElement("check_scroll_pannel")
    let sliderBG = this.g_cartoon.getCartoonElement("slider-background")
    
    let heigthData = [];
    let totalNum = checkResult.length;
    checkResult.forEach((element, index) => {
      heigthData.push(creatItem(!(index==(totalNum-1)), element))
    });

    let totalHeight = 0
    let padding = 30;
    heigthData.forEach(item=>{
      totalHeight += item.text
      totalHeight += item.word
      totalHeight += item.right
      totalHeight += item.line
      totalHeight += 15
    })
    
    let countY = 0;
    heigthData.forEach(item=>{
      if(item.textLineNum>0) {
        item.textRef.baseY = countY - item.text + 64 * 1.5;
      } else {
        item.textRef.y = countY + 64 / 2;
      }
      countY += item.text + padding

      if(item.wordRef) {
        item.wordRef.y = countY;
        countY += item.word + padding
      }

      if(item.rightRef) {
        item.rightRef.y = countY + item.right /2 + 10;
        countY += item.right + padding + 10
      }

      if(item.lineRef) {
        item.lineRef.y = countY;
        countY += item.line + padding
      }
    })

    this.m_totalScrollHeight = totalHeight + heigthData.length * 120;
    sliderBG.initSlider(scrollContent.windowHeight, this.m_totalScrollHeight, 0)
    let scroll = this.g_cartoon.getCartoonElement("check_scroll_pannel")
    scroll.ref.setSize(880, this.m_totalScrollHeight)
    let checkPannel = this.g_cartoon.getCartoonElement("checkpannel_container");
    return checkPannel.in()
  }

  initSubmit() {
    let submit = this.g_cartoon.createCartoonElementImageFunc(`button_submit`, "btn_submit", (w, h)=>{
      return {
        sx: 888 * this.g_mapScale / w,
        sy: 160 * this.g_mapScale / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 + 855 * this.g_mapScale / 2 + 118 * this.g_mapScale,
        y: this.g_canvasHeight / 2 + 700 * this.g_mapScale
      }
    })

    let submitActive = this.g_cartoon.createCartoonElementImageFunc(`button_submit_active`, "btn_submit_outline", (w, h)=>{
      return {
        sx: 888 / w,
        sy: 160 / h,
      }
    }, (w, h)=>{
      return {
        x: 0,
        y: 0
      }
    })
    submitActive.ref.alpha = 0;
    submit.ref.addChild(submitActive.ref)

    let textSubmit =  this.g_cartoon.createCartoonElementLabelFunc("button_submit_text", "Submit", "Aileron-Black", "#FFFFFF", 76, (w, h)=>{
      return {
        x: 0,
        y: 0,
      }
    })
    submit.ref.addChild(textSubmit.ref)

    let btnSubmitShadow =  this.g_cartoon.createCartoonElementImageFunc("btn_submit_shadow", "btn_submit_shadow", (w, h)=>{
      return {
        sx: 941 * this.g_mapScale / w,
        sy: 216 * this.g_mapScale / h,
      }
    }, (w, h)=>{
      return {
        x: this.g_canvasWidth / 2 + 855 * this.g_mapScale / 2 + 118 * this.g_mapScale,
        y: this.g_canvasHeight / 2 + 760 * this.g_mapScale
      }
    })

    submit.switchActive = (status) => {
      if(status) {
        submitActive.ref.alpha = 1;
        btnSubmitShadow.ref.alpha = 1;
        textSubmit.ref.fontColor = "#FFFFFF"
        // this.m_canInput = false;
      } else {
        submitActive.ref.alpha = 0;
        btnSubmitShadow.ref.alpha = 0;
        textSubmit.ref.fontColor = "#f1e4c2"
        // this.m_canInput = true;
      }
    }
    submit.switchActive(false)

    submit.out = (callback)=> {
      btnSubmitShadow.ref.visible = false;
      return tweenChange(submit.ref, {x: this.g_canvasWidth + 1000}, 0.3, ()=>{
        callback && callback()
      })
    }

    const handleSubmit = async () => {
      this.m_submitedTimes++;
      this.m_currentInputIndex = 0;
      let result = [];
      let status = false;
      let hasIncorrect = false;
      this.m_hasActiveBlock = false;
      let errorIndex = -1;
      this.m_blockGroup.forEach((group, index) => {
        status = this.updateStatusByGroupIndex(index)
        let word = ""
        let rightWord = ""
        group.forEach(block => {
          word += block.getContentText()
          rightWord += block.getRightLetter()
        });

        if(status) {
          result.push({text: `${this.m_questionIndexArray[index]}. ${this.g_formData.dataArray[index].text}`, word: word, right: true, rightWord: rightWord})
        } else {
          result.push({text: `${this.m_questionIndexArray[index]}. ${this.g_formData.dataArray[index].text}`, word: word, right: false, rightWord: rightWord})
        }
        if(!hasIncorrect && !status) {
          hasIncorrect = true;
          errorIndex = index;
        }
      })
      if(hasIncorrect) { 
        console.log("有错误")
      } else{
        console.log("全部正确")
      }
      this.g_cartoon.playAudio("sm_submit")
      this.m_blockGroup.forEach(group => {
        group.forEach(block => {
          block.modified = false;
        });
      });

      this.m_resultSaved.push(this.getResult());
      if(errorIndex>=0) {
        this.switchQuestion(this.m_currentQuestionIndex, errorIndex)
      }
      if(this.m_submitedTimes>=2 || (this.m_submitedTimes<2 && !hasIncorrect)) {
        let qp = this.g_cartoon.getCartoonElement("question_container")
        let keyboard = this.g_cartoon.getCartoonElement("keyboard_container")
        let submitButton = this.g_cartoon.getCartoonElement("button_submit");
        
        await qp.out()
        await keyboard.out()
        await submitButton.out()
        await this.showCheckPannel(result)
        // this.g_cartoon.getCartoonElement("background_mask").ref.alpha = 0
        this.g_enableMapDown = true;
        this.endGame();
      }

      // this.switchQuestion(this.m_currentQuestionIndex, this.m_currentQuestionIndex+1)
      submit.switchActive(false)
      // if(this.m_currentQuestionIndex == this.g_formData.dataArray.length-1) {
      //   // 最后一题提交以后 弹出结束按钮
      //   let btn = this.g_cartoon.getCartoonElement("FinishButton")
      //   btn.in()
      // } else {
      //   if(status) {
      //     this.g_cartoon.playAudio("正确")
      //     this.switchQuestion(this.m_currentQuestionIndex, this.m_currentQuestionIndex+1)
      //   } else {
      //     this.g_cartoon.playAudio("错误")
      //   }
      // }
    }

    this.subscribeMapDownEvent(submit.id, ()=> {
      if(this.m_endGame) {
        this.g_enableMapDown = true;
        return
      }
      if(submitActive.ref.alpha == 1) {
        handleSubmit()
        this.buttonPressAnimation(submit.id, btnSubmitShadow.id)
      }
      this.g_enableMapDown = true;
    })

    this.render(btnSubmitShadow.ref)
    this.render(submit.ref)
  }

  // 切换题目,主要是变蓝/变红输入框
  switchQuestion(fromIndex, toIndex) {
    this.g_cartoon.playAudio("sm_switch")
    if(toIndex.toString().indexOf("-") != -1) {
      let indexArr = toIndex.split("-")
      fromIndex = this.m_currentQuestionIndex // indexArr[0]
      indexArr.some(itemIndex => {
        if(fromIndex == itemIndex) {
          return false
        } else {
          toIndex = itemIndex;
          return true
        }
      })
    }
    toIndex = Number(toIndex)
    this.m_currentQuestionIndex = toIndex;
    this.m_currentInputIndex = 0;
    this.m_hasActiveBlock = false;

    this.resetAllBlockStatus();
    this.m_blockGroup.forEach((group, groupIndex) => {
      group.forEach((block, index) => {
        block.checkWhenSwitchQuestion(false, fromIndex, groupIndex, this.m_wordLetterInputCatch[index]?this.m_wordLetterInputCatch[index]:"")
      });
    });

    let indexText = this.g_cartoon.getCartoonElement("question_index")
    indexText.ref.text = this.m_questionIndexArray[toIndex];
    
    let questionText = this.g_cartoon.getCartoonElement("question_text");
    questionText.ref.text = this.g_formData.dataArray[toIndex].text
    
    let lettersArr = questionText.ref.text.split(" ")
    let preArr = lettersArr.map(item=>{
      if(item!="") {
        return item
      }
    })

    lettersArr = [];//去除undefined后的结果
    for(var i=0;i<preArr.length;i++){
      if(typeof(preArr[i])!='undefined'){
        lettersArr.push(preArr[i]);
      }
    }

    if(lettersArr.length > 14) {
      questionText.ref.maxSingalLineWidth = 1800
      questionText.ref.fontSize = 48;
      questionText.ref.refreshSize();
      let count = 0;
      while(questionText.ref.lineNum>1 && questionText.ref.fontSize>0 && count<100) {
        count++;
        questionText.ref.fontSize -= 1;
        questionText.ref.refreshSize();
      }
      questionText.ref.baseY = -1 * questionText.ref.lineNum * questionText.ref.fontSize
    } else {
      questionText.ref.baseY = 0
      questionText.ref.y = 20
      questionText.ref.maxSingalLineWidth = 0
      questionText.ref.fontSize = 64;
      questionText.ref.refreshSize();
      if(questionText.ref.width > 1800) {
        questionText.ref.setScaleXY(1800/questionText.ref.width);
      }
    }

    let nextButton = this.g_cartoon.getCartoonElement("question_next")
    if(this.g_formData.dataArray.length>toIndex+1) {
      nextButton.active(true)
    } else {
      nextButton.active(false)
    }

    let preButton = this.g_cartoon.getCartoonElement("question_pre")
    if(toIndex>0) {
      preButton.active(true)
    } else {
      preButton.active(false)
    }
    
  }

  // submit响应事件，会标红错误
  updateStatusByGroupIndex(index) {
    let blocks = this.m_blockGroup[index];
    this.m_hasErrorLetter = false;
    blocks.forEach((item, i) => {
      item.checkStatus(true, index)
    });

    // 提交后,检查是否有错误拼写, 如果有->禁用提交按钮
    let btn  = this.g_cartoon.getCartoonElement("button_submit")
    if(!this.m_hasErrorLetter) {
      btn.switchActive(false)
      return true;
    } else {
      return false;
    }
  }

  // 跳转下一个焦点输入框
  jumpToNextActive(index) {
    let blocks = this.m_blockGroup[index];
    this.m_hasActiveBlock = false;
    
    if(!blocks[this.m_currentInputIndex]) {
      return;
    }

    let checkNextActive = () => {
      // 当遇到绿色块 或者 索引小于题目数量时，循环
      let count = 0;
      do{
        blocks[this.m_currentInputIndex] && blocks[this.m_currentInputIndex].active(false); // 当前块 取消激活
        this.m_currentInput = null;
        this.m_currentInputIndex++;
        count++;
      } while(count<blocks.length && this.m_currentInputIndex<blocks.length && blocks[this.m_currentInputIndex].isCorrect)
    }

    checkNextActive();

    if(this.m_currentInputIndex>=blocks.length) {
      // 没有获取焦点的输入框,启用提交功能
      // if(!this.m_hasActiveBlock) {
      //   let btn  = this.g_cartoon.getCartoonElement("button_submit")
      //   btn.switchActive(true);
      // }

      // 切换当前输入从头开始
      this.m_currentInputIndex = -1;
      checkNextActive();
    }
    // 判断是否需要激活(绿色不需要激活,红色或者蓝色没有文字需要激活)
    if(blocks[this.m_currentInputIndex].canSetActive()) {
      blocks[this.m_currentInputIndex].active(true)
    }
  }

  checkAllFill() {
    let empty = false;
    this.m_blockGroup.forEach(group => {
      group.forEach(block => {
        if(!empty) {
          if(block.getContentText() == "") {
            empty = true;
          }
        }
      });
    })
    return empty;
  }

  endGame() {
    console.log("游戏结束")
    this.sendResult();
    this.m_endGame = true;
    this.m_blockGroup.forEach(group => {
      group.forEach(block => {
        if(block.getContentText() == block.getRightLetter()) {
          block.switchStatus("disable")
        } else {
          block.switchStatus("wrong")
        }
      });
    });
  }

  resetAllBlockStatus() {
    this.m_blockGroup.forEach(group => {
      group.forEach(block => {
        block.blockDisable = false;
        block.switchStatus("init")
      });
    });
  }




































  // --------------------------------------------------
  // --------------  Template function  ---------------
  // --------------------------------------------------
  // --------------------------------------------------
  // --------------------------------------------------
  // 
  //                                  _________
  //                                 /         /.
  //           .-------------.      /_________/ |
  //         /             / |      |         | |
  //        /+============+\ |      | |====|  | |
  //        ||C:\>        || |      |         | |
  //        ||            || |      | |====|  | |
  //        ||            || |      |   ___   | |
  //        ||            || |      |  |166|  | |
  //        ||            ||/@@@    |   ---   | |
  //        \+============+/    @   |_________|./.
  //                          @          ..  ....'
  //        ..................@     __.'.'  ''
  //      /oooooooooooooooo//     ///
  //      /................//     /_/
  //      ------------------
  //
  // --------------------------------------------------

  @ViewChild('canvas', {static: true }) canvas: ElementRef;
  @ViewChild('wrap', {static: true }) wrap: ElementRef;
  @HostListener("window:resize", ["$event"])
  onResize(event) {
    this.g_winResizeEventStream.next();
  }
  ngOnDestroy() {
    window["curCtx"] = null;
    this.g_cartoon.stopAllAudio()
    window.cancelAnimationFrame(this.g_animationId);
  }
  ngOnInit() {
    const getData = (<any>window).courseware.getData;
    getData(data => {
      // if (window['air'].airClassInfo.user.classRole == 'tea') {
      //   if(!this.g_ForceChangeDefaultRole){
      //     this.g_teacherFlag = true;
      //   }
      // }
      // this.g_currentUser = window['air'].airClassInfo.user;
      if (data && typeof data == "object") {
        this.g_data = data;
        this.g_formData = data.contentObj;
      } else {
        this.g_data = {};
      }

      
      if (!this.g_data.contentObj) {
        this.g_data.contentObj = {};
        this.g_formData = {};
      }

      this.initDefaultData();
      this.initAudio();
      this.initImg();

       // 预加载资源
       this.g_cartoon.loadResources().then(() => {
        window["air"].hideAirClassLoading(this.g_KEY, this.g_data);
        this.initSystem();
        this.update();
        this.systemReady()
      });

      this.initListener();
    }, this.g_KEY);
  }

  // ----------------------------------
  // 初始化默认数据
  // ----------------------------------
  initDefaultData() {
    if ( Object.keys(this.g_formData).length===0 || this.g_formData.version != demoData.version ) {
      this.g_formData = demoData;
      console.log("Use default data.", this.g_formData)
    }
  }


  // ----------------------------------
  // 初始化音乐
  // ----------------------------------
  initAudio() {
    const contentObj = this.g_formData;
    if (!contentObj) {
      return;
    }
    // 添加用户上传音效
    let images:Array<string> = this.mapToAduioArray(contentObj)
    images.forEach(image => {
      this.g_cartoon.addAudio( image, image );
    });

    // 添加本地音效
    for( var key in localAudios ){
      this.g_cartoon.addAudio( key, localAudios[key] );
    }
  }

  // ----------------------------------
  // 初始化图片
  // ----------------------------------
  initImg() {
    const contentObj = this.g_formData;
    if (contentObj) {
      const addPicUrl = url => {
        if (url) {
          this.g_cartoon.addImage(url, url);
        }
      };
      let images:Array<string> = this.mapToImageArray(contentObj)
      images.forEach(image => {
        addPicUrl(image)
      });
    }
    // 添加本地图片
    for( var key in localImages ){
     this.g_cartoon.addImage( key, localImages[key] );
    }
  }


  mapDown(event) {
    event.preventDefault();
    let myStopPropagation = false;
    if (!this.g_enableMapDown) {
      return;
    }

    this.m_mapDownArray.forEach((item)=>{
      if(!myStopPropagation){
        if (this.checkClickTarget(this.g_cartoon.getCartoonElementRef(item.id))) {
          this.g_enableMapDown = false;
          if(this.m_mapDragObject[item.id]){
            this.m_mapDragObject[item.id].trigger()
            let dragElement = this.g_cartoon.getCartoonElement(item.id)
            if(dragElement){
              this.g_currentDragElementID = item.id
              this.g_dragFirstClickX = this.g_clickX
              this.g_dragFirstClickY = this.g_clickY
              this.enableMoveAsstant(()=>{
                this.m_mapDragObject[item.id].move(dragElement)
              })
            }
            myStopPropagation = true;
          }else{
            if(item.callback()){
              myStopPropagation = true;
            }
          }
        }
      }
    })
  }

  mapMove(event) {
    // event.preventDefault();
    let myStopPropagation = false;
    if (!this.g_enableMapMove) {
      return;
    }

    this.m_mapMoveArray.forEach((item)=>{
      if(!myStopPropagation){
        if (this.checkClickTarget(this.g_cartoon.getCartoonElementRef(item.id))) {
          this.g_enableMapMove = false;
          if(item.callback()){
            myStopPropagation = true;
          }
        }
      }
    })
  }

  mapUp(event) {
    // event.preventDefault();
    let myStopPropagation = false;
    if (!this.g_enableMapUp) {
      return;
    }
    this.m_mapUpArray.forEach((item)=>{
      if(!myStopPropagation){
        if (this.checkClickTarget(this.g_cartoon.getCartoonElementRef(item.id))) {
          this.g_enableMapUp = false;
          if(item.callback()){
            myStopPropagation = true;
          }
          this.g_currentDragElementID = null;
          this.disableMoveAsstant();
        }
      }
    })
  }

  update() {
    this.g_animationId = window.requestAnimationFrame(this.update.bind(this));
    // 清除画布内容
    this.g_ctx.clearRect(0, 0, this.g_canvasWidth, this.g_canvasHeight);
    TWEEN.update();
    this.updateArr(this.m_renderArr);
    this.updateArr(this.m_endPageArr);
    this.updateArr(this.m_elementPetalArr);
    this.updateArr(this.m_frontCurtainArr)
  }

  updateItem(item) {
    if (item) {
      item.update();
    }
  }

  updateArr(arr) {
    if (!arr) {
      return;
    }
    for (let i = 0; i < arr.length; i++) {
      arr[i].update(this);
    }
  }

  initListener() {
    const element = this.canvas.nativeElement;
    this.g_winResizeEventStream.pipe(debounceTime(500)).subscribe(data => {
      this.renderAfterResize();
    });
    
    const addTouchListener = () => {
      element.addEventListener('touchstart', touchDownFunc);
      element.addEventListener('touchmove', touchMoveFunc);
      element.addEventListener('touchend', touchUpFunc);
      element.addEventListener('touchcancel', touchUpFunc);
    };
    const removeTouchListener = () => {
      element.removeEventListener('touchstart', touchDownFunc);
      element.removeEventListener('touchmove', touchMoveFunc);
      element.removeEventListener('touchend', touchUpFunc);
      element.removeEventListener('touchcancel', touchUpFunc);
    };

    const addMouseListener = () => {
      element.addEventListener('mousedown', mouseDownFunc);
      element.addEventListener('mousemove', mouseMoveFunc);
      element.addEventListener('mouseup', mouseUpFunc);
    };
    const removeMouseListener = () => {
      element.removeEventListener('mousedown', mouseDownFunc);
      element.removeEventListener('mousemove', mouseMoveFunc);
      element.removeEventListener('mouseup', mouseUpFunc);
    };

    const touchDownFunc = (e) => {
      if (this.g_firstTouch) {
        this.g_firstTouch = false;
        removeMouseListener();
      }
      setMxMyByTouch(e);
      this.mapDown(e);
    };
    const touchMoveFunc = (e) => {
      setMxMyByTouch(e);
      this.mapMove(e);
    };
    const touchUpFunc = (e) => {
      setMxMyByTouch(e);
      this.mapUp(e);
    };

    const mouseDownFunc = (e) => {
      if (this.g_firstTouch) {
        this.g_firstTouch = false;
        removeTouchListener();
      }
      setMxMyByMouse(e);
      this.mapDown(e);
    };
    const mouseMoveFunc = (e) => {
      setMxMyByMouse(e);
      this.mapMove(e);
    };
    const mouseUpFunc = (e) => {
      setMxMyByMouse(e);
      this.mapUp(e);
    };

    const setMxMyByTouch = event => {
      if (event.touches.length <= 0) {
        return;
      }
      if (this.g_canvasLeft == null) {
        setParentOffset();
      }
      this.g_clickX = event.touches[0].pageX - this.g_canvasLeft;
      this.g_clickY = event.touches[0].pageY - this.g_canvasTop;
    };

    const setParentOffset = () => {
      const rect = this.canvas.nativeElement.getBoundingClientRect();
      this.g_canvasLeft = rect.left;
      this.g_canvasTop = rect.top;
    };

    const setMxMyByMouse = (event) => {
      this.g_clickX = event.offsetX;
      this.g_clickY = event.offsetY;
    };

    addMouseListener();
    addTouchListener();
  }

  showArr(arr) {
    if (!arr) {
      return;
    }
    for (let i = 0; i < arr.length; i++) {
      arr[i].visible = true;
    }
  }

  hideArr(arr) {
    if (!arr) {
      return;
    }
    for (let i = 0; i < arr.length; i++) {
      arr[i].visible = false;
    }
  }

  IsPC() {
    if (window["ELECTRON"]) {
      return false; // 封装客户端标记
    }
    if (
      document.body.ontouchmove !== undefined &&
      document.body.ontouchmove !== undefined
    ) {
      return false;
    } else {
      return true;
    }
  }

  renderAfterResize() {
    this.g_canvasWidth = this.wrap.nativeElement.clientWidth;
    this.g_canvasHeight = this.wrap.nativeElement.clientHeight;
    this.update();
    this.handleScreenResize()
  }

  checkClickTarget(target) {
    if (!target) {
      return false;
    }
    const rect = target.getBoundingBox();
    if (this.checkPointInRect(this.g_clickX, this.g_clickY, rect)) {
      return true;
    }
    return false;
  }

  getWorlRect(target) {
    let rect = target.getBoundingBox();
    if (target.parent) {
      const pRect = this.getWorlRect(target.parent);
      rect.x += pRect.x;
      rect.y += pRect.y;
    }
    return rect;
  }

  checkPointInRect(x, y, rect) {
    if (x >= rect.x && x <= rect.x + rect.width) {
      if (y >= rect.y && y <= rect.y + rect.height) {
        return true;
      }
    }
    return false;
  }

  getPosByAngle(angle, len) {
    const radian = (angle * Math.PI) / 180;
    const x = Math.sin(radian) * len;
    const y = Math.cos(radian) * len;
    return { x, y };
  }

  getPosDistance(sx, sy, ex, ey) {
    const _x = ex - sx;
    const _y = ey - sy;
    const len = Math.sqrt(Math.pow(_x, 2) + Math.pow(_y, 2));
    return len;
  }

  subscribeMapDownEvent(id,callback, zIndex?){
    zIndex = zIndex?zIndex:0
    this.m_mapDownObject.push({id:id, zIndex:zIndex?zIndex:1, callback:callback})
    this.m_mapDownObject.sort((a,b)=>{
      return b.zIndex-a.zIndex
    })
    this.m_mapDownArray = []
    this.m_mapDownObject.forEach(item=>{
      this.m_mapDownArray.push(item)
    })
  }

  subscribeMapUpEvent(id,callback, zIndex?){
    zIndex = zIndex?zIndex:0
    this.m_mapUpObject.push({id:id, zIndex:zIndex?zIndex:1, callback:callback})
    this.m_mapUpObject.sort((a,b)=>{
      return b.zIndex-a.zIndex
    })
    this.m_mapUpArray = []
    this.m_mapUpObject.forEach(item=>{
      this.m_mapUpArray.push(item)
    })
  }

  subscribeMapMoveEvent(id, callback, zIndex?){
    zIndex = zIndex?zIndex:0
    this.m_mapMoveObject.push({id:id, zIndex:zIndex?zIndex:1, callback:callback})
    this.m_mapMoveObject.sort((a,b)=>{
      return a.zIndex - b.zIndex
    })
    this.m_mapMoveArray = []
    this.m_mapMoveObject.forEach(item=>{
      this.m_mapMoveArray.push(item)
    })
  }

  subscribeMapDragEvent(id, trigger, move, release){
    this.subscribeMapDownEvent(id,()=>{})
    this.m_mapDragObject[id] = {
      trigger,
      move,
      release
    };
  }

  releaseDragElement(){
    if(this.g_currentDragElementID){
      this.m_mapDragObject[this.g_currentDragElementID].release()
    }
  }

  // 全局初始化入口，当资源加载完毕后执行
  initSystem() {
    
    this.g_canvasWidth = this.wrap.nativeElement.clientWidth;
    this.g_canvasHeight = this.wrap.nativeElement.clientHeight;

    const sx = this.g_canvasWidth / this.g_canvasBaseW;
    const sy = this.g_canvasHeight / this.g_canvasBaseH;
    const s = Math.min(sx, sy);

    this.g_mapScale = s;
    this.g_cartoon.mapScale = this.g_mapScale;
    this.g_cartoon.clientWidth = this.wrap.nativeElement.clientWidth;
    this.g_cartoon.clientHeight = this.wrap.nativeElement.clientHeight;

    this.m_renderArr = [];
    this.m_frontCurtainArr = [];
    this.m_renderObject = [];
    this.g_enableMapDown = true;

    this.g_ctx = this.canvas.nativeElement.getContext("2d");
    this.canvas.nativeElement.width = this.g_canvasWidth;
    this.canvas.nativeElement.height = this.g_canvasHeight;
    window["curCtx"] = this.g_ctx;

    // 初始化舞台
    this.initStage();
    this.update();
  }
  

  initStage() {
    const bgWidth = 1280;
    const bgHeight = 720;
    this.g_cartoon.stageWidth = bgWidth*this.g_mapScale;
    this.g_cartoon.stageHeight= bgHeight*this.g_mapScale;

    const imageColor = this.g_cartoon.createCartoonElement("g-ackground-color", "ShapeRect").ref;
    // console.log( "stageWidth: " + this.g_cartoon.stageWidth + " stageHeight" + this.g_cartoon.stageHeight)
    // console.log( "clientWidth: " + this.g_cartoon.clientWidth + " clientHeight" + this.g_cartoon.clientHeight)
    // console.log( "canvasWidth: " + this.g_canvasWidth + " canvasHeight" + this.g_canvasHeight)
    // console.log( "mapScale: " + this.g_mapScale )
    imageColor.x = this.g_cartoon.clientWidth / 2 ;
    imageColor.y = this.g_cartoon.clientHeight / 2 ;
    imageColor.setSize(this.g_cartoon.clientWidth, this.g_cartoon.clientHeight);
    imageColor.init();
    imageColor.fillColor = this.g_background_color;
    this.render(imageColor, -999999)

    const image = this.g_cartoon.createCartoonElement("bg_1280_720_Ruler", "MySprite").ref;
    image.init(this.g_cartoon.images.get("_bg_1280_720_Ruler"));
    image.x = this.g_canvasWidth / 2;
    image.y = this.g_canvasHeight /2;
    image.visible = this.g_EnableStageRuler
    this.g_cartoon.setOrigin( image.x-(bgWidth/2*this.g_mapScale), image.y-(bgHeight/2*this.g_mapScale)  )
    this.g_cartoon.setRelativeOrigin( -bgWidth/2, -bgHeight/2)
    image.setScaleXY(this.g_mapScale);
    this.render(image, -999)
    this.g_stage = image

    const topElementContainer = this.g_cartoon.createCartoonElement("_bg_1280_720", "MySprite").ref;
    topElementContainer.init(this.g_cartoon.images.get("_bg_1280_720"));
    topElementContainer.x = this.g_canvasWidth / 2;
    topElementContainer.y = this.g_canvasHeight /2;
    topElementContainer.setScaleXY(this.g_mapScale);
    this.render(topElementContainer, 9999)
    this.g_topElementContainer = topElementContainer
    
    const maskLayer = this.g_cartoon.createCartoonElement("_mask_layer_1280_720", "MySprite").ref;
    maskLayer.init(this.g_cartoon.images.get("_mask_layer_1280_720"));
    maskLayer.scaleX = this.g_canvasWidth / maskLayer.width;
    maskLayer.scaleY = this.g_canvasHeight / maskLayer.height;
    maskLayer.alpha = 0
    maskLayer.x = this.g_canvasWidth / 2;
    maskLayer.y = this.g_canvasHeight /2;
    this.render(maskLayer, this.g_maskLayerZindex)

    this.subscribeMapUpEvent("g-ackground-color", ()=>{
      if(this.g_currentDragElementID){
        this.releaseDragElement()
        this.g_currentDragElementID = null;
      }else{
        this.g_enableMapUp = true;
      }
    })
  }

  render(ele, zIndex?:number){
    this.m_renderObject.push({element:ele, zIndex:zIndex?zIndex:1})
    this.m_renderObject.sort((a,b)=>{
      return a.zIndex - b.zIndex
    })
    this.m_renderArr = []
    this.m_renderObject.forEach(item=>{
      this.m_renderArr.push(item.element)
    })    
  }

  sendServerEvent(key, data) {
    const c = (<any> window).courseware;
    c.sendEvent(key, JSON.stringify(data));
  }

  addServerListener(msg_key, callback) {
    const c = (<any> window).courseware;
    c.onEvent(msg_key, (data,next) => {
      callback(JSON.parse(data))
      next && next();
    });
  }

  randomArray_shuffle(array) {
    var input = array;
    for (var i = input.length-1; i >=0; i--) {
        var randomIndex = Math.floor(Math.random()*(i+1));
        var itemAtIndex = input[randomIndex];
        input[randomIndex] = input[i];
        input[i] = itemAtIndex;
    }
    return input;
  }

  paginationArray(pageNo, pageSize, array) {
    var offset = (pageNo - 1) * pageSize;
    return (offset + pageSize >= array.length) ? array.slice(offset, array.length) : array.slice(offset, offset + pageSize);
  }

  stopAllTimeout(){
    this.m_setTimeoutIDs.forEach(id=>clearTimeout(id))
    this.m_setTimeoutIDs = []
  }

  stopAllInterval(){
    this.m_setIntervalIDs.forEach(id=>clearInterval(id))
    this.m_setIntervalIDs = []
  }

  topOfRenderArray(element){
    let index = this.m_renderArr.indexOf(element)
    if(index !=-1){
      this.m_renderArr.splice(index, 1)
      this.m_renderArr.push(element)
    }
  }

  setRenderZIndex(element, zIndex){
    let index = null;
    for(let i=0; i<this.m_renderObject.length; i++){
      if( this.m_renderObject[i].element.id == element.id ){
        index = i
      }
    }
    if(index){
      this.m_renderObject.splice(index, 1)
      this.m_renderObject.push({element:element, zIndex:zIndex?zIndex:1})
      this.m_renderObject.sort((a,b)=>{
        return a.zIndex - b.zIndex
      })
  
      this.m_renderArr = []
      this.m_renderObject.forEach(item=>{
        this.m_renderArr.push(item.element)
      })
    }
  }
  
  deleteElementInRender(id){
    let index = null;
    for(let i=0; i<this.m_renderObject.length; i++){
      if( this.m_renderObject[i].element.id == id ){
        index = i
      }
    }
    if(index){
      this.m_renderObject.splice(index, 1)
      this.m_renderObject.sort((a,b)=>{
        return a.zIndex - b.zIndex
      })
      this.m_renderArr = []
      this.m_renderObject.forEach(item=>{
        this.m_renderArr.push(item.element)
      })
    }else{
      console.warn("Can not found element id:" + id)
    }
  }

  enableMoveAsstant(callback){
    if (this.m_moveAsstantIntervalId) {
      this.g_enableDragging = false;
      clearInterval(this.m_moveAsstantIntervalId)
    }
    this.m_moveAsstantIntervalId = setInterval(() => {
      if(this.g_enableDragging){
        callback()
      }else{
        let moveX = Math.abs(this.g_dragFirstClickX - this.g_clickX)
        let moveY = Math.abs(this.g_dragFirstClickY - this.g_clickY)
        if (moveX > this.g_enableDragDistance || moveY > this.g_enableDragDistance) {
          this.g_enableDragging = true;
        }
      }
    }, 50)
  }

  disableMoveAsstant(){
    this.g_enableDragging = false;
    clearInterval(this.m_moveAsstantIntervalId)
  }

  cleanSystemVar(){
    this.m_mapDownQueue = {}
    this.m_mapDownArray = []
    this.m_mapDownObject = []
    this.m_mapMoveArray = []
    this.m_mapMoveObject = []
    this.m_mapUpQueue = {}
    this.m_mapUpArray = []
    this.m_mapUpObject = []
    this.m_mapDragQueue = []
    this.m_mapDragArray = []
    this.m_mapDragObject = []
    this.stopAllInterval();
    this.stopAllTimeout()
    this.g_cartoon.stopAllAudio()
    this.resetLongAudio();
  }

  getMaxSubstringLength(str){
    let maxLength = 0;
    let subSubstring = str.split(" ")
    for (let index=0; index<subSubstring.length; index++) {
      if(subSubstring[index].length > maxLength){
        maxLength = subSubstring[index].length;
      }
    }
    return maxLength
  }

  setLeftCornerTest(){
    const bgRect = new ShapeRect();
    bgRect.setSize(57, 65);
    bgRect.fillColor = '#f8c224';
    const sx = this.g_canvasWidth / this.g_canvasBaseW;
    bgRect.setScaleXY(sx);
    bgRect.x = 65 * sx;
    this.g_partTitle_x = bgRect.x
    this.g_mainTitle_x = bgRect.x + 80 * sx
    bgRect.alpha = 0.5
    bgRect.visible = this.g_showLeftCornerTest
    this.render(bgRect, 9999);
  }

  alignCenter(elementArray, spacing, laseX = 0, withAni?, callback?){
    let totlaWidth = 0
    let length = elementArray.length
    elementArray.forEach(element => {
      let bd = element.ref.getBoundingBox()
      totlaWidth += bd.width
    });
    totlaWidth += (elementArray.length-1) * spacing
    // laseX = laseX? laseX: this.g_canvasWidth / 2 - totlaWidth/2;
    elementArray.forEach((element, index) => {
      let bd = element.ref.getBoundingBox()
      if(withAni){
        tweenChange(element.ref, {x: laseX + bd.width / 2}, 0.2, ()=>{
          this.g_cartoon.saveSize(element.id)
          if(length == (index+1)){
            callback && callback()
          }
        })
      }else{
        element.ref.x = laseX + bd.width / 2
        this.g_cartoon.saveSize(element.id)
        if(length == (index+1)){
          callback && callback()
        }
      }

      laseX = (laseX + bd.width + spacing)
    });
    return totlaWidth
  }

  alignLeft(elementArray, spacing, startX = 0, withAni?, callback?){
    let laseX = startX;
    elementArray.forEach((element, index) => {
      let bd = element.ref.getBoundingBox()
      if(withAni){
        tweenChange(element.ref, {x: laseX + bd.width / 2}, 0.2, ()=>{
          this.g_cartoon.saveSize(element.id)
          if(length == (index+1)){
            callback && callback()
          }
        })
      }else{
        element.ref.x = laseX + bd.width / 2
        this.g_cartoon.saveSize(element.id)
        if(length == (index+1)){
          callback && callback()
        }
      }

      laseX = (laseX + bd.width + spacing)
    });
  }

  createTestLine(x, y, height, color?){
    var colorAll = ['#ff0000','#eb4310','#f6941d','#fbb417','#ffff00','#cdd541','#99cc33','#3f9337','#219167','#239676','#24998d','#1f9baa','#0080ff','#3366cc','#333399','#003366','#800080','#a1488e','#c71585','#bd2158'];
    color = color ? color : colorAll[Math.floor(Math.random()*20)]
    this.render(this.g_cartoon.createRectangula({
      width: 5,
      height: height,
      x: x,
      y: y,
      fillColor: color
    }), 9999)
  }

  getSuitSizeBackground(key, width){
    let bgAll = multiSizeBackground[key]
    if(!bgAll){
      return ""
    }
    let suitFileName = ""
    for(let fileName in bgAll){
      if(  Number(fileName) >= width){
        suitFileName = bgAll[fileName]
        break
      }
    }
    return suitFileName
  }












  













  












  // --------------------------------------------------
  // --------------  Template function  ---------------
  // --------------------------------------------------
  // --------------------------------------------------
  // --------------------------------------------------
  // 
  //                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
  //            __.'              ~.   .~              `.__
  //          .'//                  \./                  \\`.
  //        .'//                     |                     \\`.
  //      .'// .-~"""""""~~~~-._     |     _,-~~~~"""""""~-. \\`.
  //    .'//.-"                 `-.  |  .-'                 "-.\\`.
  //  .'//______.============-..   \ | /   ..-============.______\\`.
  //.'______________________________\|/______________________________`.
  //
  // --------------------------------------------------
  // showParticle( element_id )                 泡泡效果
  // --------------------------------------------------
  // showEndPatal()  /  stopEndPatal()  花瓣飘落结束动画 
  // --------------------------------------------------
  // showCorrectPatal()                 指定元素上面飘花
  // --------------------------------------------------
  // convertPercentToRadian()   将百分比转换为弧长 第一个参数是百分比，第二个参数是方向 true为逆时针，false为顺时针。用于ShapeCircle换圆弧
  // --------------------------------------------------
  // movePaoWuxian()                        元素抛物线跳
  // --------------------------------------------------
  // showJellyAnimation()------------------------------
  // showBlingStar()----------------------显示星星效果--
  // --------------------------------------------------
  


  maskLayerShow(isShow, time) {
    let element = this.g_cartoon.getCartoonElement("_mask_layer_1280_720")
    if(isShow) {
      tweenChange(element.ref, {alpha: 1}, time)
    } else {
      tweenChange(element.ref, {alpha: 0}, time)
    }
  }

  // 泡泡
  showParticle(card) {
    let myCard = this.g_cartoon.getCartoonElementRelativePosition(card.id)
    showPopParticle(this.g_cartoon.images.get("_bubble"), { x: myCard.x , y: myCard.y }, this.g_stage);
  }

  // 选择正确动画
  showCorrectPatal(card_id, showTime, callback?) {
    this.m_elementPetalArr = [];
    this.m_showElementPetalFlag = true;
    this.addCorrectPetal(card_id);
    setTimeout(()=>{
      this.m_elementPetalArr = [];
      this.m_showElementPetalFlag = false;
      callback && callback()
    },showTime)
  }
  stopAllCorrectPatal(){
    this.m_elementPetalArr = [];
    this.m_showElementPetalFlag = false;
  }

  addCorrectPetal(card_id) {
    if (!this.m_showElementPetalFlag) {
      return;
    }

    let element = this.g_cartoon.getCartoonElement(card_id)
    const petal = new MySprite(this.g_ctx);

    const id = Math.ceil(Math.random() * 3);
    petal.init(this.g_cartoon.images.get(this.m_PetalImage + id));

    const randomS = (Math.random() * 0.4 + 0.6) * this.g_mapScale * 0.5;
    petal.setScaleXY(randomS);

    const randomR = Math.random() * 360;
    petal.rotation = randomR;

    const randomX = Math.random() * element.ref.width * this.g_mapScale;

    petal.x = element.ref.x - (element.ref.width * this.g_mapScale / 2) + randomX;
    petal.y = element.ref.y - (element.ref.height * this.g_mapScale / 2);

    const randomT = 1 + Math.random() * 2;
    petal["time"] = randomT;

    let randomTR = 360 * Math.random(); // - 180;
    if (Math.random() < 0.5) {
      randomTR *= -1;
    }
    petal["tr"] = randomTR;

    this.m_elementPetalArr.push(petal);
    moveItem(
      petal,
      petal.x,
      element.ref.y + (element.ref.height * this.g_mapScale / 2),
      petal["time"],
      () => {
        removeItemFromArr(this.m_elementPetalArr, petal);
      }
    );
    rotateItem(petal, petal["tr"], petal["time"]);
    setTimeout(() => {
      this.addCorrectPetal(card_id);
    }, 200);
  }


  // 结束动画花瓣飘落
  showEndPatal() {
    this.m_endPageArr = [];
    this.m_showPetalFlag = true;
    this.addPetal();
  }

  stopEndPatal() {
    this.m_endPageArr = [];
    this.m_showPetalFlag = false;
  }

  addPetal() {
    if (!this.m_showPetalFlag) {
      return;
    }
    const petal = this.getPetal();
    this.m_endPageArr.push(petal);
    moveItem(
      petal,
      petal.x,
      this.g_canvasHeight + petal.height * petal.scaleY,
      petal["time"],
      () => {
        removeItemFromArr(this.m_endPageArr, petal);
      }
    );
    rotateItem(petal, petal["tr"], petal["time"]);
    setTimeout(() => {
      this.addPetal();
    }, 100);
  }

  getPetal() {
    const petal = new MySprite(this.g_ctx);

    const id = Math.ceil(Math.random() * 3);
    petal.init(this.g_cartoon.images.get(this.m_PetalImage + id));

    const randomS = (Math.random() * 0.4 + 0.6) * this.g_mapScale;
    petal.setScaleXY(randomS);

    const randomR = Math.random() * 360;
    petal.rotation = randomR;

    const randomX = Math.random() * this.g_canvasWidth;
    petal.x = randomX;
    petal.y = (-petal.height / 2) * petal.scaleY;

    const randomT = 2 + Math.random() * 5;
    petal["time"] = randomT;

    let randomTR = 360 * Math.random(); // - 180;
    if (Math.random() < 0.5) {
      randomTR *= -1;
    }
    petal["tr"] = randomTR;

    return petal;
  }

  buttonPressAnimation(buttonID, shadowID?, callback?) {
    let button = buttonID ? this.g_cartoon.getCartoonElement(buttonID).ref : null;
    let shadow = shadowID ? this.g_cartoon.getCartoonElement(shadowID).ref : null;

    let pAll = []
    pAll.push(new Promise((resovle, reject) => {
      let initY = button.y
      button.y += 10
      tweenChange(button,{ scaleX: button.initScaleX * 1.02 , scaleY: button.initScaleY * 1.02 }, 0.05, ()=>{
        tweenChange(button,{ scaleX: button.initScaleX * 0.98 , scaleY: button.initScaleY * 0.98 }, 0.05, ()=>{
          tweenChange(button,{ scaleX: button.initScaleX , scaleY: button.initScaleY }, 0.1, ()=>{
            button.y = initY;
            callback && callback()
            resovle(null)
          })
        })
      })
    }))
    
    if(shadow) {
      pAll.push(new Promise((resovle, reject) => {
        let initY = shadow.y
        shadow.y -= 10
        tweenChange(shadow,{ scaleX: shadow.initScaleX * 1.02 , scaleY: shadow.initScaleY * 1.02 }, 0.05, ()=>{
          tweenChange(shadow,{ scaleX: shadow.initScaleX * 0.98 , scaleY: shadow.initScaleY * 0.98 }, 0.05, ()=>{
            tweenChange(shadow,{ scaleX: shadow.initScaleX , scaleY: shadow.initScaleY }, 0.1, ()=>{
              shadow.y = initY;
              callback && callback()
              resovle(null)
            })
          })
        })
      }))
    }
    return Promise.all(pAll)
  }

  showJellyAnimation(element_id, callback?){
    let element = this.g_cartoon.getCartoonElement(element_id).ref
    tweenChange(element,{ scaleX: element.initScaleX * 1.02 , scaleY: element.initScaleY * 1.02 }, 0.05, ()=>{
      tweenChange(element,{ scaleX: element.initScaleX * 0.98 , scaleY: element.initScaleY * 0.98 }, 0.05, ()=>{
        tweenChange(element,{ scaleX: element.initScaleX , scaleY: element.initScaleY }, 0.1, ()=>{
          callback && callback()
        })
      })
    })
  }

  showShakeAnimation(element_id, callback?){
    let element = this.g_cartoon.getCartoonElement(element_id).ref
    let originX = element.x
    tweenChange(element,{ x: originX - 10*this.g_mapScale }, 0.1, ()=>{
      tweenChange(element,{ x: originX + 10*this.g_mapScale }, 0.1, ()=>{
        tweenChange(element,{ x: originX }, 0.1, ()=>{
          callback && callback()
        })
      })
    })
  }

  convertPercentToRadian(per, direction){
    let radian = 0;
    if(direction) { //逆时针
      if(per*360 > 270){
        radian = 361 - (per*360 - 270)
      }else{
        radian = 270 - per*360
      }
    }else{ //顺时针
      if(per*360 > 90){
        radian = per*360 - 90
      }else{
        radian = 270 + per*360
      }
    }
    return (radian * Math.PI) / 180;
  }

  showBlingStar(element, callback?){
    let rect =  element.getBoundingBox()
    showBlingBling(this.g_cartoon.images.get('icon_star'), rect, element, 0.5, 1, 0.08, 0.5);
    this.m_setTimeoutIDs.push(setTimeout(() => {
      callback && callback()
    }, 2000))
    // setTimeout(()=>{
    //   showBlingBling(this.g_cartoon.images.get('icon_star'), rect, element, 0.5, 1, 0.08, 1.8);
    // },200)
    // setTimeout(()=>{
    //   showBlingBling(this.g_cartoon.images.get('icon_star'), rect, element, 0.5, 1, 0.08, 1.6);
    // },400)
  }

  movePaoWuxian(element,dis,time,callback?){
    let disX = dis.x - element.x
    let disY = (element.y - dis.y) 
    let count = 0
    let runTime = time/5
    let vx = disX/runTime
    let a = -0.05
    let vy0 = disY/runTime - 0.5*a*runTime
    let id = setInterval(()=>{
      element.x += vx
      element.y -= vy0 + a*count
      count++;
      if(count>runTime){
        clearInterval(id)
        callback && callback()
      }
    }, 5);
  }

  showBalloons(maxBalloon = 10) {
    let balloonImgList = [
      "_balloon_blue",
      "_balloon_green",
      "_balloon_orange",
      "_balloon_pink",
      "_balloon_red",
      "_balloon_yellow",
    ];
  
    for (var i = 0; i < maxBalloon; ++i) {
      let balloon = new MySprite();
      balloon.init(
        this.g_cartoon.images.get(balloonImgList[this.randomInt(balloonImgList.length)])
      );
      let leftBorder = -640;
      let rightBorder = 640;
      balloon.x = this.randomInt(leftBorder, rightBorder);
      balloon.y = 720 / 2 + this.randomInt(400);
      this.g_topElementContainer.addChild(balloon);
  
      balloon.scaleX = 0;
      balloon.scaleY = 0;
      tweenChange(
        balloon, {
          scaleX: 1 + Math.random() * 0.3 - 0.15,
          scaleY: 1 + Math.random() * 0.3 - 0.15,
        },
        0.5
      );
  
      let wholeTime = 3;
      if (i < 4) {
        wholeTime = 3 + i;
      }
  
      tweenChange(
        balloon,
        { y: -720 / 2 - this.randomInt(200) },
        wholeTime,
        ()=>{
          this.g_topElementContainer.removeChild(balloon)
        },
        TWEEN.Easing.Quadratic.In
      );
  
      let time = Math.random() * wholeTime;
      tweenChange(
        balloon,
        {
          x: this.Between(
            leftBorder,
            rightBorder,
            balloon.x + Math.min(time * 50, this.randomInt(200))
          ),
        },
        time,
        () => {
          tweenChange(
            balloon,
            {
              x: this.Between(
                leftBorder,
                rightBorder,
                balloon.x - Math.min(time * 50, this.randomInt(200))
              ),
            },
            wholeTime - time
          );
        }
      );
    }
  }

  randomInt(a, b = 0) {
    let max = Math.max(a, b);
    let min = Math.min(a, b);
    return Math.floor(Math.random() * (max - min) + min);
  }

  Between(a, b, c) {
    return [a, b, c].sort((a, b) => a - b)[1];
  }

}