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

import {
  Label,
  MySprite, tweenChange,
  ShapeRect, randomSortByArr, rotateItem, moveItem, removeItemFromArr
} from './Unit';
import { res, resAudio } from './resources';

import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

import TWEEN from '@tweenjs/tween.js';

import {
  setRectFontSize,
  getRandomItemFromArr
} from './MyUtil';

import {
  FloorInfo
} from './FloorInfo';

import {
  Exercises
} from './Exercises';

import { constants } from 'buffer';

@Component({
  selector: 'app-play',
  templateUrl: './play.component.html',
  styleUrls: ['./play.component.css']
})
export class PlayComponent implements OnInit, OnDestroy {

  @ViewChild('canvas', { static: true }) canvas: ElementRef;
  @ViewChild('wrap', { static: true }) wrap: ElementRef;

  // 数据
  data;

  ctx;

  canvasWidth = 1280; // canvas实际宽度
  canvasHeight = 720; // canvas实际高度

  canvasBaseW = 1280; // canvas 资源预设宽度
  canvasBaseH = 720;  // canvas 资源预设高度

  mx; // 点击x坐标
  my; // 点击y坐标


  // 资源
  rawImages = new Map(res);
  rawAudios = new Map(resAudio);

  images = new Map();

  animationId: any;
  winResizeEventStream = new Subject();

  audioObj = {};

  renderArr = [];

  endRenderArr = [];

  mapScale = 1;

  canvasLeft;
  canvasTop;

  saveKey = 'DF-L208';

  canTouch = true;

  canPlay = false;

  canClickMonkey = false;

  canOverCard = true;

  showPetalStatus = false;

  /**背景图片 */
  bg;

  btnStart;

  btnRestart;

  /**桃子 */
  peach;

  /**楼层信息 */
  floorInfo

  /**练习题 */
  exercisesArr = [];

  /**左边猴子 */
  leftMonkey;

  /**右边猴子 */
  rightMonkey;

  /**绳子挂卡片的坐标 */
  cardXArr = [];

  /**遮罩层 */
  cover;

  /**大桃子 */
  bigPeach;

  /**背景光 */
  bigLight;

  @HostListener('window:resize', ['$event'])
  onResize(event) {
    this.winResizeEventStream.next();
  }


  ngOnInit() {

    this.data = {};

    // 获取数据
    const getData = (<any>window).courseware.getData;
    getData((data) => {

      if (data && typeof data == 'object') {
        this.data = data;
      }
      console.log('data:', data);

      // 初始化 各事件监听
      this.initListener();

      // 若无数据 则为预览模式 需要填充一些默认数据用来显示
      this.initDefaultData();

      // 初始化 音频资源
      this.initAudio();
      // 初始化 图片资源
      this.initImg();
      // 开始预加载资源
      this.load();

    }, this.saveKey);

  }

  ngOnDestroy() {
    window['curCtx'] = null;
    window.cancelAnimationFrame(this.animationId);
  }


  load() {

    // 预加载资源
    this.loadResources().then(() => {
      window["air"].hideAirClassLoading(this.saveKey, this.data);
      this.init();
      this.update();
    });
  }


  init() {

    this.initCtx();
    this.initData();
    this.initView();
  }

  initCtx() {
    this.canvasWidth = this.wrap.nativeElement.clientWidth;
    this.canvasHeight = this.wrap.nativeElement.clientHeight;
    this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
    this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;


    this.ctx = this.canvas.nativeElement.getContext('2d');
    this.canvas.nativeElement.width = this.canvasWidth;
    this.canvas.nativeElement.height = this.canvasHeight;

    window['curCtx'] = this.ctx;
  }






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

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







  initListener() {

    this.winResizeEventStream
      .pipe(debounceTime(500))
      .subscribe(data => {
        this.renderAfterResize();
      });


    // ---------------------------------------------
    const setParentOffset = () => {
      const rect = this.canvas.nativeElement.getBoundingClientRect();
      this.canvasLeft = rect.left;
      this.canvasTop = rect.top;
    };
    const setMxMyByTouch = (event) => {
      if (event.touches.length <= 0) {
        return;
      }
      if (this.canvasLeft == null) {
        setParentOffset();
      }
      this.mx = event.touches[0].pageX - this.canvasLeft;
      this.my = event.touches[0].pageY - this.canvasTop;
    };

    const setMxMyByMouse = (event) => {
      this.mx = event.offsetX;
      this.my = event.offsetY;
    };
    // ---------------------------------------------


    let firstTouch = true;

    const touchDownFunc = (e) => {
      if (firstTouch) {
        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 (firstTouch) {
        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 element = this.canvas.nativeElement;

    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);
    };

    addMouseListener();
    addTouchListener();
  }


  playAudio(key, now = false, callback = null) {

    const audio = this.audioObj[key];
    if (audio) {
      if (now) {
        audio.pause();
        audio.currentTime = 0;
      }

      if (callback) {
        audio.onended = () => {
          callback();
        };
      }
      audio.play();
    }
  }



  loadResources() {
    const pr = [];
    this.rawImages.forEach((value, key) => {// 预加载图片

      const p = this.preload(value)
        .then(img => {
          this.images.set(key, img);
        })
        .catch(err => console.log(err));

      pr.push(p);
    });

    this.rawAudios.forEach((value, key) => {// 预加载音频

      const a = this.preloadAudio(value)
        .then(() => {
          // this.images.set(key, img);
        })
        .catch(err => console.log(err));

      pr.push(a);
    });
    return Promise.all(pr);
  }

  preload(url) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      // img.crossOrigin = "anonymous";
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.src = url;
    });
  }

  preloadAudio(url) {
    return new Promise((resolve, reject) => {
      const audio = new Audio();
      audio.oncanplay = (a) => {
        resolve();
      };
      audio.onerror = () => {
        reject();
      };
      audio.src = url;
      audio.load();
    });
  }


  renderAfterResize() {
    this.canvasWidth = this.wrap.nativeElement.clientWidth;
    this.canvasHeight = this.wrap.nativeElement.clientHeight;
    this.init();
  }





  checkClickTarget(target) {

    const rect = target.getBoundingBox();

    if (this.checkPointInRect(this.mx, this.my, 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;
  }





  addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) {

    const audioObj = this.audioObj;

    if (url == null) {
      url = key;
    }

    this.rawAudios.set(key, url);

    const audio = new Audio();
    audio.src = url;
    audio.load();
    audio.loop = loop;
    audio.volume = vlomue;

    audioObj[key] = audio;

    if (callback) {
      audio.onended = () => {
        callback();
      };
    }
  }

  addUrlToImages(url) {
    this.rawImages.set(url, url);
  }






  // ======================================================编写区域==========================================================================





  /**
   * 添加默认数据 便于无数据时的展示
   */
  initDefaultData() {

    if (!this.data.exercises) {

      this.data.exercises = [];

      for (let i = 0; i < 5; ++i) {

        let contentItem;

        if (i % 2 == 0) {
          contentItem = this.getDefaultContentItem('Hello', null);
        }
        else if (i % 3 == 0) {
          contentItem = this.getDefaultContentItem('World', null);
        }
        else {
          contentItem = this.getDefaultContentItem('Lion', null);
        }


        this.data.exercises.push(contentItem);

      }
    }
  }

  /**
   * 
   * @param text 
   * @param pic_url 
   */
  getDefaultContentItem(text, pic_url) {
    let content = {
      text: text,
      pic_url: pic_url,
      audio_url: this.rawAudios.get('click')
    }

    return content;
  }


  /**
   * 添加预加载图片
   */
  initImg() {

    for (let i = 0; i < this.data.exercises.length; ++i) {

      let exercises = this.data.exercises[i];

      this.addUrlToImages(exercises.pic_url);
    }

  }

  /**
   * 添加预加载音频
   */
  initAudio() {

    // 音效
    this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3);
    this.addUrlToAudioObj('peachShow', this.rawAudios.get('peachShow'));

    this.addUrlToAudioObj('monkey', this.rawAudios.get('monkey'));

    this.addUrlToAudioObj('spring', this.rawAudios.get('spring'));

    this.addUrlToAudioObj('win', this.rawAudios.get('win'));

    for (let i = 0; i < this.data.exercises.length; ++i) {

      let exercises = this.data.exercises[i];

      this.addUrlToAudioObj(exercises.audio_url);
    }

  }



  /**
   * 初始化数据
   */
  initData() {

    const sx = this.canvasWidth / this.canvasBaseW;
    const sy = this.canvasHeight / this.canvasBaseH;
    const s = Math.min(sx, sy);
    this.mapScale = s;

    this.canPlay = false;

    this.renderArr = [];

    this.endRenderArr = [];

    this.btnRestart = {};

    this.btnStart = {};

    this.peach = {};

    this.exercisesArr = [];

    this.leftMonkey = {};

    this.rightMonkey = {};

    this.cardXArr = [];

    this.bigLight = {};

    this.bigPeach = {};

    this.showPetalStatus = false;

    //绳子X坐标(从下往上)
    const initCardX = () => {

      //第一根
      this.cardXArr.push(this.canvasWidth / 2 - 90 * this.mapScale);

      //第二根
      this.cardXArr.push(this.canvasWidth / 2 + 114 * this.mapScale);

      //第三根
      this.cardXArr.push(this.canvasWidth / 2 - 60 * this.mapScale);

      //第四根
      this.cardXArr.push(this.canvasWidth / 2 + 64 * this.mapScale);

      //第五根
      this.cardXArr.push(this.canvasWidth / 2);

    };

    initCardX();

    this.canOverCard = true;
  }



  /**
   * 初始化试图
   */
  initView() {


    this.initBackground();

    this.initFloorPic();

    this.initBottomPart();

    this.initPeachPic();

    this.initMonkeyPic();

    this.initEndPic();
  }

  initBottomPart() {

    const btnStart = new MySprite();
    btnStart.init(this.images.get('start'));
    btnStart.setScaleXY(this.mapScale);
    btnStart.x = this.canvasWidth - 50 * this.mapScale - btnStart.getBoundingBox().width / 2;
    btnStart.y = this.canvasHeight - 100 * this.mapScale;

    this.renderArr.push(btnStart);

    this.btnStart.sprite = btnStart;
  }

  /**
   * 初化背景
   */
  initBackground() {

    const bg_pic = new MySprite();
    bg_pic.init(this.images.get("bg"));
    bg_pic.x = this.canvasWidth / 2;
    bg_pic.y = this.canvasHeight / 2;
    bg_pic.setScaleXY(Math.max(this.canvasWidth / bg_pic.width, this.canvasHeight / bg_pic.height));

    this.bg = bg_pic;

    this.renderArr.push(bg_pic);


  }

  /**
   * 初始化楼层信息
   */
  initFloorPic() {

    //取练习题
    let exercisesArr = this.data.exercises;

    //打乱数组
    let newExercisesArr = randomSortByArr(exercisesArr);

    let startY = this.canvasHeight - 100 * this.mapScale;

    const floorInfo = new FloorInfo();

    //初始楼层信息
    for (let i = 0; i < this.data.exercises.length; ++i) {

      //绳子图片索引
      let ropeIndex = 5 - this.data.exercises.length + i + 1;
 
      floorInfo.addFloor(startY, this.cardXArr[ropeIndex - 1]);

      let ropeImgKey = "rope_";

      if(this.data.exercises.length == 4){
        if(ropeIndex == 5){
          ropeImgKey = ropeImgKey + "5_l";
        }
        else{
          ropeImgKey = ropeImgKey + ropeIndex;
        }
      }
      else if(this.data.exercises.length == 5){
        if(ropeIndex == 4){
          ropeImgKey = ropeImgKey + "4_l";
        }
        else{
          ropeImgKey = ropeImgKey + ropeIndex;
        }
      }
      else{
        ropeImgKey = ropeImgKey + ropeIndex;
      }

      const rope = new MySprite();
      rope.init(this.images.get(ropeImgKey));
      rope.setScaleXY(this.bg.scaleY);

      rope.x = this.canvasWidth / 2;
      rope.y = startY - rope.getBoundingBox().height / 2;

      let exercises = newExercisesArr[i];

      //取出楼层信息
      let floor = floorInfo.floors[i];

      this.initCardPic(exercises, floor, i);

      this.renderArr.push(rope);

      startY = startY - 118 * this.mapScale;

    }

    this.floorInfo = floorInfo;
  }

  /**
   * 初始化卡片
   */
  initCardPic(exercises, floor, index) {

    let cardObj = new Exercises();
    cardObj.index = index;
    cardObj.audioUrl = exercises.audio_url;


    //卡片背面
    const cardBack = new MySprite();
    cardBack.init(this.images.get("card-bg"));
    cardBack.setScaleXY(this.mapScale);
    cardBack.alpha = 0;
    cardObj.back = cardBack;

    const cardBaseboard = new ShapeRect();
    cardBaseboard.setSize(cardBack.getBoundingBox().width, cardBack.getBoundingBox().height);
    cardBaseboard.alpha = 0;
    cardBaseboard.x = floor.cardX - cardBaseboard.getBoundingBox().width / 2;
    cardBaseboard.y = floor.startY - 7 * this.mapScale;
    cardObj.baseboard = cardBaseboard;

    //卡片发光
    const cardLight = new MySprite();
    cardLight.init(this.images.get("card-light"));
    cardLight.setScaleXY(this.mapScale);
    cardLight.alpha = 0;
    cardLight.x = cardBaseboard.getBoundingBox().width / 2;
    cardLight.y = cardBaseboard.getBoundingBox().height / 2;
    cardObj.light = cardLight;
    cardBaseboard.addChild(cardLight);

    

    //卡片正面
    const cardFront = new MySprite();
    cardFront.init(this.images.get("card-front"));
    cardFront.setScaleXY(this.mapScale);
    cardFront.x = cardLight.x;
    cardFront.y = cardLight.y;
    cardFront.alpha = 0;
    cardFront.visible = true;
    cardObj.front = cardFront;
    cardBaseboard.addChild(cardFront);

    cardBack.x = cardLight.x;
    cardBack.y = cardLight.y;
    cardBaseboard.addChild(cardBack);


    //设置内容
    this.setContent(exercises, cardFront, cardObj);

    cardFront.childDepandAlpha = true;

    this.renderArr.push(cardBaseboard);

    this.exercisesArr.push(cardObj);

  }

  /**
   * 设置内容
   */
  setContent(content, parItem, card) {

    //图片存在，则渲染图片
    if (content.pic_url) {

      const content_pic = new MySprite();
      content_pic.init(this.images.get(content.pic_url));
      content_pic.alpha = 0;

      let w = content_pic.width;

      let h = content_pic.height;

      let scale = Math.min((parItem.height - 25 * this.mapScale) / h, (parItem.width - 25 * this.mapScale) / w);

      content_pic.setScaleXY(scale);

      content_pic.x = 0;
      content_pic.y = 0;
      parItem.addChild(content_pic);

      card.contentType = 'P';

      card.contentSprite = content_pic;
    }
    else {
      let content_val = new Label();
      content_val.text = content.text;
      content_val.textAlign = 'middle';
      content_val.fontSize = 120;
      content_val.fontName = "BRLNSDB";
      content_val.fontColor = "#A52A2A";
      content_val.alpha = 0;

      content_val.refreshSize();

      setRectFontSize(parItem.width - 25 * this.mapScale, parItem.height - 25 * this.mapScale, content_val);

      content_val.refreshSize();

      content_val.x = - content_val.getBoundingBox().width / 2 + 5 * this.mapScale;

      parItem.addChild(content_val);

      card.contentType = 'T';

      card.contentSprite = content_val;
    }

  }

  /**
   * 初始化桃子
   */
  initPeachPic() {

    //桃子发光
    const peachLight = new MySprite();
    peachLight.init(this.images.get("peach-light"));
    peachLight.setScaleXY(this.mapScale);
    peachLight.alpha = 0;
    peachLight.x = this.canvasWidth / 2;
    peachLight.y = this.floorInfo.getTopFloor().startY - peachLight.getBoundingBox().height / 2 - 15 * this.mapScale;

    //桃子图片
    const peach = new MySprite();
    peach.init(this.images.get("peach"));
    peach.setScaleXY(this.mapScale);
    peach.x = 0;
    peach.y = 0;

    peachLight.addChild(peach);


    this.renderArr.push(peachLight);

    peach.setScaleXY(0);

    this.peach = { light: peachLight, peach: peach, initX: peachLight.x, initY: peachLight.y };
  }

  /**
   * 初始化猴子
   */
  initMonkeyPic() {

    const initMonekey = (flag, monkeyObj) => {
      //猴子发光
      const light = new MySprite();
      light.init(this.images.get(flag + "-monkey-light"));
      light.setScaleXY(this.mapScale);
      light.alpha = 0;
      light.x = light.getBoundingBox().width / 2;
      light.y = light.getBoundingBox().height / 2;
      monkeyObj.light = light;

      //猴子底板
      const baseboard = new ShapeRect();
      baseboard.setSize(light.getBoundingBox().width, light.getBoundingBox().height);
      baseboard.alpha = 0;
      baseboard.y = this.canvasHeight - baseboard.getBoundingBox().height + 30 * this.mapScale;
      monkeyObj.baseboard = baseboard;
      monkeyObj.initY = baseboard.y;

      baseboard.addChild(light);

      //猴子
      const monkey = new MySprite();
      monkey.init(this.images.get(flag + "-monkey"));
      monkey.setScaleXY(this.mapScale);
      monkey.x = light.x;
      monkey.y = light.y;
      monkeyObj.monkey = monkey;
      baseboard.addChild(monkey);

      //默认为当前楼层
      monkeyObj.curFloor = 0;

      monkeyObj.flag = flag;

      this.renderArr.push(baseboard);


    }

    //初始化左边猴子
    initMonekey('l', this.leftMonkey);
    this.leftMonkey.baseboard.x = - this.leftMonkey.baseboard.getBoundingBox().width;
    this.leftMonkey.initX = this.leftMonkey.baseboard.x;

    //初始化右边猴子
    initMonekey('r', this.rightMonkey);
    this.rightMonkey.baseboard.x = this.canvasWidth + this.rightMonkey.baseboard.getBoundingBox().width;
    this.rightMonkey.initX = this.rightMonkey.baseboard.x;
  }

  /**
   * 初始化结束界面
   */
  initEndPic() {

    //灰色透明背景
    const cover = new ShapeRect();
    cover.setSize(this.canvasWidth, this.canvasHeight);
    cover.fillColor = "#696969";
    cover.alpha = 0;
    cover.x = 0;
    cover.y = 0;
    this.endRenderArr.push(cover);
    this.cover = cover;


    const btnRestart = new MySprite();
    btnRestart.init(this.images.get('restart'));
    btnRestart.setScaleXY(this.mapScale);
    btnRestart.x = this.canvasWidth + btnRestart.getBoundingBox().width / 2;
    btnRestart.y = this.btnStart.sprite.y;

    this.endRenderArr.push(btnRestart);

    this.btnRestart.sprite = btnRestart;
    this.btnRestart.showX = this.btnStart.sprite.x;
    this.btnRestart.showY = this.btnStart.sprite.y;
    this.btnRestart.initX = btnRestart.x;
    this.btnRestart.initY = btnRestart.y;

    //大桃子背景光
    const light = new MySprite();
    light.init(this.images.get("light"));
    light.setScaleXY(0);
    light.x = 0;
    light.y = 0;
    light.alpha = 0;
    this.bigLight.sprite = light;
    this.bigLight.initX = light.x;
    this.bigLight.initY = light.y;

    this.endRenderArr.push(light);

    //大桃子图片
    const bigPeach = new MySprite();
    bigPeach.init(this.images.get("big-peach"));
    bigPeach.setScaleXY(0);
    bigPeach.alpha = 0;
    bigPeach.x = 0;
    bigPeach.y = 0;
    this.bigPeach.sprite = bigPeach;
    this.bigPeach.initX = bigPeach.x;
    this.bigPeach.initY = bigPeach.y;
    this.endRenderArr.push(bigPeach);
  }

  mapDown(event) {

    if (!this.canTouch) {
      return;
    }

    if (this.checkClickTarget(this.btnStart.sprite)) {

      this.playAudio('click');
      this.btnStart.keyDown = true;
      this.btnStart.sprite.setScaleXY(this.mapScale * 1.3);
      return;
    }

    if (this.checkClickTarget(this.btnRestart.sprite)) {
      this.playAudio('click');
      this.btnRestart.keyDown = true;
      this.btnRestart.sprite.setScaleXY(this.mapScale * 1.3);
      return;
    }

    if (this.canPlay) {

      if (this.checkClickTarget(this.leftMonkey.baseboard)) {

        this.clickLeftMonkey();

        return;
      }

      if (this.checkClickTarget(this.rightMonkey.baseboard)) {

        this.clickRightMonkey();

        return;
      }

      for (let i = 0; i < this.exercisesArr.length; ++i) {

        let exercises = this.exercisesArr[i];

        if (this.checkClickTarget(exercises.baseboard)) {

          this.clickCard(exercises);

          return;
        }

      }


    }
  }

  /**
   * 点击卡片
   * @param card 
   */
  clickCard(card) {

    //如果不是第一张卡片，刚判断前一张是否已经翻过来了
    if(card.index != 0){

      let tCard = this.exercisesArr[card.index - 1];

      //未翻过来，则返回
      if(tCard.curShow == '0'){
        return;
      }
    }

    

    //显示背面，则翻转
    if (card.curShow == '0') {

      if(!this.canOverCard){
        return;
      }

      //停止闪烁
      card.lightShow = false;
      card.light.alpha = 0;

      //停止闪烁
      this.stopLightMonkey();

      //禁止翻动卡片
      this.canOverCard = false;

      this.overCard(card.baseboard, () => {
        this.canClickMonkey = true;
      });

      //设置卡片已翻面
      card.curShow = '1';

      this.startLightMonkey();

      //将楼层指向下一层
      this.floorInfo.nextFloor = card.index + 1;

      //卡片未到顶部，则将下一个卡片点亮
      if (card.index < this.exercisesArr.length - 1) {
        //this.lightCard(this.exercisesArr[card.index + 1]);
      }
      else {
        this.peach.canRotate = true;

        this.rotatePeach();

        this.lightPeach();
      }

    }
    else {

      //停止所有的音效
      for(let i = 0; i < this.exercisesArr.length; ++ i){
            
        let card = this.exercisesArr[i];

        let audio = this.audioObj[card.audioUrl];
        
        audio.pause();

        audio.currentTime = 0;
      }
      this.playAudio(card.audioUrl);
    }
  }

  /**
   * 点击左边猴子
   */
  clickLeftMonkey() {

    this.clickMonkey(this.leftMonkey);

  }

  /**
   * 点击右边猴子
   */
  clickRightMonkey() {
    this.clickMonkey(this.rightMonkey);
  }

  /**
   * 点击猴子
   * @param monkey 
   */
  clickMonkey(monkey) {

    if (!this.canClickMonkey) {
      return;
    }

    //停止闪烁
    this.stopLightMonkey();

    //停止旋转
    this.peach.canRotate = false;

    this.peach.light.alpha = 0;

    this.canClickMonkey = false;

    //如果未达到顶部，则往上移动
    if (monkey.curFloor < this.exercisesArr.length - 1) {
      if (monkey.curFloor < this.floorInfo.nextFloor) {

        let floor = this.floorInfo.floors[monkey.curFloor + 1];

        //移动到下一层
        tweenChange(monkey.baseboard, { y: floor.startY - 40 * this.mapScale }, 1, () => {
          monkey.curFloor = monkey.curFloor + 1;
          console.log('monkey cur floor', monkey.curFloor);
          this.canClickMonkey = true;

          this.canOverCard = true;

          let card = this.exercisesArr[monkey.curFloor];

          if(card.curShow == '0' && !card.lighting){
            card.lightShow = true;
            this.lightCard(card);
          }

         
        });
      }
    }
    else {

      //还有卡片未被翻过来，则不跑向成功
      for(let i = 0; i < this.exercisesArr.length; ++ i){

        if(this.exercisesArr[i].curShow == '0'){
          return;
        }
      }

      let toX = this.peach.initX - monkey.baseboard.getBoundingBox().width / 2;

      let toY = this.peach.initY - monkey.baseboard.getBoundingBox().height / 2 + 30 * this.mapScale;

      //达到最顶层，当前游戏结束
      this.jump(monkey, toX, toY, 0.5, () => {

        //猴子向上离开界面
        this.monkeyLeave();

        //桃子带着离开界面
        let toY = - this.peach.light.getBoundingBox().height;
        tweenChange(this.peach.light, { y: toY }, 0.3, () => {

          //显示结束画面
          this.showEndPage(monkey.flag);
        });
      });
    }

  }

  mapMove(event) {

  }

  mapUp(event) {

    if (!this.canTouch) {
      return;
    }

    if (this.checkClickTarget(this.btnStart.sprite)) {

      //按下松开
      if (this.btnStart.keyDown = true) {

        this.btnStart.keyDown = false;

        let toX = this.btnStart.sprite.getBoundingBox().width + this.btnStart.sprite.x;

        //向左移出
        tweenChange(this.btnStart.sprite, { x: toX }, 0.3, () => {

          //恢复原来大小写
          this.btnStart.sprite.setScaleXY(this.mapScale);

          //开始游戏
          this.playGame();
        });


      }
    }

    if (this.checkClickTarget(this.btnRestart.sprite)) {

      //按下松开
      if (this.btnRestart.keyDown = true) {

        this.btnRestart.keyDown = false;

        let toX = this.btnRestart.initX;

        //向左移出
        tweenChange(this.btnRestart.sprite, { x: toX }, 0.3, () => {

          //恢复原来大小写
          this.btnRestart.sprite.setScaleXY(this.mapScale);

          //开始游戏
          this.restartGame();
        });


      }
    }
  }



  update() {

    // ----------------------------------------------------------
    this.animationId = window.requestAnimationFrame(this.update.bind(this));
    // 清除画布内容
    this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
    // tween 更新动画
    TWEEN.update();
    // ----------------------------------------------------------



    this.updateArr(this.renderArr);

    this.updateArr(this.endRenderArr);
  }

  /**
   * 翻卡片
   * @param item 
   * @param callback 
   */
  overCard(item, callback?: any) {

    this.playAudio('spring');

    let w = this.mapScale;

    tweenChange(item.children[2], { scaleX: 0 }, 0.3, () => {

      item.children[3].visible = !item.children[3].visible;

      tweenChange(item.children[2], { scaleX: w }, 0.3, () => {
        callback && callback();
      });

    });
  }

  /**
   * 跳跃
   * @param monkey
   * @param toX 
   * @param toY 
   * @param time
   * @param callback
   */
  jump(monkey, toX, toY, time: number, callback = null) {

    let sX = monkey.baseboard.x;

    let sY = monkey.baseboard.y;

    //计算中间坐标
    let mPos = this.getJumpMiddleMap(toX, toY, sX, sY);

    tweenChange(monkey.baseboard, { x: mPos.x, y: mPos.y }, time / 2, () => {
      tweenChange(monkey.baseboard, { x: toX, y: toY }, time, () => {

        if (callback) {
          callback();
        }

      }, null, () => {



      });
    });

  }

  /**
   * 获取指定位置的中间坐标
   * @param toX 
   * @param toY 
   * @param sX 
   * @param sY 
   */
  getJumpMiddleMap(toX, toY, sX, sY) {

    //斜率
    let k = (toY - sY) / (toX - sX);

    //取得跳出的坐标
    let mX = (sX + toX) / 2;


    let mY = k * (mX - toX) + toY;

    //指定高度
    mY = mY - 100 * this.mapScale;

    return { x: mX, y: mY };
  }

  /**
   * 点亮卡片
   * @param card 
   */
  lightCard(card) {

    if (!card.lightShow) {
      card.lighting = false;
      return;
    }

    card.lighting = true;

    let alpha = card.light.alpha;

    tweenChange(card.light, { alpha: 1 }, 0.4, () => {
      tweenChange(card.light, { alpha: 0 }, 0.4, () => {
        setTimeout(() => {
          this.lightCard(card);
        }, 700);
      });
    });
  }

  /**
   * 猴子开始闪烁
   */
  startLightMonkey() {

    //已经闪烁，不重复触发
    if(!this.leftMonkey.stopLight){
      return;
    }
    this.leftMonkey.stopLight = false;
    this.lightMonkey(this.leftMonkey);

    //已经闪烁，不重复触发
    if(!this.rightMonkey.stopLight){
      return;
    }
    this.rightMonkey.stopLight = false;
    this.lightMonkey(this.rightMonkey);
  }

  /**
   * 点亮猴子
   * @param monkey 
   */
  lightMonkey(monkey) {

    if (monkey.stopLight) {

      return;
    }

    let alpha = monkey.light.alpha;

    tweenChange(monkey.light, { alpha: 1 }, 0.5, () => {
      tweenChange(monkey.light, { alpha: 0 }, 0.5, () => {
        this.lightMonkey(monkey);
      });
    });
  }

  /**
   * 停止闪烁
   */
  stopLightMonkey() {

    this.leftMonkey.stopLight = true;

    this.rightMonkey.stopLight = true;
  }

  /**
   * 猴子离开界面
   */
  monkeyLeave() {


    const leave = (monkey) => {

      let toY = - this.leftMonkey.baseboard.getBoundingBox().height;

      tweenChange(monkey.baseboard, { y: toY }, 0.3);
    }

    leave(this.leftMonkey);

    leave(this.rightMonkey);
  }

  /**
   * 点亮桃子
   */
  lightPeach() {

    //点亮桃子
    tweenChange(this.peach.light, { alpha: 1 }, 0.1);

  }

  /**
   * 旋转桃子
   */
  rotatePeach() {

    const rotate4 = () => {
      rotateItem(this.peach.light, 0, 0.4, () => {

        if (this.peach.canRotate) {
          setTimeout(() => {
            rotate1();
          }, 0.4);
        }

      });
    };

    const rotate3 = () => {
      rotateItem(this.peach.light, -30, 0.4, () => {

        rotate4();

      });
    };

    const rotate2 = () => {
      rotateItem(this.peach.light, 0, 0.4, () => {

        rotate3();

      });
    };

    const rotate1 = () => {

      rotateItem(this.peach.light, 30, 0.4, () => {

        rotate2();

      });
    };

    rotate1();
  }

  /**
   * 开始玩游戏
   */
  playGame() {

    this.playAudio('peachShow');

    this.canOverCard = true;

    //桃子显示并放大
    tweenChange(this.peach.peach, { scaleX: this.mapScale * 1.2, scaleY: this.mapScale * 1.2, alpha: 1 }, 0.3, () => {

      //缩回正常尺寸
      tweenChange(this.peach.peach, { scaleX: this.mapScale, scaleY: this.mapScale }, 0.2, () => {
        this.peach.light.alpha = 1;

        setTimeout(() => {
          tweenChange(this.peach.light, {alpha : 0}, 0.5)
          this.peach.canRotate = true;
        }, 1000);
      });

      //显示卡片
      for (let i = 0; i < this.exercisesArr.length; ++i) {

        let exercises = this.exercisesArr[i];

        exercises.front.alpha = 1;

        exercises.back.alpha = 1;
        exercises.baseboard.scaleY = 0;

        if (i == this.exercisesArr.length - 1) {

          tweenChange(exercises.baseboard, {scaleY : this.mapScale}, 0.3, () => {

            this.playAudio('monkey');

            this.jump(this.leftMonkey, 300 * this.mapScale, this.leftMonkey.initY, 0.5, () => {

              //显示最底层的卡片
              this.lightCard(this.exercisesArr[0]);

              this.canPlay = true;

              this.canClickMonkey = true;
            });

            this.jump(this.rightMonkey, this.canvasWidth - 300 * this.mapScale - this.rightMonkey.baseboard.getBoundingBox().width, this.rightMonkey.initY, 0.5);
          });

        }
        else {
          tweenChange(exercises.baseboard, {scaleY : this.mapScale}, 0.3)
        }

      }
    })
  }

  /**
   * 重新开始游戏
   */
  restartGame() {

    //取练习题
    let exercisesArr = this.data.exercises;

    //打乱数组
    let newExercisesArr = randomSortByArr(exercisesArr);

    //卡片隐藏
    for (let i = 0; i < this.exercisesArr.length; ++i) {

      let card = this.exercisesArr[i];

      card.back.alpha = 0;

      tweenChange(card.front, { alpha: 0 }, 0.3, () => {

        this.overCard(card.baseboard);

        //重置内容
        card.resetContent();

        let exercises = newExercisesArr[i];

        //移除内容
        card.front.removeChild(card.contentSprite);

        card.contentSprite = null;

        card.audioUrl = exercises.audio_url;

        //设置内容
        this.setContent(exercises, card.front, card);
      });

    }

    const initMonekey = (monkey) => {

      //初始化猴子位置
      monkey.baseboard.x = monkey.initX;
      monkey.baseboard.y = monkey.initY;

      monkey.curFloor = 0;
    };

    //初始化猴子信息
    initMonekey(this.leftMonkey);
    initMonekey(this.rightMonkey);

    //初始楼层下一层索引
    this.floorInfo.nextFloor = 0;

    //初始化桃子
    this.peach.light.alpha = 0;
    this.peach.light.x = this.peach.initX;
    this.peach.light.y = this.peach.initY;
    this.peach.peach.setScaleXY(0);

    setTimeout(() => {

      this.playGame();
    }, 1000);


  }

  /**
   * 显示结束画面
   */
  showEndPage(winner) {

    const getShowPos = (winner) => {

      let x = 0;

      let y = 300;

      //r：右侧胜利，l：左侧胜利
      if (winner == 'r') {

        x = this.canvasWidth - 300 * this.mapScale;
      }
      else if (winner == 'l') {

        x = 300 * this.mapScale;
      }

      return { x: x, y: y };
    };

    this.playAudio('win');

    //显示灰色半透明背景
    tweenChange(this.cover, { alpha: 0.5 }, 0.5);

    //显示大桃子
    setTimeout(() => {

      let pos = getShowPos(winner);

      //设置显示坐标
      this.bigLight.sprite.x = pos.x;
      this.bigLight.sprite.y = pos.y;
      this.bigLight.sprite.alpha = 1;

      tweenChange(this.bigLight.sprite, { scaleX: this.mapScale, scaleY: this.mapScale }, 0.2, () => {

        this.showPetalStatus = true;

        this.showPetal(pos);

        //停止撒花
        setTimeout(() => {
          this.showPetalStatus = false;
        }, 500);

        this.rotateLight();

        //弹出重玩按钮
        setTimeout(() => {
          //显示重新开始按钮
          tweenChange(this.btnRestart.sprite, { x: this.btnRestart.showX, y: this.btnRestart.showY }, 0.3);
        }, 2700);

        //隐藏大桃子和灯光
        setTimeout(() => {

          //隐藏桃子
          tweenChange(this.bigPeach.sprite, { scaleX: 0, scaleY: 0 }, 0.3);

          //隐藏灯光
          tweenChange(this.bigLight.sprite, { scaleX: 0, scaleY: 0 }, 0.3);

          //隐藏背景
          tweenChange(this.cover, { alpha: 0 }, 0.3);

        }, 3000);
      });

      this.bigPeach.sprite.x = pos.x;
      this.bigPeach.sprite.y = pos.y;
      this.bigPeach.sprite.alpha = 1;
      tweenChange(this.bigPeach.sprite, { scaleX: this.mapScale, scaleY: this.mapScale }, 0.2);

    }, 300);
  }

  /**
   * 灯光旋转
   */
  rotateLight() {
    rotateItem(this.bigLight.sprite, 1.6 * 270, 3.3, () => {

    });
  }

  /**
   * 显示结束花瓣
   * @param pos 花瓣显示位置
   */
  showPetal(pos) {

    if (!this.showPetalStatus) {
      return;
    }

    const petal = this.getPetal(pos);
    this.endRenderArr.push(petal);

    let toY = pos.y + this.bigLight.sprite.getBoundingBox().height / 2;

    moveItem(petal, petal.x, toY + petal.height * petal.scaleY, petal['time'], () => {
      removeItemFromArr(this.endRenderArr, petal);
    });

    rotateItem(petal, petal['tr'], petal['time']);

    setTimeout(() => {
      this.showPetal(pos);
    }, 50);
  }

  /**
   * 得到花瓣
   * @param pos 
   */
  getPetal(pos) {

    const petal = new MySprite(this.ctx);

    const id = Math.ceil(Math.random() * 9);
    petal.init(this.images.get('petal_' + id));

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

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

    let startX = pos.x - this.bigLight.sprite.getBoundingBox().width / 2;

    let startY = pos.y - this.bigLight.sprite.getBoundingBox().height / 2;

    const randomX = startX + Math.random() * this.bigLight.sprite.getBoundingBox().width;
    petal.x = randomX;

    petal.y = startY - petal.height / 2 * petal.scaleY;

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

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

    return petal;
  }
}
