import {
  MySprite,
  getMinScale,
  ShapeRect,
  tweenChange,
  randomSortByArr,
  Label,
  showPopParticle,
  moveItem,
  removeItemFromArr,
  rotateItem,
  ShapeRectNew,
  waterWave,
  ShapeCircle
} from "./Unit";

export class Cartoon {
  
  // 系统缩放比例
  mapScale = 1;
  stageWidth;
  stageHeight;
  clientWidth;
  clientHeight;
  // 音乐 和 图片的缓冲区
  audio = new Map();
  images = new Map();
  imagesOriginSize = new Map();
  
  // 坐标原点 包含缩放
  originX = 0;
  originY = 0;
  
  setOrigin = (x, y)=>{
    this.originX = x;
    this.originY = y;
  }
  getOrigin = ()=>{
    return {
      x: this.originX,
      y: this.originY
    }
  }
  
  // 相对坐标原点 包含缩放 用于添加孩子动画元素
  relativeOriginX = 0;
  relativeOriginY = 0;
  setRelativeOrigin = (x, y)=>{
    this.relativeOriginX = x;
    this.relativeOriginY = y;
  }
  getRelativeOrigin = ()=>{
    return {
      x: this.relativeOriginX,
      y: this.relativeOriginY
    }
  }
  
  // 存放音乐和图片的地址
  audioObj = {}
  imageObj = {}
  _currentPlayAudio;
  // 添加音乐
  addAudio = ( key, url ) => {
    this.audioObj[key] = url
  };
  // 添加音乐
  addImage = ( key, url ) => {
    this.imageObj[key] = url
  };
  // 播放音乐
  _playingNow = []
  audioCallback = {}
  playAudio = function( key, now = false, callback = null, loop?, onplayingCallback?) {
    const audio = this.audio.get(key);
    if (audio) {
      if (now) {
        audio.pause();
        audio.currentTime = 0;
      }
      this.audioCallback[key] = {}
      if (callback) {
        this.audioCallback[key]["onended"] = ()=>{
          callback && callback()
        }
        audio.onended = () => {
          let index = this._playingNow.indexOf(audio)
          if(index != -1){
            this._playingNow.splice(index,1)
          }
          callback();
        };
      }
      if(onplayingCallback){
        this.audioCallback[key]["onplaying"] = ()=>{
          onplayingCallback && onplayingCallback(audio)
        }
        audio.onplaying = ()=>{
          onplayingCallback && onplayingCallback(audio)
        }
      }
      audio.play();
      audio.callback = callback
      audio.loop = loop?true:false
      this._playingNow.push(audio)   
      this._currentPlayAudio = audio;
    }
  }
  setAudioVolume(key, volume){
    if(volume<0 || volume>1){
      return
    }
    const audio = this.audio.get(key);
    audio.volume = volume
  }
  stopAllAudio(){
    this._playingNow.forEach(audio=>{
      try{
        if(audio){
          audio.onended && audio.onended()
          audio.pause();
          audio.currentTime = 0;
        }else{
          if(audio.src && this.audioCallback[audio.src] && this.audioCallback[audio.src]["onended"]){
            this.audioCallback[audio.src]["onended"]()
          }
        }
      }catch(err){
        console.log(err)
      }
    })
    this._playingNow = []
  }
  stopAudio(audio_URL?){
    if(audio_URL){
      const audio = this.audio.get(audio_URL);
      try{
        if(audio){
          audio.onended && audio.onended()
          audio.pause();
          audio.currentTime = 0;
        }else{
          if(this.audioCallback[audio_URL] && this.audioCallback[audio_URL]["onended"]){
            this.audioCallback[audio_URL]["onended"]()
          }
        }
        
      }catch(err){
        console.log(err)
      }
    }
    else if(this._currentPlayAudio){
      this._currentPlayAudio.pause();
      this._currentPlayAudio.currentTime = 0;
    }
  }
  // 异步加载图片 音频资源
  loadResources = ()=> {
    const pr = [];
    for(let key in this.imageObj){
      const p = this.preloadImage(this.imageObj[key]).then( (img:any) => {
        this.images.set(key, img);
        this.imagesOriginSize.set(key, {width:img.width, height:img.height});
      }).catch(err => console.log(key));
      pr.push(p);
    };
    for(let key in this.audioObj){
      const a = this.preloadAudio(this.audioObj[key]).then( (audio:any) => {
        this.audio.set(key, audio);
      }).catch(err => console.log(key));
      pr.push(a);
    };
    return Promise.all(pr);
  }
  
  // 预加载图片
  preloadImage = (url) => {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.src = url;
      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);
      };
      audio.onerror = () => {
        reject();
      };
      audio.src = url;
      audio.load();
    });
  }
  
  // 缓存页面元素
  cartoonElementsBuffer = {}
  createCartoonElement = (key, type)=>{
    this.cartoonElementsBuffer[key] = {}
    this.cartoonElementsBuffer[key].id = key;
    switch(type){
      case "MySprite": this.cartoonElementsBuffer[key].ref = new MySprite(); break;
      case "ShapeRect": this.cartoonElementsBuffer[key].ref = new ShapeRect(); break;
      case "ShapeRectNew": this.cartoonElementsBuffer[key].ref = new ShapeRectNew(); break;
      case "Label": this.cartoonElementsBuffer[key].ref = new Label(); break;
      case "waterWave":  this.cartoonElementsBuffer[key].ref = new waterWave(); break;
      case "ShapeCircle": this.cartoonElementsBuffer[key].ref = new ShapeCircle(); break;
      default : this.cartoonElementsBuffer[key].ref = new MySprite(); break;
    }
    this.cartoonElementsBuffer[key].ref.id = key;
    return this.cartoonElementsBuffer[key]
  }

  createCartoonElementImage(id:string, image:string, width:number, height:number, initX:number, initY:number, withScale?:boolean){
    let element = this.createCartoonElement(id, "MySprite")
    element.ref.init(this.images.get(image))
    element.initX = initX
    element.initY = initY
    if(withScale){
      element.initScaleX = width*this.mapScale / element.ref.width
      element.initScaleY = height*this.mapScale / element.ref.height
    }else{
      element.initScaleX = width / element.ref.width
      element.initScaleY = height / element.ref.height
    }
    element.ref.scaleX = element.initScaleX
    element.ref.scaleY = element.initScaleY
    element.ref.x = element.initX
    element.ref.y = element.initY
    return this.cartoonElementsBuffer[id]
  }

  createCartoonElementImageFunc(id:string, image:string, callbackScale:Function, callbackPosition:Function){
    let element = this.createCartoonElement(id, "MySprite")
    element.ref.init(this.images.get(image))
    element.rePosition = ()=>{
      let scale = callbackScale(element.ref.width, element.ref.height)
      let position = callbackPosition(element.ref.width, element.ref.height)
      // save initScale
      element.ref.initScaleX = scale.sx
      element.ref.initScaleY = scale.sy
      element.initScaleX = scale.sx
      element.initScaleY = scale.sy
      
      // save initX_Y
      element.ref.initX = position.x
      element.ref.initY = position.y
      element.initX = position.x
      element.initY = position.y

      // save initRotation
      element.ref.initRotation = element.rotation?element.rotation:0
      element.initRotation = element.rotation?element.rotation:0

      element.ref.scaleX = scale.sx
      element.ref.scaleY = scale.sy
      element.ref.x = element.initX
      element.ref.y = element.initY
    }
    element.rePosition()
    return this.cartoonElementsBuffer[id]
  }

  createLabel = ( text, fontName, fontColor, fontSize, initX?, initY? )=>{
    let element = new Label()
    element.text = text;
    if(fontName){
      element.fontName = fontName;
    }
    if(fontColor){
      element.fontColor = fontColor;
    }
    if(fontSize){
      element.fontSize = fontSize;
    }
    element.textAlign = "center";
    element.x = initX;
    element.y = initY;
    return element
  }

  createImage(image, callbackScale, callbackPosition ){
    let element = new MySprite()
    element.init(this.images.get(image))

    let scale = callbackScale(element.width, element.height)
    let position = callbackPosition(element.width, element.height)

    element.scaleX = scale.sx
    element.scaleY = scale.sy
    element.x = position.x
    element.y = position.y

    return element
  }

  getCartoonElementRef = (key)=>{
    if(this.cartoonElementsBuffer[key]){
      return this.cartoonElementsBuffer[key].ref;
    }else{
      return undefined
    }
  }
  getCartoonElement = (key)=>{
    return this.cartoonElementsBuffer[key]
  }
  getCartoonElementsRef = (keys)=>{
    let allElelemts = []
    keys.forEach(id => {
      if(this.cartoonElementsBuffer[id]){
        allElelemts.push(this.cartoonElementsBuffer[id].ref)
      }
    });
    return allElelemts
  }
  getCartoonElements = (keys)=>{
    let allElelemts = []
    keys.forEach(id => {
      if(this.cartoonElementsBuffer[id]){
        allElelemts.push(this.cartoonElementsBuffer[id])
      }
    });
    return allElelemts
  }
  getAllCartoonElement = ()=>{
    return this.cartoonElementsBuffer
  }


  setCartoonElementPosition = (key, posi)=>{
    this.cartoonElementsBuffer[key].ref.x = posi.x
    this.cartoonElementsBuffer[key].ref.y = posi.y
    this.cartoonElementsBuffer[key].x = posi.x
    this.cartoonElementsBuffer[key].y = posi.y
  }
  setCartoonElementPositionX = (key, x)=>{
    this.cartoonElementsBuffer[key].ref.x = x
    this.cartoonElementsBuffer[key].x = x
  }
  setCartoonElementRelativePositionX = (key, x)=>{
    this.cartoonElementsBuffer[key].relativeX = x
  }
  setCartoonElementPositionY = (key, y)=>{
    this.cartoonElementsBuffer[key].ref.y = y
    this.cartoonElementsBuffer[key].y = y
  }
  setCartoonElementRelativePositionY = (key, y)=>{
    this.cartoonElementsBuffer[key].relativeY = y
  }

  getCartoonElementPosition = (key)=>{
    return {
      x: this.cartoonElementsBuffer[key].x,
      y: this.cartoonElementsBuffer[key].y
    }
  }
  getCartoonElementRelativePosition = (key)=>{
    return {
      x: this.cartoonElementsBuffer[key].relativeX,
      y: this.cartoonElementsBuffer[key].relativeY
    }
  }

  resetAll = ()=>{
    this.cartoonElementsBuffer = {}
  }

}