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

import {
  Label,
  MySprite, tweenChange,
  Line,
  ShapeRectNew,
  ShapeRect
} from './Unit';
import { res, resAudio } from './resources';

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

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

import { Title, getDefaultTile } from './Title';

import { getDefaultExercisesItem, Exercises } from './Exercises';

import { Listening } from './Listening';
import { NzTreeHigherOrderServiceToken } from 'ng-zorro-antd';


@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 = {};

  //A皮肤显示框
  skinRenderArr = [];

  renderArr;

  bigCardRenderArr;


  mapScale = 1;
  mapScaleX = 1;
  mapScaleY = 1;

  canvasLeft;
  canvasTop;

  saveKey = 'YM-42';


  canTouch = true;

  /**标题*/
  title;

  listening;

  exercisesArr;

  curAudio;

  mask : ShapeRect;

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

    this.playAudio('page');
  }

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

  pauseAudio(key, callback = null) {

    const audio = this.audioObj[key];
    if (audio) {

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



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

    if (!key) {
      return;
    }

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

  addUrlToImage(url, key){
    if(!key){
      key = url;
    }

    this.rawImages.set(key, url);
  }




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





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

    if (!this.data.exercisesArr) {

      this.data.exercisesArr = [];

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

        let exercises = getDefaultExercisesItem();

        exercises.index = i + i;

        this.data.exercisesArr.push(exercises);

      }

      console.log(this.data.exercisesArr);
    }

    if (!this.data.title) {
      this.data.title = getDefaultTile();
    }

    //设置默认皮肤
    if (!this.data.skin) {
      this.data.skin = 'A';
    }
  }


  /**
   * 添加预加载图片
   */
  initImg() {
    //练习题图片
    for (let i = 0; i < this.data.exercisesArr.length; ++i) {

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

      if (exercises.pic_url) {
        this.addUrlToImages(exercises.pic_url);
      }

    }

    const loadBg = (skin, skinType) =>{
      if (skin.lt_pic_url) {
        this.addUrlToImage(skin.lt_pic_url, skinType + "_" + skin.lt_pic_url);
      }
  
      if (skin.lm_pic_url) {
        this.addUrlToImage(skin.lm_pic_url, skinType + "_" + skin.lm_pic_url);
      }
  
      if (skin.lb_pic_url) {
        this.addUrlToImage(skin.lb_pic_url, skinType + "_" + skin.lb_pic_url);
      }
  
      if (skin.mt_pic_url) {
        this.addUrlToImage(skin.mt_pic_url, skinType + "_" + skin.mt_pic_url);
      }
  
      if (skin.mb_pic_url) {
        this.addUrlToImage(skin.mb_pic_url, skinType + "_" + skin.mb_pic_url);
      }
  
      if (skin.rt_pic_url) {
        this.addUrlToImage(skin.rt_pic_url, skinType + "_" + skin.rt_pic_url);
      }
  
      if (skin.rm_pic_url) {
        this.addUrlToImage(skin.rm_pic_url, skinType + "_" + skin.rm_pic_url);
      }
  
      if (skin.rb_pic_url) {
        this.addUrlToImage(skin.rb_pic_url, skinType + "_" + skin.rb_pic_url);
      }
    }

    if(this.data.skinA){
      loadBg(this.data.skinA, 'A');
    }

    if(this.data.skinB){
      loadBg(this.data.skinB, 'B');
    }
  }

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

    // 音效
    this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3);
    this.addUrlToAudioObj('waves', this.rawAudios.get('waves'));
    this.addUrlToAudioObj('back', this.rawAudios.get('back'));
    this.addUrlToAudioObj('page', this.rawAudios.get('page'));

    //标题发音
    if (this.data.title.audio_url) {
      this.addUrlToAudioObj('titleAudio', this.data.title.audio_url);
    }


    //听力材料
    if (this.data.listenAudioUrl) {
      this.addUrlToAudioObj('listenAudio', this.data.listenAudioUrl);
    }


    //练习题音效
    for (let i = 0; i < this.data.exercisesArr.length; ++i) {

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

      if (exercises.audio_url) {
        this.addUrlToAudioObj('exercises_' + i, 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.mapScaleX = s;
    this.mapScaleY = s;


    this.renderArr = [];

    this.bigCardRenderArr = [];

    this.exercisesArr = [];

    this.skinRenderArr = [];
  }



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

    this.initBg();

    this.initTitle();

    this.initBottomPart();

    this.initExercises();
  }

  initBg() {
    
    const getPic = (key, anchorX: number = 0.5, anchorY: number = 0.5) => {
      const pic = new MySprite();
      pic.init(this.images.get(key), anchorX, anchorY);
      pic.setScaleXY(this.mapScale);
      this.skinRenderArr.push(pic);
      return pic;
    }

    const initBg = (skin, skinType) => {
      
      //左上
      if (skin.lt_pic_url) {
        const pic = getPic(skinType + '_' + skin.lt_pic_url, 0, 0);
        pic.x = 0;
        pic.y = 0;

      }

      //左中
      if (skin.lm_pic_url) {
        const pic = getPic(skinType + '_' + skin.lm_pic_url, 0);
        pic.x = 0;
        pic.y = (this.canvasHeight - pic.getBoundingBox().height) / 2;
      }

      //左下
      if (skin.lb_pic_url) {
        const pic = getPic(skinType + '_' + skin.lb_pic_url, 0, 1);
        pic.x = 0;
        pic.y = this.canvasHeight;
      }

      //中上
      if (skin.mt_pic_url) {
        const pic = getPic(skinType + '_' + skin.mt_pic_url, 0.5, 0);
        pic.x = this.canvasWidth / 2;
        pic.y = 0;
      }

      //中下
      if (skin.mb_pic_url) {
        const pic = getPic(skinType + '_' + skin.mb_pic_url, 0.5, 1);
        pic.x = this.canvasWidth / 2;
        pic.y = this.canvasHeight;
      }

      //右上
      if (skin.rt_pic_url) {
        const pic = getPic(skinType + '_' + skin.rt_pic_url, 1, 0);
        pic.x = this.canvasWidth;
        pic.y = 0;
      }

      //右中
      if (skin.rm_pic_url) {
        const pic = getPic(skinType + '_' + skin.rm_pic_url, 1, 0.5);
        pic.x = this.canvasWidth;
        pic.y = this.canvasHeight / 2;
      }

      //右下
      if (skin.rb_pic_url) {
        const pic = getPic(skinType + '_' + skin.rb_pic_url, 1, 1);
        pic.x = this.canvasWidth;
        pic.y = this.canvasHeight;
      }
    }

    if(this.data.skin === 'A'){
      if(this.data.skinA){
        initBg(this.data.skinA, 'A');
      }
    }
    else{
      if(this.data.skinB){
        initBg(this.data.skinB, 'B');
      }
    }
  }

  initBottomPart() {

    const listening = new Listening(this.audioObj['listenAudio'], this.images);
    listening.init(this.mapScale, this.mapScale);

    listening.bg.x = this.canvasWidth - listening.bg.width - 10 * this.mapScale;
    listening.bg.y = this.canvasHeight - listening.bg.height - 8 * this.mapScale;
    this.listening = listening;

    this.renderArr.push(listening.bg);
  }

  initTitle() {
    const title = new Title(this.data.title, this.images);

    title.init(this.mapScale, this.mapScale);
    title.audio = this.audioObj['titleAudio'];
    this.title = title;

    title.titleBg.y = 0;
    title.titleBg.x = 0;

    this.renderArr.push(title.titleBg);
  }

  initExercises() {

    let startX = 81 * this.mapScaleX;

    let startY = 157 * this.mapScaleY;
    


    let lBgArr = [];
    //如果是A皮肤，则增加长的背景信息
    if (this.data.skin === 'A') {

      startX = (this.canvasWidth - 1100 * this.mapScale) / 2;

      let height = 3 * 80 * this.mapScale + (3-1) * 61 * this.mapScale;

      startY = (this.canvasHeight - height) / 2;

      for (let i = 0; i < 3; ++i) {
        const lBg = new ShapeRectNew();
        lBg.fillColor = "#E5E3E4";
        lBg.x = startX;
        lBg.setSize(1100 * this.mapScale, 80 * this.mapScale, 40 * this.mapScale);
        this.skinRenderArr.push(lBg);
        lBgArr.push(lBg);

      } 
    }
    else{
      let width = 2 * 560 * this.mapScale + 25 * this.mapScaleX;

      startX = (this.canvasWidth - width) / 2;

      let height = 3 * 96 * this.mapScale + (3-1) * 78 * this.mapScale;

      startY = (this.canvasHeight - height) / 2;
    }

    let tempStartY = startY;

    let startYArr = [];

    startYArr.push(startY);

    let hight = 0;

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

      let index = i + 1;

      let exercisesData = this.data.exercisesArr[i];

      exercisesData.index = index;


      let exercises = new Exercises(exercisesData, this.images);
      exercises.audio = this.audioObj['exercises_' + i];

      exercises.init(this.data.skin, this.mapScaleX, this.mapScaleY);

      this.exercisesArr.push(exercises);

      exercises.bg.x = startX;

      exercises.bg.y = startY;

      if (index % 3 == 0) {

        if (this.data.skin === 'A') {
          startX = startX + exercises.bg.width;
        }
        else {
          startX = startX + 25 * this.mapScaleX + exercises.bg.width;
        }

        //到下一行增加高度
        startY = tempStartY;

        
      }
      else {
        if (this.data.skin === 'A') {
          startY = startY + exercises.bg.height + 61 * this.mapScaleY;
        }
        else {
          startY = startY + exercises.bg.height + 78 * this.mapScaleY;
        }
        hight = exercises.bg.height;
        startYArr.push(startY);
      }

      this.renderArr.push(exercises.bg);

      this.bigCardRenderArr.push(exercises.cardBg);
    }

    for(let i = 0; i < lBgArr.length; ++ i){
      lBgArr[i].y = startYArr[i];
      lBgArr[i].height = hight ;
    }

    let minFontSize = 100;

    //获取最小字体
    for (let i = 0; i < this.exercisesArr.length; ++i) {

      let textLabel = this.exercisesArr[i].textLabel;

      if (minFontSize > textLabel.fontSize) {
        minFontSize = textLabel.fontSize;
      }

    }

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

      this.exercisesArr[i].resetText(minFontSize, this.data.skin);
    }

    const mask = new ShapeRect();
    mask.setSize(this.canvasWidth, this.canvasHeight);
    mask.visible = false;
    mask.alpha = 0.3
    mask.fillColor = "#000000";
    this.renderArr.push(mask);
    this.mask = mask;
  }

  mapDown(event) {

    if (!this.canTouch) {
      return;
    }

    if (this.curAudio) {
      if (this.curAudio != this.listening.audio) {
        this.curAudio.pause();
      }
    }

    if (this.checkClickTarget(this.listening.bg)) {

      this.curAudio = this.listening.play(()=>{
        this.listening.reset();
      });

      return;
    }

    if (this.curAudio) {
      if (this.curAudio == this.listening.audio) {
        this.listening.pauseAudio();
      }
      else {
        this.curAudio.pause();
      }

    }

    if (this.checkClickTarget(this.title.titleBg)) {
      this.curAudio = this.title.playAudio();
      return;
    }

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

      let exer = this.exercisesArr[i];

      if (!exer.canClick) {
        continue;
      }

      if (this.checkClickTarget(exer.bg)) {

        if (!exer.showed) {
          this.playAudio('waves', true);

          this.mask.visible = true;
          exer.showBigCard(this.canvasWidth / 2, this.canvasHeight / 2, () => {

            //将其它词组设置为不可点击
            for (let j = 0; j < this.exercisesArr.length; ++j) {

              if (i != j) {
                //暂停其它音频播放
                this.exercisesArr[j].pasueAudio();
                this.exercisesArr[j].canClick = false;
              }
            }
          });

          return;
        }

      }

      if (exer.canClickCard) {

        if (this.checkClickTarget(exer.overturnPic)) {
          this.playAudio('turn', true);
          exer.overturn(1);
          return;
        }

        if (this.checkClickTarget(exer.closePic)) {

          this.playAudio('turn', true);

          this.mask.visible = false;
          exer.close(() => {
            //将词组设置为可点击
            for (let j = 0; j < this.exercisesArr.length; ++j) {
              this.exercisesArr[j].canClick = true;
            }
          });
          return;
        }

        if (this.checkClickTarget(exer.bigCard)) {

          this.curAudio = exer.playAudio();
        }
      }


    }
  }

  mapMove(event) {

  }

  mapUp(event) {

  }



  update() {

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

    this.updateArr(this.skinRenderArr);

    this.updateArr(this.renderArr);

    this.updateArr(this.bigCardRenderArr);
  }

}
