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

import {
  formatTime,
  getMinScale, hideItem,
  Label, LineRect, MyAnimation,
  MySprite, removeItemFromArr, RichText, ShapeRect, showItem, showPopParticle, tweenChange,

} from './Unit';
import {res, resAudio} from './resources';

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

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


@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;
  mapScale = 1;

  canvasLeft;
  canvasTop;

  saveKey = 'pu14';




  canTouch = true;

  private bg: any;
  private hotZoneArr: any[];
  private hotZoneRate: number;
  private oldHotMapScale: number;
  private textLabelArr: any;
  private allBtns: any;
  private curAudio: any;
  private progressBarBg: MySprite;
  private currentTime: number;
  private isClickedProgress: boolean;
  private clickedSuccessArr: any;
  private light: LineRect;
  private particleLayer: MySprite;
  private shadowArr: any;

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

  initHotZone() {

    let curBgRect;
    if (this.bg) {
      curBgRect = this.bg.getBoundingBox();
    }

    let oldBgRect = this.data.bgItem.rect;
    if (!oldBgRect) {
      oldBgRect = curBgRect;
    }

    const rate = curBgRect.width / oldBgRect.width;
    this.hotZoneRate = rate;

    this.hotZoneArr = [];
    const arr = this.data.hotZoneItemArr;
    if (!arr && arr.length > 0) {
      return;
    }

    this.oldHotMapScale = arr[0].mapScale;


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

      const data = JSON.parse(JSON.stringify(arr[i]));

      data.rect.x *= rate;
      data.rect.y *= rate;
      data.rect.width *= rate;
      data.rect.height *= rate;

      data.rect.x += curBgRect.x;
      data.rect.y += curBgRect.y;

      const hotZone = this.getHotZoneItem(data, rate);
      hotZone.visible = false;
      this.hotZoneArr.push(hotZone);

    }

  }

  getHotZoneItem(data, rate) {

    const saveRect = data.rect;
    let item;
    if (data.itemType === 'rect') {
      item = new ShapeRect(this.ctx);
      item.fillColor = '#ff0000';
      item.setSize(saveRect.width, saveRect.height);
      item.x = saveRect.x;
      item.y = saveRect.y;

    } else if (data.itemType == 'pic') {
      item = this.createBtn(data.pic_url, null, 1);
      item.setScaleXY(data.imgScale * rate);
      item.x = saveRect.x + saveRect.width / 2;
      item.y = saveRect.y + saveRect.height / 2;
      item.onClick = () => {
        console.log('item.data:', item.data);
        this.playAudio(item.data.audio_url);
      }

    } else if (data.itemType == 'text') {
      item = new Label();
      item.text = data.text;
      item.textAlign = 'center';
      item.fontSize = data.fontSize;
      item.fontName = data.fontName;
      item.fontColor = data.fontColor;
      item.x = saveRect.x + saveRect.width / 2;
      item.y = saveRect.y + saveRect.height / 2;
      item.childDepandAlpha = true;
      item.setShadow(0, 1, 1, '#ffd98d')


      item.setScaleXY(data.fontScale * rate);
      item.refreshSize();

      const textBg = this.createBtn('text_bg', null, 1);
      item.setMaxSize(textBg.width * 0.98);
      textBg.onClick = () => {
        console.log('item.data:', item.data);
        this.playAudio(item.data.audio_url);
      };

      textBg.y = 5;
      textBg.setScaleXY(1 / item.scaleX * this.oldHotMapScale * this.hotZoneRate);
      item.addChild(textBg, -1);
      item.bg = textBg;


      this.textLabelArr.push(item);
    }

    item['data'] = data;

    this.renderArr.push(item);

    return item;
  }

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

    if (!this.data.bgItem && !this.data.hotZoneItemArr) {

      this.data.questionType = '2';
      this.data.text = 'This is a test question.';

      this.data.bgItem = {
        rect: {height: 735, width: 1306, x: 320, y: 0},
        url: 'assets/play/default/pic.jpg'
      };

      this.data.hotZoneItemArr = [
        {
          fontColor: "#8f3758",
          fontName: "BRLNSDB_1",
          fontScale: 1.521875,
          fontSize: 50,
          imgScale: 1,
          index: 0,
          itemType: "rect",
          mapScale: 1.521,
          rect: {
            height: 148.55,
            width: 148.55,
            x: 385.42,
            y: 275
          }
        },
        {
          fontColor: "#8f3758",
          fontName: "BRLNSDB_1",
          fontScale: 1.521875,
          fontSize: 50,
          imgScale: 1,
          index: 1,
          itemType: "rect",
          mapScale: 1.521875,
          rect: {
            height: 200,
            width: 370,
            x: 902.33,
            y: 268.5
          }
        }
      ];
    }
  }


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

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

    this.addUrlToImages(this.data.bgItem.url);

    console.log('this.data:', this.data);
    this.data.hotZoneItemArr.forEach((item) => {
      if (item.itemType === 'pic') {
        this.addUrlToImages(item.pic_url);
      }
    });
  }

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

    // 音频资源
    this.addUrlToAudioObj(this.data.audio_url);
    this.data.hotZoneItemArr.forEach((item) => {
      if (item.audio_url) {
        this.addUrlToAudioObj(item.audio_url);
      }
    });

    // 音效
    this.addUrlToAudioObj('click', this.rawAudios.get('click'), 1);
    this.addUrlToAudioObj('right', this.rawAudios.get('right'), 0.5);
    this.addUrlToAudioObj('wrong', this.rawAudios.get('wrong'), 0.5);


  }

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

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

    // this.mapScale = sx;
    // this.mapScale = sy;


    this.currentTime = 0;
    this.renderArr = [];
    this.allBtns = [];
    this.currentTime = 0;
    this.clickedSuccessArr = [];
    this.shadowArr = [];
    // this.isMagnifierTouched = false;
    // this.photoAnima = null;
    // this.textLabelArr = [];
    // this.allBtns = [];
  }

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

    this.initBg();
    this.initTopPart();
    this.initHotZone();

  }


  createLight() {

    const light = new LineRect();
    light.init();
    light.visible = false;
    light.setShadow(0, 0, 15 * this.mapScale, 'rgba(255, 255, 0, 1)')
    light.lineWidth = 7 * this.mapScale;
    // this.light = light;
    this.renderArr.push(light);
    return light;
  }

  initTopPart() {
    switch (this.data.questionType) {
      case '1':
        this.initBigAudioPlayer();
        break;

      case '2':
        this.initBigTextQuestion();
        break;

      case '3':
        this.initPlayerAndText();
        break;
    }
  }

  initPlayerAndText() {
    const audioPlayer = this.initSmallAudioPlayer();
    const textPanel = this.initSmallTextQuestion();

    const offX = 10 * this.mapScale;
    const totalW = audioPlayer.width * audioPlayer.scaleX + textPanel.width * textPanel.scaleX + offX;
    audioPlayer.x = this.canvasWidth / 2 - totalW / 2 + audioPlayer.width / 2 * audioPlayer.scaleX;
    textPanel.x = audioPlayer.x + audioPlayer.width / 2 * audioPlayer.scaleX + offX + textPanel.width / 2 * textPanel.scaleX;
  }


  initSmallAudioPlayer() {
    const res = {
      playerBg: 'player_bg_small',
      playerTop: 'player_top_small',
      btnPlay: 'btn_play_small',
      btnPause: 'btn_pause_small',
      barTop: 'progressbar_played_small',
      barBottom: 'progressbar_bg_small',
      barBtn: 'btn_current_position_small',
    };
    const audioPlayer = this.initAudioPlayer(res);
    audioPlayer['progress'].x += 15;
    audioPlayer['progress'].setScaleXY(0.9);
    audioPlayer['progress']['bar'].y += 2;
    audioPlayer['playBtn'].x -= 12
    audioPlayer['playBtn'].setScaleXY(0.9);

    return audioPlayer;
  }



  initBigAudioPlayer() {

    const res = {
      playerBg: 'player_bg_big',
      playerTop: 'player_top_big',
      btnPlay: 'btn_play_big',
      btnPause: 'btn_pause_big',
      barTop: 'progressbar_played_big',
      barBottom: 'progressbar_bg_big',
      barBtn: 'btn_current_position_big',
    };
    this.initAudioPlayer(res);
  }

  initAudioPlayer(res) {
    this.curAudio = this.audioObj[this.data.audio_url];
    this.curAudio.onended = () => {
      this.setAudioState(this.curAudio, false);
      this.curAudio.currentTime = 0;
    }

    const audioPlayer = this.createAudioPlayer(res);
    audioPlayer.setScaleXY(this.mapScale);
    audioPlayer.x = this.canvasWidth / 2;
    audioPlayer.y = audioPlayer.height / 2 * audioPlayer.scaleY;
    this.renderArr.push(audioPlayer);

    this.setAudioProgress(this.progressBarBg, 0);

    return audioPlayer;
  }

  private createAudioPlayer(res) {
    const audioPlayer = this.createSprite(res.playerBg)

    const playBtn = this.createPlayPauseButton(res.btnPlay, res.btnPause);
    audioPlayer.addChild(playBtn);
    audioPlayer['playBtn'] = playBtn;

    const progressBarContainer = this.createProgressBar(res.barTop, res.barBottom, res.barBtn);
    progressBarContainer.x = -this.progressBarBg.width / 2 - 32
    progressBarContainer.y = -1;

    playBtn.x = progressBarContainer.x + this.progressBarBg.width + 50;
    playBtn.y = progressBarContainer.y - 4;
    audioPlayer.addChild(progressBarContainer);

    const audioTopItem = this.createSprite(res.playerTop);
    audioPlayer.addChild(audioTopItem);

    audioPlayer['progress'] = progressBarContainer;

    return audioPlayer;
  }

  private createPlayPauseButton(playKey, pauseKey) {
    const button = this.createSprite(playKey);

    const btnPause = this.createSprite(pauseKey);
    this.hide(btnPause);
    button.addChild(btnPause);

    this.curAudio.playBtn = button;
    this.curAudio.stopBtn = btnPause;

    return button;
  }

  private createProgressBar(barTopKey, barBottomKey, barBtnKey) {
    const container = new MySprite();
    const progressBarBg = this.createSprite(barBottomKey);
    progressBarBg.anchorX = 0;
    this.progressBarBg = progressBarBg;

    const progressBarPlayed = this.createSprite(barTopKey);
    progressBarPlayed.anchorX = 0;
    progressBarPlayed.x = 5;
    progressBarPlayed.y = -6.5;

    // progressBarPlayed.scaleX = 0;
    progressBarBg['bar'] = progressBarPlayed;
    container['bar'] = progressBarPlayed;

    const btn = this.createSprite(barBtnKey)
    btn.y = -3;
    progressBarBg['btn'] = btn;

    const currentTime = this.createTime();
    currentTime.text = formatTime('mm:ss', new Date(this.currentTime * 1000));
    currentTime.refreshSize();
    currentTime.x = 0;
    currentTime.y = 30;
    progressBarBg['timeLabel'] = currentTime;

    const totalTime = this.createTime();
    totalTime.text = formatTime('mm:ss', new Date(this.curAudio.duration * 1000));
    totalTime.refreshSize();
    totalTime.x = progressBarBg.width - totalTime.width;
    totalTime.y = currentTime.y;

    container.addChild(progressBarBg);
    container.addChild(progressBarPlayed);
    container.addChild(btn);
    container.addChild(currentTime)
    container.addChild(totalTime)
    return container;
  }

  private createTime() {
    const label = new Label();
    label.fontSize = 22;
    label.fontColor = '#fff3cc';
    label.fontName = 'BRLNSDB_1';
    label.setShadow(1, 1, 2, '#000000')
    return label;
  }

  private setAudioProgress(target: any, progress: number) {
    target.btn.x = target.width * progress;

    const showRect = {x: 0, y: 0, width: target.bar.width * progress, height: target.bar.height};

    target.bar.setShowRect(showRect);

    this.currentTime = Math.floor(progress * this.curAudio.duration);
    target.timeLabel.text = formatTime('mm:ss', new Date(this.currentTime * 1000));
  }

  private touchDownProgressBar(target) {
    this.setAudioState(this.curAudio, false);

    const rect = target.getBoundingBox();
    const sx = rect.width / target.width;
    const tmpW = (this.mx - rect.x) / sx;
    if (tmpW >= 0 && tmpW <= target.width) {
      const progress = tmpW / target.width;
      this.curAudio.currentTime = progress * this.curAudio.duration;
      this.setAudioProgress(target, progress);
    }
  }

  private setAudioState(audio: any, isPlay: boolean) {
    if (isPlay) {
      this.hide(audio.playBtn);
      this.show(audio.stopBtn);
      audio.play();
    } else {
      this.hide(audio.stopBtn);
      this.show(audio.playBtn);
      audio.pause();
    }
  }

  private hide(element: MySprite) {
    element.alpha = 0;
  }
  private show(element: MySprite) {
    element.alpha = 1;
  }

  private touchDownAudioBtn(audio) {
    if (audio.paused) {
      audio.play();
      this.setAudioState(audio, true);
    } else {
      audio.pause();
      this.setAudioState(audio, false);
    }
  }



  initBigTextQuestion() {
    const textBg = this.createSprite('text_bg_big');
    textBg.setScaleXY(this.mapScale);
    textBg.x = this.canvasWidth / 2;
    textBg.y = textBg.height / 2 * textBg.scaleY;

    const label = new RichText();
    label.text = this.data.text;
    textBg.addChild(label);
    label.width = textBg.width ;
    label.offW = 30;
    label.fontName = 'BRLNSDB_1';
    label.textAlign = 'center';
    label.fontSize = 37;
    label.disH = 6;
    label.y = - 22;

    this.renderArr.push(textBg);
  }

  initSmallTextQuestion() {
    const textBg = this.createSprite('text_bg_small');
    textBg.setScaleXY(this.mapScale);
    textBg.x = this.canvasWidth / 2;
    textBg.y = textBg.height / 2 * textBg.scaleY;

    const label = new RichText();
    label.text = this.data.text;
    textBg.addChild(label);
    label.width = textBg.width ;
    label.offW = 30;
    label.fontName = 'BRLNSDB_1';
    label.textAlign = 'center';
    label.fontSize = 33;
    label.disH = 6;
    label.y = - 22;

    this.renderArr.push(textBg);
    return textBg;
  }




  clickedHotZone(item) {

    if (this.clickedSuccessArr.indexOf(item) !== -1) {
      this.canTouch = true;
      return;
    }

    this.clickedSuccessArr.push(item);

    const data = item.data;
    if (!data.checked) {
      console.log('right');
      this.showFrame(item);
    } else {
      console.log('wrong');
      this.clickWrong();
    }
  }


  clickWrong() {

    // tweenChange()
    const crack = this.createSprite('crack');
    crack.alpha = 0;
    this.renderArr.push(crack);
    crack.x = this.mx;
    crack.y = this.my;
    crack.setScaleXY(this.mapScale);
    tweenChange(crack, { alpha: 1 }, 0.25, () => {
      setTimeout(() => {
        removeItemFromArr(this.renderArr, crack);
      }, 500)
    }, TWEEN.Easing.Quadratic.Out)
    this.playAudio('wrong', true);
    // shake(this.bgRect, 0.5, () => {
    //   this.canTouch = true;
    // });
  }

  showFrame(hotZone) {

    this.playAudio('right', true);

    const light = this.createLight();
    light.setScaleXY(0);
    light.alpha = 0;
    light.visible = true;

    // const hotZone = this.hotZoneArr[index];
    const px = hotZone.x + hotZone.width / 2;
    const py = hotZone.y + hotZone.height / 2;

    light.x = px;
    light.y = py;
    light.setSize(hotZone.width, hotZone.height);

    tweenChange(light, {
      scaleX: 1, // hotZone.width / (light.width - edge * 2),
      scaleY: 1, // hotZone.height / (light.height - edge * 2),
      alpha: 1
    }, 0.5, () => {

      setTimeout(() => {
        hideItem(light, 0.3, () => {
          removeItemFromArr(this.renderArr, light);
        }, TWEEN.Easing.Quadratic.In);
      }, 200);

    }, TWEEN.Easing.Quadratic.Out);

    setTimeout(() => {

      this.playAudio('star', true);
      showPopParticle(this.images.get('star'), {x: px, y: py},
        this.particleLayer, 20, 50 * this.mapScale, 100 * this.mapScale, 1);
    }, 400);

    setTimeout( () => {
      this.showShadow(hotZone);
    }, 1000);
  }

  showShadow(hotZone) {

    const shadow = new MySprite();
    shadow.init(this.images.get('shadow'));
    shadow.alpha = 0;
    shadow.x = hotZone.x + hotZone.width / 2;
    shadow.y = hotZone.y + hotZone.height / 2;
    shadow.childDepandAlpha = true;
    this.renderArr.push(shadow);

    const lineRect = new LineRect();
    lineRect.init();
    lineRect.lineWidth = 2 * this.mapScale;
    // lineRect.lineColor = '#c2ff39';
    lineRect.lineColor = '#ffffff';
    lineRect.setSize(hotZone.width - lineRect.lineWidth, hotZone.height - lineRect.lineWidth);
    shadow.addChild(lineRect);

    const sx = hotZone.width / (shadow.width - 360);
    const sy = hotZone.height / (shadow.height - 360);
    shadow.scaleX = sx;
    shadow.scaleY = sy;

    lineRect.scaleX = 1 / sx;
    lineRect.scaleY = 1 / sy;

    showItem(shadow, 0.5, () => {
      this.checkGameEnd();
    });
    this.shadowArr.push(shadow);
  }

  checkGameEnd() {

    if (this.clickedSuccessArr.length < this.hotZoneArr.length) {
      this.canTouch = true;
      return;
    }

    this.gameEnd();
  }

  gameEnd() {
    console.log('game end');
  }





  private updateTime() {
    if (!this.isClickedProgress && this.curAudio) {
      const progress = this.curAudio.currentTime / this.curAudio.duration;
      this.setAudioProgress(this.progressBarBg, progress);
    }
  }

  mapDown(event) {

    if (!this.canTouch) {
      return;
    }

    this.allBtns.forEach((btn) => {
      if (this.checkClickTarget(btn)) {
        btn._onTouchStart();
        return;
      }
    });

    for (const item of this.hotZoneArr) {
      if (this.checkClickTarget(item)) {
        this.clickedHotZone(item);
        return;
      }
    }

    // ------- 播放器 --------
    if (this.curAudio) {
      if (this.checkClickTarget(this.progressBarBg)) {
        this.isClickedProgress = true;
        this.touchDownProgressBar(this.progressBarBg);
        return;
      }
      if (this.checkClickTarget(this.curAudio.playBtn)) {
        this.touchDownAudioBtn(this.curAudio);
        return;
      }
    }
    // ------------------------

    if (this.checkClickTarget(this.bg)) {
      this.clickWrong();
    }
  }

  mapMove(event) {
    if (!this.isClickedProgress) {
      return;
    }

    this.allBtns.forEach((btn) => {
      if (!this.checkClickTarget(btn)) {
        btn._isDown = false;
        return;
      }
    });

    this.touchDownProgressBar(this.progressBarBg);
  }

  mapUp(event) {

    this.allBtns.forEach((btn) => {
      if (btn._isDown) {
        btn._onTouchEnd();
      }
    });

    this.isClickedProgress = false;
  }

  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.textLabelArr);
    this.updateItem(this.particleLayer);

    this.updateTime();


  }

  private createSprite(key: string) {
    const sprite = new MySprite();
    sprite.init(this.images.get(key));
    return sprite;
  }

  private initBg() {

    const bg = this.createSprite('bg');
    const sx = this.canvasWidth / bg.width;
    const sy = this.canvasHeight / bg.height;
    const s = Math.max(sx, sy);
    bg.setScaleXY(s);
    bg.x = this.canvasWidth / 2;
    bg.y = this.canvasHeight / 2;
    this.renderArr.push(bg);

    const picBg = this.createSprite('pic_bg');
    picBg.setScaleXY(this.mapScale);
    picBg.x = this.canvasWidth / 2;
    picBg.y = this.canvasHeight - picBg.height / 2 * picBg.scaleY;
    this.renderArr.push(picBg);

    const url = this.data.bgItem.url;
    const pic = this.createSprite(url);

    const rect = new ShapeRect();
    // rect.fillColor = '#ffffff';
    rect.fillColor = '#d3323e';
    rect.width = 913;
    rect.height = 495;
    rect.x = -rect.width / 2 - 8;
    rect.y = -rect.height / 2 + 8;
    // rect.alpha = 0.3;
    picBg.addChild(rect, -1);

    pic.x = rect.width / 2;
    pic.y = rect.height / 2;

    const psx = (rect.width) / pic.width;
    const psy = (rect.height) / pic.height;
    const ps = Math.min(psx, psy);
    pic.setScaleXY(ps);
    this.bg = pic;
    rect.addChild(pic);

    const particleLayer = new MySprite();
    particleLayer.width = this.canvasWidth;
    particleLayer.height = this.canvasHeight;
    this.particleLayer = particleLayer;
  }


  private createBtn(url_up: string, url_down: string = null, downScale = 0.9) {
    const btnUp: any = this.createSprite(url_up);
    let btnDown;
    if (url_down) {
      btnDown = this.createSprite(url_down);
      btnUp.addChild(btnDown);
    }
    btnUp.btnDown = btnDown;

    btnUp._onTouchStart = () => {
      if (btnDown) {
        btnDown.alpha = 1;
        btnUp.alpha = 0;
      }
      if (!btnUp.baseScale) {
        btnUp.baseScale = btnUp.scaleX;
      }

      btnUp.setScaleXY(btnUp.baseScale * downScale);

      if (btnUp.onTouchStart) {
        btnUp.onTouchStart();
      }
      btnUp._isDown = true;
    };

    btnUp._onTouchMove = () => {
    };

    btnUp._onTouchEnd = () => {
      if (btnDown) {
        btnDown.alpha = 0;
        btnUp.alpha = 1;
      }
      btnUp.setScaleXY(btnUp.baseScale);
      if (btnUp.onClick) {
        btnUp.onClick();
      }
      btnUp._isDown = false;
    };

    this.allBtns.push(btnUp);
    return btnUp;
  }
}
