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

import {
  MySprite,
  Label,
  moveItem,
  rotateItem,
  removeItemFromArr,
  ShapeRect, tweenChange, Dot, Line, scaleItem, hideItem,

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

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

import * as _ from 'lodash';
import TWEEN from '@tweenjs/tween.js';

import letterData from './letter-data';




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

  @Input()
  set data(data) {
    this._data = data;
  }
  get data() {
    return this._data;
  }

  @Input()
  sid;

  @ViewChild('canvas') canvas: ElementRef;
  @ViewChild('wrap') wrap: ElementRef;
  canvasWidth = 1280;
  canvasHeight = 720;

  canvasBaseW = 1280;
  canvasBaseH = 720;

  ctx;
  fps = 0;
  frametime = 0;  // 上一帧动画的时间，   两帧时间差


  mx;
  my; // 点击坐标



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

  images = new Map();

  animationId: any;
  winResizeEventStream = new Subject();


  audioObj = {};
  renderArr;
  mapScale = 1;

  canvasLeft;
  canvasTop;


  canTouch = true;


  KEY = 'dfzx_16';

  // -----
  picArr;
  pageLabel;
  leftBtn;
  rightBtn;
  bgLayer;
  curPageIndex;
  letter;
  bread;
  panel;
  breadLayer;
  downFlag;
  moveFlag;
  dotArr;
  curPosArr;
  curPosIndex;
  posDataIndex;
  posDataArr;
  curLine;
  lineArr;
  breadBtn;
  panelBtn;
  circleArr;
  playSoundFlag;
  timeIdArr = [];

  touchAreaMinLen = 15;
  drawLineWidth = 31;


  drawLineColor;


  hotZoneArr;

  picIndex = 0;


  bgArr;
  endPageArr;
  gameEndFlag;
  showPetalFlag;
  bg;




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

  }


  ngOnInit() {


    const getData = (<any> window).courseware.getData;
    getData((data) => {

      if (data && typeof data == 'object') {
        this.data = data;
      } else {
        this.data = {};
      }

      console.log('data:' , data);
      if (!this.data.contentObj) {
        this.data.contentObj = {};
      }

      this.initDefaultData();



      this.initAudio();
      this.initImg();
      this.initListener();

    }, this.KEY);


    //
    // // this.initAudio();
    // this.initImg();
    // this.initListener();
  }





  initDefaultData() {


    const bgItem = this.data.contentObj.bgItem;
    if (!bgItem) {
      const bgItem = {
        'rect' : {
          height: 465,
          width: 763.5889570552147,
          x: 250.70552147239266,
          y: 0
        },

        'url': 'assets/play/default/pic.jpg'
      };
      this.data.contentObj.bgItem = bgItem;

      const hotZoneItemArr = [
        {
          audio_url: "assets/play/default/audio.mp3",
          index: 0,
          rect: {
            height: 201,
            width: 165,
            x: 51.29,
            y: 28
          }
        },

        {
          audio_url: "assets/play/default/audio.mp3",
          index: 1,
          rect: {
            height: 119,
            width: 95,
            x: 307.29,
            y: 169
          }
        },

        {
          audio_url: "assets/play/default/audio.mp3",
          index: 2,
          rect: {
            height: 131,
            width: 97,
            x: 483.29,
            y: 168
          }
        },

      ];


      this.data.contentObj.hotZoneItemArr = hotZoneItemArr;
      this.data.contentObj.letter = 'b';

    }


    // let picArr = this.data.contentObj.hotZoneI;
    // // console.log('picArr: ', picArr);
    // if (!picArr || picArr.length == 0) {
    //
    //
    //   const picArr = [];
    //   for (let i = 0; i < 2; i++) {
    //     picArr.push({
    //       'pic_url': 'assets/play/default/pic.jpg',
    //       'audio_url': 'assets/play/default/audio.mp3'
    //     });
    //   }
    //
    //   this.data.contentObj.picArr = picArr;
    //
    // }


  }

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

  initData() {

    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;


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

    // this.mapScale = this.canvasWidth / this.canvasBaseW;
    // this.mapScale = this.canvasHeight / this.canvasBaseH;
    this.renderArr = [];

    console.log(' in initData', this.data);




    for (let i = 0; i < this.timeIdArr.length; i++) {
      clearTimeout( this.timeIdArr[i] );
    }


    this.canTouch = true;
    this.playSoundFlag = false;

    this.circleArr = [];
    this.lineArr = [];
    this.dotArr = [];

    this.curPageIndex = 0;

    // this.downFlag = false;

    this.endPageArr = [];

    // this.clockUpdateFlag = false;

    if (!this.data.contentObj.picArr) {
      this.data.contentObj.picArr = [];
    }
    this.picArr = this.data.contentObj.picArr;

    this.picIndex = 0;

    this.letter = this.data.contentObj.letter;


  }





  initAudio() {

    const contentObj = this.data.contentObj;
    if (!contentObj) { return; }



    // const addAudio = (key) => {
    //   const audioUrl = contentObj[key];
    //   if (audioUrl) {
    //     const audio = new Audio();
    //     audio.src = audioUrl;
    //     audio.load();
    //     this.audioObj[key] = audio;
    //   }
    // }
    //
    // for (let i = 0; i < 4; i ++) {
    //   const key = i + '_audio_url';
    //   addAudio(key);
    // }
    //
    // addAudio('audio_url');
    //


    const addUrlToAudioObj = (audioUrl) => {

      if (audioUrl) {

        // console.log('audioUrl:', audioUrl);
        const audio = new Audio();
        audio.src = audioUrl;
        audio.load();
        this.audioObj[audioUrl] = audio;
      }
    };


    let arr = contentObj.picArr;

    if (arr) {
      // console.log('arr: ', arr);
      for (let i = 0; i < arr.length; i++) {
        addUrlToAudioObj(arr[i].audio_url);
      }
    }

    arr = contentObj.hotZoneItemArr;
    if (arr) {
      for (let i = 0; i < arr.length; i++) {
        addUrlToAudioObj(arr[i].audio_url);
      }
    }







    const audioObj = this.audioObj;
    const addOneAudio = (key, url, vlomue = 1, loop = false, callback = null) => {

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

      audioObj[key] = audio;

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


    addOneAudio('click', this.rawAudios.get('click'), 0.7);
    // addOneAudio('angry', this.rawAudios.get('angry'), 1);
    // addOneAudio('cow_start', this.rawAudios.get('cow_start'), 1);
    // addOneAudio('eat', this.rawAudios.get('eat'), 1);
    // addOneAudio('grass', this.rawAudios.get('grass'), 1);
    // addOneAudio('happy', this.rawAudios.get('happy'), 1);
    // addOneAudio('right', this.rawAudios.get('right'), 1);
    // addOneAudio('wrong', this.rawAudios.get('wrong'), 1);



    //
    // const titleUrl = this.data.contentObj.title_audio_url;
    // if (titleUrl) {
    //
    //   this.titleAudio.src = titleUrl;
    //   this.titleAudio.load();
    // }



    // this.bgAudio.src = 'assets/bat-mail/music/bg.mp3';
    // this.bgAudio.load();
    // this.bgAudio.loop = true;
    // this.bgAudio.volume = 0.5;
    //
    // this.wrongAudio.src = 'assets/common/music/wrong.mp3';
    // this.wrongAudio.load();
    //
    // this.rightAudio.src = 'assets/common/music/right.mp3';
    // this.rightAudio.load();
    //
    // this.successAudio.src = 'assets/magic-hat/music/finish.mp3';
    // this.successAudio.load();
    //
    // this.successAudio.onended = () => {
    //   // this.showSuccessAudio();
    // };


  }

  initImg() {

    const contentObj = this.data.contentObj;
    if (contentObj) {


      const addPicUrl = (url) => {
        if (url) {
            this.rawImages.set(url, url);
          }
      };


      let arr = this.data.contentObj.picArr;
      if (arr) {

        for (let i = 0; i < arr.length; i++) {
          addPicUrl( arr[i].pic_url);
        }
      }


      addPicUrl(contentObj.bgItem.url);


    }



    // this.initFontImg();



    // 预加载资源

    this.loadResources().then(() => {
      // this.setfontData();

      window['air'].hideAirClassLoading(this.KEY, this.data);

      this.init();
      this.update();
    });

  }

  initFontImg() {



    // const fontbaseUrlW = 'assets/mechanical/letter/';
    // const fontDataW = {};
    //
    // let num = 97;
    // for (let i = 0; i < 26; i++) {
    //
    //   const key = String.fromCharCode(num + i);  // 'a'
    //   const url = fontbaseUrlW + key + '.png';
    //
    //   this.rawImages.set(url, url);
    //   fontDataW[key] = url;
    // }
    //
    //
    // this.fontDataW = fontDataW;
  }

  setfontData() {

    // for (let key in this.fontDataW) {
    //   this.fontDataW[key] = this.images.get(this.fontDataW[key]);
    // }
  }








  init() {

    this.initData();
    this.initCtx();

    this.initView();




  }

  initCtx() {

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

    window['curCtx'] = this.ctx;


  }


  initView() {

    this.initBg();

    this.initHotZone();
    // this.setHotZoneCircle();
    this.initCircleParticle();


    this.initBreadLayer();
    this.initLetterDot();
    this.createLine();


    this.breadLayer.visible = false;
    this.panel.visible = true;



    this.initSmallLetter();
    this.initSmallPanel();

  }


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

      const id = setTimeout(() => {
        this.addOneCircleParticle(this.hotZoneArr[i]);
        removeItemFromArr(this.timeIdArr, id);
      }, Math.random() * 5 * 1000);
      this.timeIdArr.push(id);
    }
  }

  addOneCircleParticle(item) {

    const circle = this.getCircle();
    circle.setScaleXY(0);
    circle.x = item.x + item.width / 2;
    circle.y = item.y + item.height / 2;

    const time = 1.5;

    scaleItem(circle, this.mapScale * 1.5, time, () => {

    });

    hideItem(circle, time, () => {

      removeItemFromArr(this.circleArr, circle);

    });



    if (!item.particleTimes) {
      item.particleTimes = 0;
    }
    item.particleTimes ++;

    let delay;
    if (item.particleTimes >= 3) {
      delay = 5;
      item.particleTimes = 0;
    } else {
      delay = 0.5;
    }

    if (!this.gameEndFlag) {
      const id = setTimeout(() => {
        this.addOneCircleParticle(item);
        removeItemFromArr(this.timeIdArr, id);
      }, delay * 1000);
      this.timeIdArr.push(id);
    }
  }

  getCircle() {

    const circle = new MySprite();
    circle.init(this.images.get('circle'));
    this.circleArr.push(circle);
    return circle;
  }




  initSmallLetter() {


    const bread = new MySprite();
    bread.init(this.images.get('bread-' + this.letter));
    bread.scaleX = bread.scaleY = this.mapScale;
    bread.x = this.canvasWidth / 2;
    bread.y = this.canvasHeight / 2;

    const shadow = new MySprite();
    shadow.init(this.images.get('shadow'));
    shadow.y = bread.height / 2 - 15 ;
    bread.addChild(shadow, -2);

    const letterBg = new MySprite(this.ctx);
    letterBg.init(this.images.get('letter-bg'));
    letterBg.scaleX = letterBg.scaleY = bread.width / letterBg.width * 0.9;
    bread.addChild(letterBg, -1);

    this.breadBtn = bread;

    const tmpX = this.panel.x + this.panel.width / 2 * this.panel.scaleX;
    const tmpW = (this.canvasWidth - tmpX) ;
    this.breadBtn.x = tmpX + tmpW / 2;
    this.breadBtn.y = this.canvasHeight / 2 + 180 * this.mapScale;
    this.breadBtn.setScaleXY( tmpW / bread.width * 0.7 );

  }

  initSmallPanel() {


    const itemW = this.breadBtn.width * this.breadBtn.scaleX;

    const panel = new MySprite();
    panel.init(this.images.get('panel'));
    panel.x = this.breadBtn.x;
    panel.y = this.breadBtn.y;
    panel.setScaleXY(itemW / panel.width);


    const w = 800;
    const h = 480;
    const pic = new MySprite();
    pic.init(this.images.get(this.data.contentObj.bgItem.url));
    const sx2 = w / pic.width;
    const sy2 = h / pic.height;
    const s2 = Math.min(sx2, sy2);
    pic.setScaleXY(s2);

    pic.y = -16;
    panel.addChild(pic);

    this.panelBtn = panel;

  }




  initLetterDot() {

    const letter = this.data.contentObj.letter;

    const cloneDataStr = JSON.stringify(letterData);
    const cloneData = JSON.parse(cloneDataStr);

    const posDataArrLeft = cloneData[letter].posDataArr.concat();

    if (cloneData[letter].lineW) {
      this.drawLineWidth = cloneData[letter].lineW;
    }
    this.drawLineColor = cloneData[letter].color;

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

      for (let j = 0; j < posDataArrLeft[i].length; j++) {
        posDataArrLeft[i][j].x = this.bread.x + posDataArrLeft[i][j].x * this.bread.scaleX ;
        posDataArrLeft[i][j].y = this.bread.y + posDataArrLeft[i][j].y * this.bread.scaleY ;

        posDataArrLeft[i][j].x = Math.round( posDataArrLeft[i][j].x * 100) / 100;
        posDataArrLeft[i][j].y = Math.round( posDataArrLeft[i][j].y * 100) / 100;
      }

      arr = arr.concat(posDataArrLeft[i]);
    }


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

      this.addOneDot(arr[i].x, arr[i].y);
    }

    this.curPosArr = posDataArrLeft[0];

    this.curPosIndex = 0;
    this.posDataIndex = 0;

    this.posDataArr = posDataArrLeft;

  }


  createLine() {

    this.curLine = new Line();
    this.curLine.initData(this.drawLineWidth * this.bread.scaleX, this.drawLineColor);
    this.lineArr.push(this.curLine);
  }



  addOneDot(x = null, y = null) {

    if (x == null || y == null) {
      x = this.mx;
      y = this.my;
    }
    const dot = new Dot(this.ctx);
    dot.init(x, y);

    if (this.dotArr.length === 0) {
      dot['start'] = true;

    } else {

      const lastDot = this.dotArr[this.dotArr.length - 1];
      if (lastDot.end === true) {
        dot['start'] = true;
      }
    }

    this.dotArr.push(dot);


    return dot;
  }




  initBreadLayer() {

    const breadLayer = new MySprite();
    breadLayer.width = this.canvasWidth;
    breadLayer.height = this.canvasHeight;
    this.breadLayer = breadLayer;
    this.renderArr.push(breadLayer);

    const letter = this.letter;

    console.log('letter: ' , letter);

    const bread = new MySprite();
    bread.init(this.images.get('bread-' + letter));
    bread.scaleX = bread.scaleY = this.mapScale;
    bread.x = this.canvasWidth / 2;
    bread.y = this.canvasHeight / 2;
    this.bread = bread;

    const shadow = new MySprite();
    shadow.init(this.images.get('shadow'));
    shadow.y = bread.height / 2 - 15 ;
    bread.addChild(shadow, -1);




    const letterBg = new MySprite(this.ctx);
    letterBg.init(this.images.get('letter-bg'));
    letterBg.scaleX = letterBg.scaleY = this.mapScale;
    letterBg.x = bread.x;
    letterBg.y = bread.y;
    this.breadLayer.addChild(letterBg);
    // this.breadLayer.addChild(bread);

    // this.renderArr.push(letterBg);
    // this.renderArr.push(bread);


  }



  initItem() {






    const bread = new MySprite();
    bread.init(this.images.get('bread-' + this.letter));
    bread.scaleX = bread.scaleY = this.mapScale * 1.5;
    bread.x = this.canvasWidth / 2;
    bread.y = this.canvasHeight / 2;
    this.bread = bread;
    bread.alpha = 0.2;


    const line = new MySprite(this.ctx);
    line.init(this.images.get('line-' + this.letter));
    bread.addChild(line, -1);



  }


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

      setTimeout(() => {

        this.addWaterParticle(this.hotZoneArr[i]);

      }, Math.random() * 3000);
    }
  }

  addWaterParticle(item) {

    const circle = new MySprite();
    circle.init(this.images.get('circle'));
    circle.setScaleXY(this.mapScale);
  }




  showOneParticle(item) {

    // if (!this.showParticleFlag) {
    //   return;
    // }
    //
    // const showTime = 2;
    // const s = 1.9;
    //
    // const particle = this.getParticle();
    // particle.x = item.x;
    // particle.y = item.y;
    // particle.alpha = 0.6;
    //
    // this.particleArr.push(particle);
    //
    //
    // tweenChange(particle, {'alpha': 0, 'scaleX': s, 'scaleY': s}, showTime, () => {
    //   // this.showBtnParticle();
    // }, TWEEN.Easing.Sinusoidal.Out);
    //
    // setTimeout(() => {
    //   this.showOneParticle();
    // }, showTime / 3 * 1000);

  }

  getParticle() {

    const circle = new MySprite();
    circle.init(this.images.get('circle'));
    circle.setScaleXY(this.mapScale);

    return circle;
  }






  initBottomRight() {

    const px = this.canvasWidth - 100 * this.mapScale;
    const py = this.canvasHeight - 50 * this.mapScale;
    const offX = 40 * this.mapScale;



    const leftBtn = new MySprite();
    leftBtn.init(this.images.get('btn_left'));
    leftBtn.setScaleXY(this.mapScale);
    leftBtn.x = px - offX;
    leftBtn.y = py;

    const rightBtn = new MySprite();
    rightBtn.init(this.images.get('btn_right'));
    rightBtn.setScaleXY(this.mapScale);
    rightBtn.x = px + offX;
    rightBtn.y = py;

    this.renderArr.push(leftBtn);
    this.renderArr.push(rightBtn);

    const textBg = new MySprite();
    textBg.init(this.images.get('text_bg'));
    textBg.setScaleXY(this.mapScale);
    textBg.x = px;
    textBg.y = py - 65 * this.mapScale;
    this.renderArr.push(textBg);




    const label = new Label();
    label.text = '0 / 0';
    label.fontName = 'BRLNSDB';
    label.fontSize = 24;
    label.fontColor = '#ffffff';
    label.textAlign = 'center';
    label.setMaxSize( textBg.width * textBg.scaleX * 0.9 );
    textBg.addChild(label);


    this.leftBtn = leftBtn;
    this.rightBtn = rightBtn;
    this.pageLabel = label;

    if (this.picArr.length <= 1) {
      this.leftBtn.visible = false;
      this.rightBtn.visible = false;
      textBg.visible = false;
    }
  }


  refreshPageLabel() {

    const label = this.pageLabel;
    label.text = (this.curPageIndex + 1) + ' / ' + this.picArr.length;

    this.showAudio();
  }

  showAudio() {
    const data = this.picArr[this.curPageIndex];
    const audio = this.audioObj[data.audio_url];
    if (audio) {
      audio.play();
    }
  }




  initPic() {



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

      const data = this.picArr[i];

      const pic = new MySprite();
      pic.init(this.images.get(data.pic_url));
      // pic.x = this.canvasWidth / 2;
      // pic.y = this.canvasHeight / 2;

      const maxW = this.canvasWidth * 0.9;
      const maxH = this.canvasHeight * 0.9;
      const sx = maxW / pic.width;
      const sy = maxH / pic.height;
      const s = Math.min(sx, sy);
      pic.setScaleXY(s);
      // pic.setRadius(50 * this.mapScale);


      const picBg = new ShapeRect();
      picBg.setSize(pic.width * pic.scaleX, pic.height * pic.scaleY);
      picBg.x = this.canvasWidth / 2 + this.canvasWidth * i;
      picBg.y = this.canvasHeight / 2;
      picBg.init();
      picBg.fillColor = '#ffffff';
      // picBg.setRadius(50 * this.mapScale);
      picBg.setShadow(0, 10, 20, 'rgba(0,0,0,0.3)');
      // picBg.alpha = 0;
      // this.renderArr.push(picBg);
      // this.renderArr.push(picShadow);

      picBg.addChild(pic);

      this.bgLayer.addChild(picBg);
    }






  }














  initBg() {

    this.bgArr = [];

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


    const panel = new MySprite();
    panel.init(this.images.get('panel'));
    panel.setScaleXY(this.mapScale);
    panel.x = this.canvasWidth / 2;
    panel.y = this.canvasHeight / 2 + 10 * this.mapScale;
    this.renderArr.push(panel);
    this.panel = panel;


    const w = 800;
    const h = 480;
    const pic = new MySprite();
    pic.init(this.images.get(this.data.contentObj.bgItem.url));
    const sx2 = w / pic.width;
    const sy2 = h / pic.height;
    const s2 = Math.min(sx2, sy2);
    pic.setScaleXY(s2);

    // const pic = new ShapeRect();
    // pic.init();
    // pic.setSize(w, h);
    // pic.alpha = 0.3;

    pic.y = -16;
    panel.addChild(pic);

    this.bg = pic;


    this.bgLayer = new MySprite();
    this.renderArr.push(this.bgLayer);

  }








  mapDown(event) {


    if (!this.canTouch) {
      return;
    }


    if (!this.breadLayer.visible) {

      for (let i = 0; i < this.hotZoneArr.length; i++) {
        if (this.checkClickTarget(this.hotZoneArr[i])) {
          // console.log('clicked hot zone', this.hotZoneArr[i]);
          this.clickHotZone(this.hotZoneArr[i]);
          return;
        }
      }

      if (this.checkClickTarget(this.breadBtn)) {
        this.playAudio('click', true);
        this.breadBtnClick();
        return;
      }

    } else {

      if (this.checkClickTarget(this.panelBtn)) {
        this.playAudio('click', true);
        this.panelBtnClick();
        return;
      }


      this.downFlag = true;
      this.moveFlag = false;

      this.checkTouchCurDot();
    }





  }





  mapMove(event) {

    if (!this.downFlag) { return; }

    // console.log(' in mapMove');
    this.moveFlag = true;

    this.checkTouchCurDot();

  }


  mapUp(event) {

    this.downFlag = false;
    this.moveFlag = false;
    this.checkChangePosArr();
  }








  checkChangePosArr() {

    if (this.curPosIndex >= this.curPosArr.length - 1) {

      if (this.posDataIndex < this.posDataArr.length - 1) {
        this.posDataIndex ++ ;
        this.curPosArr = this.posDataArr[this.posDataIndex];
        this.curPosIndex = 0;
        this.createLine();
      } else {
        (<any> window).courseware.sendEvent('gameEnd');
        console.log('send gameEnd event')
      }
    }
  }



  checkTouchCurDot() {


    if (this.moveFlag && this.curPosIndex === 0) { return; }

    const curDot = this.curPosArr[this.curPosIndex];
    if (curDot) {

      const d = this.getPosDistance(this.mx, this.my, curDot.x, curDot.y);

      const arr = this.curPosArr.slice(0, this.curPosIndex + 1);
      this.curLine.setPosArr(arr);

      if (d <= this.touchAreaMinLen) {
        this.curPosIndex ++ ;
        this.checkTouchCurDot();
      }

    }

  }



  clickHotZone(hotZone) {

    const data = hotZone.data;

    const audio = this.audioObj[data.audio_url];
    if (audio) {
      this.playSoundFlag = true;
      this.playAudio(audio, true, () => {

        this.reshowCircle();
      });
      // audio.play();
    }

  }

  reshowCircle() {

    this.circleArr.length = 0;
    // for (let i = 0; i < this.circleArr.length; i++) {
    //   this.circleArr[i].alpha = 0;
    // }
    this.playSoundFlag = false;

  }


  breadBtnClick() {

    this.breadLayer.visible = true;
    this.panel.visible = false;
  }

  panelBtnClick() {

    this.breadLayer.visible = false;
    this.panel.visible = true;
  }



  nextPageClick() {
    console.log(' in leftBtnClick');

    if (this.curPageIndex >= this.picArr.length - 1) {
      return;
    }

    this.curPageIndex ++;

    this.changePageByIndex();
  }

  lastPageClick() {

    console.log(' in rightBtnClick');


    if (this.curPageIndex <= 0) {
      return;
    }

    this.curPageIndex --;

    this.changePageByIndex();

  }


  changePageByIndex() {

    console.log(' in changePageByIndex');
    this.canTouch = false;


    moveItem(this.bgLayer, -this.curPageIndex * this.canvasWidth, 0, 1, () => {
      this.canTouch = true;
      this.refreshPageLabel();
      // this.resetCurData();
    }, TWEEN.Easing.Cubic.Out);


    this.playAudio('click', true);
  }














  update() {


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

    TWEEN.update();



    this.updateArr(this.renderArr);

    if (this.breadLayer.visible) {
      this.updateArr(this.lineArr);
      this.updateItem(this.bread);
      this.updateItem(this.panelBtn);

    } else {

      if (!this.playSoundFlag) {
        this.updateArr(this.circleArr);
      }
      this.updateItem(this.breadBtn);
    }


  }










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

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


  initHotZone() {


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

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

    const rate = curBgRect.width / oldBgRect.width;


    // this.imgArr = [];
    // const arr = this.data.contentObj.imgItemArr;
    this.hotZoneArr = [];
    const arr = this.data.contentObj.hotZoneItemArr;
    if (!arr) return;

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

      const data = JSON.parse(JSON.stringify(arr[i]));
      // const img = {pic_url: data.pic_url};

      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);
      hotZone.alpha = 0;
      this.hotZoneArr.push(hotZone);

    }

  }




  getHotZoneItem(data) {
    const saveRect = data.rect;
    const item = new ShapeRect(this.ctx);
    item.setSize(saveRect.width, saveRect.height);
    item.x = saveRect.x ;
    item.y = saveRect.y ;
    item['data'] = data;

    this.renderArr.push(item);

    return item;
  }


  showEndPatal() {
    this.endPageArr = [];
    this.showPetalFlag = true;
    this.addPetal();
  }

  stopEndPatal() {
    this.endPageArr = [];
    this.showPetalFlag = false;
  }

  addPetal() {

    if (!this.showPetalFlag) {
      return;
    }

    const petal = this.getPetal();
    this.endPageArr.push(petal);

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

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

    setTimeout(() => {
      this.addPetal();
    }, 200);

  }


  getPetal() {

    const petal = new MySprite(this.ctx);

    const id = Math.ceil( Math.random() * 3 );
    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;

    const randomX = Math.random() * this.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;
  }





  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();
      }
      console.log('touch down');
      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();
      }
      console.log('mouse down');
      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) {

    let audio;
    if (typeof key == 'string') {
      audio = this.audioObj[key];
    } else {
      audio = key;
    }

    if (audio) {
      if (now) {
        audio.pause();
        audio.currentTime = 0;
      }

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




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

  }


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

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

}
