export default class Cartoon {
  elements = {

  }

  touchEventCallback = {

  }

  audioCallback = {

  }

  constructor() {

  }

  audios = {}
  audioIDs = {}
  
  initCartoonElement(key, node) {
    if(!node) {
      console.error("Can not find node for key:[" + key + "]")
    }
    this.elements[key] = {}
    this.elements[key].key = key
    this.elements[key].node = node
    this.elements[key].initX = node.x
    this.elements[key].initY = node.y
    this.elements[key].initScaleX = node.scaleX
    this.elements[key].initScaleY = node.scaleY
    this.elements[key].dragonBones = new DragonBones(node)

    this.elements[key]["setLocation"] = (x, y) => {
      if(x) {
        this.elements[key].initX = x
        this.elements[key].node.x = x
      }
      if(y) {
        this.elements[key].initY = y
        this.elements[key].node.y = y
      }
    }

    return this.elements[key]
  }

  getCartoonElement(key) {
    let node = this.elements[key]
    if(!node) {
      console.error("Can't find '" + key + "' node.")
    }
    return node
  }

  getSpritNode(nodeName, nameSpace = "") {
    let node = cc.find(`${nameSpace}${nodeName}`)
    return node?node:null
  }

  getNodeByName(nodeName, parentNodeName) {
    let node = null
    if(parentNodeName) {
      node = this.getSpritNode(parentNodeName).getChildByName(nodeName)
    } else {
      node = this.getSpritNode(nodeName)
    }
    return node?node:null
  }

  getNodeByPath(path) {
    let node = cc.find(path)
    if(!node) {
      console.warn("Can not fount node.(PATH:" + path + ")")
    }
    return node?node:null
  }

  getColor(hex) {
    let color = new cc.color()
    color.fromHEX(hex);
    return color
  }

  getFontFamily(fontName) {
    let font = cc.find(`Canvas/res/font/${fontName}`).getComponent('cc.Label').font;
    return font
  }

  newLabelNode(text, fontFamily, fontSize, color) {
    const labelNode = new cc.Node();
    labelNode.color = this.getColor(color);
    const label = labelNode.addComponent(cc.Label);
    label.string = text;
    label.fontSize = fontSize;
    label.lineHeight = fontSize;
    label.font = this.getFontFamily(fontFamily);
    return labelNode
  }

  createFrameAni(imagePath, len) {
    let frameAni = new cc.Sprite(imagePath.replace(/_NUM_/g, 1));
    frameAni.setPosition(cc.p(cc.winSize.width*0.3, cc.winSize.height/2));
    this.addChild(frameAni);

    //创建帧动画序列，名词形式
    var animation = new cc.Animation();
    for (var i = 1; i <= len; i++) {
        animation.addSpriteFrameWithFile(imagePath.replace(/_NUM_/g, i));
    }
    //设置帧动画属性
    animation.setDelayPerUnit(2.0 / 4);       //每一帧停留的时间
    animation.setRestoreOriginalFrame(true);   //播放完后回到第一帧
    var animate = new cc.Animate(animation);
    frameAni.run = () => {
      frameAni.runAction(new cc.RepeatForever(animate));
    }
  }
  
  cloneNode(targetNode) {
    var node = cc.instantiate(targetNode);
    return node
  }

  subscribeTouchEvent(key, callBack) {
    if(!this.touchEventCallback[key]) {
      this.touchEventCallback[key] = callBack
      
      this.elements[key].node.off(cc.Node.EventType.TOUCH_START)
      this.elements[key].node.on(cc.Node.EventType.TOUCH_START, ()=>{
        if(this.touchEventCallback[key]) {
          this.touchEventCallback[key]()
        }
      })
    } else {
      this.touchEventCallback[key] = callBack
    }
  }

  initLocalAudios(audioNames = []) {
    const audioNode = cc.find('Canvas/res/audio');
    const getAudioByResName = (resName) => {
      return audioNode.getChildByName(resName).getComponent(cc.AudioSource);
    }
    audioNames.forEach(audioName=>{
      this.audios[audioName] = getAudioByResName(audioName);
    })
  }

  playLocalAudio(audioName, cb) {
    let audio = cc.audioEngine.play(this.audios[audioName].clip, false, 0.2)
    if (cb) {
      this.audioCallback[audio_url] = cb
      cc.audioEngine.setFinishCallback(audio, () => {
        delete this.audioCallback[audio_url]
        cb();
      });
    }
  }

  // Video
  getVideo(video_url){
    return new Promise((resolve, reject)=>{
      cc.assetManager.loadRemote(video_url, (err, videoClip) => {
        resolve(videoClip)
      });
    })
  }

  stopVideo(videoPlayer) {
    console.log(videoPlayer)
    if(videoPlayer.clip && videoPlayer.clip.loaded) {
      videoPlayer.stop()
    }
  }

  playVideo(videoPlayer, callback) {
    if(videoPlayer && videoPlayer.isPlaying) {
      videoPlayer.stop()
    }

    if(videoPlayer) {
      setTimeout(()=>{
        videoPlayer.play()
        videoPlayer.node.off("completed")
        videoPlayer.node.on("completed", ()=>{
          if(callback) {
            callback()
          }
        })
      }, 50)
    }
  }

  // Audio
  playAudio(audio_url, cb = null) {
    return new Promise((resolve, reject)=>{
      if (audio_url) {
      var urlreg=/^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*([\?&]\w+=\w*)*$/
      if(urlreg.test(audio_url)) {
        cc.assetManager.loadRemote(audio_url, (err, audioClip) => {
          if(cb) {
            this.audioCallback[audio_url] = cb
          }
          const audioId = cc.audioEngine.play(audioClip, false, 1);
          if (cb) {
            cc.audioEngine.setFinishCallback(audioId, () => {
              delete this.audioCallback[audio_url]
              cb();
            });
          }
          this.audioIDs[audio_url] = audioId
          resolve(audioId)
        });
      } else {
        const audioNode = cc.find('Canvas/res/audio').getChildByName(audio_url).getComponent(cc.AudioSource);
        let audioId = cc.audioEngine.play(audioNode.clip, false, 1)
        if (cb) {
          this.audioCallback[audio_url] = cb
          cc.audioEngine.setFinishCallback(audioId, () => {
            delete this.audioCallback[audio_url]
            cb();
          });
        }
        this.audioIDs[audio_url] = audioId
        resolve(audioId)
      }
    }
    })
  }

  stopAllAudio(exceptUrls = []) {
    for(let key in this.audioIDs) {
      if(exceptUrls.indexOf(key) == -1) {
        if(this.audioCallback[key]) {
          this.audioCallback[key]()
        }
        if(this.audioIDs[key]) {
          cc.audioEngine.stop(this.audioIDs[key])
          delete this.audioIDs[key];
        }
      }
    }
  }

  // Tweenchange
  tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) {
    const tween = cc.tween(item).to(time, obj).call(()=>{
      if(callBack) {
        callBack()
      }
    });
    easing && tween.easing(easing);
    update && tween.onUpdate((a, b) => { update(a, b); });
  
    tween.start();
    return tween;
  }

  // Common Ani
  creatSpeaker(parentNode, nodeName1, nodeName2) {
    const sprNode = this.cloneNode(this.getNodeByPath(`Canvas/res/img/${nodeName1}`));
    sprNode.parent = parentNode;
    sprNode.x = 0;
    sprNode.y = 0;
    sprNode.zIndex = 2;
    parentNode.icon = sprNode;

    const sprNode2 = this.cloneNode(this.getNodeByPath(`Canvas/res/img/${nodeName2}`));
    sprNode2.parent = sprNode.parent;
    sprNode2.x = sprNode.x;
    sprNode2.y = sprNode.y;
    sprNode2.opacity = 0;
    sprNode.spr2 = sprNode2;

    // sprNode.addComponent(cc.Button)
    // sprNode.on('click', () => {
    //   this.showSoundAnima(sprNode);
    //   if(clickCB) {
    //     clickCB(this)
    //   }
    //   playAudioByUrl( item.data.audio_url , () => {
    //     this.stopSoundAnima(sprNode);
    //   });
    // });

    return sprNode
  }

  showSoundAnima(iconNode, time = 0.4) {
    iconNode.isRunAnima = true;
    iconNode.spr2.opacity = 255;
    iconNode.opacity = 0;

    cc.tween(iconNode)
      .delay(time / 2)
      .call(() => {
        iconNode.spr2.opacity = 0;
        iconNode.opacity = 255;
      })
      .delay(time / 2)
      .call(() => {
        if (iconNode.isRunAnima) {
          this.showSoundAnima(iconNode);
        }
      })
      .start()
  }

  stopSoundAnima(iconNode) {
    iconNode.isRunAnima = false;
  }
}


class DragonBones {
  parentNode = null
  _animationLoaded = null
  constructor(parentNode) {
    this.parentNode = parentNode
  }

  resetDragonBones() {
    const picNode = this.parentNode
    if (picNode.animaNode) {
      picNode.animaNode.removeFromParent();
      this._animationLoaded = null
    }
  }

  setDragonBones(dragonBonesConfig, armatureName, callback, onClickCB) {
    const parentNode = this.parentNode
    if (parentNode.animaNode) {
      parentNode.animaNode.removeFromParent();
    }
    const animaNode = new cc.Node();
    animaNode.parent = parentNode;
    parentNode.animaNode = animaNode;

    
    const dragonDisplay = animaNode.addComponent(dragonBones.ArmatureDisplay);

    this._animationLoaded = dragonDisplay;
    
    // const image = "http://staging-teach.cdn.ireadabc.com/5a0c5af3e952acd0ac83a6e5c6f03ff1.png";
    // const ske = "http://staging-teach.cdn.ireadabc.com/bd825dcceea298d1146be8067ae3d17f.json";
    // const atlas = "http://staging-teach.cdn.ireadabc.com/246f8991b729fa3e5a7f4802de828efa.json";
    
    const image = dragonBonesConfig.texPngData.url
    const ske = dragonBonesConfig.skeJsonData.url
    const atlas = dragonBonesConfig.texJsonData.url

    cc.loader.load(image, (error, texture) => {
      cc.loader.load({url: atlas, type: 'txt'}, (error, atlasJson) => {
        cc.loader.load({url: ske, type: 'txt'}, (error, dragonBonesJson) => {
          const atlas = new dragonBones.DragonBonesAtlasAsset();
          atlas.atlasJson = (atlasJson);
          atlas.texture = texture;

          const asset = new dragonBones.DragonBonesAsset();
          asset.dragonBonesJson = (dragonBonesJson);

          dragonDisplay.dragonAtlasAsset = atlas;
          dragonDisplay.dragonAsset = asset;

          let json = JSON.parse(asset.dragonBonesJson);
          let armatures = json["armature"];
          let armatureNames = [];
          for (let i = 0; i < armatures.length; i++) {   
            armatureNames.push(armatures[i].name);
          }

          let armatureNameIndex = armatureNames.indexOf(armatureName)
          if(armatureNameIndex == -1) {
            armatureNameIndex = 0;
          }

          if (armatureNames.length > 0) {
            let defaultArmatureName = armatureNames[armatureNameIndex];
            dragonDisplay.armatureName = defaultArmatureName;

            let defaultArmature = armatures[armatureNameIndex];
            let animations = defaultArmature.animation;
            let animationNames = [];
            for (let i = 0; i < animations.length; i++) {
              animationNames.push(animations[i].name);
            }
            
            dragonDisplay.animaNames = animationNames;
            animaNode.addComponent(cc.Button)
            animaNode.on('click', ()=>{
              if(onClickCB) {
                onClickCB(this)
              }
            })
          }
          
          

          let sx = parentNode.width / animaNode.width;
          let sy = parentNode.height / animaNode.height;
          animaNode.setScale(Math.min(sx, sy));
          if(callback) {
            callback(this)
          }
        });
      });
    });
  }

  deleteDragonBones() {
    const parentNode = this.parentNode
    if (parentNode.animaNode) {
      parentNode.animaNode.removeFromParent();
    }
  }

  stopDragonBones() {
    if(this._animationLoaded) {
      this._animationLoaded.armature().animation.stop();
    }
  }

  showDragonBones(times = 1, animaName, callBack) {
    let animaNameIndex = this._animationLoaded.animaNames.indexOf(animaName)
    if (this._animationLoaded && this._animationLoaded.animaNames.length > 0) {
      if(!animaName || animaNameIndex==-1) {
        this._animationLoaded.playAnimation(this._animationLoaded.animaNames[0], times);
      } else {
        this._animationLoaded.playAnimation(animaName, times);
      }
      // this._animationLoaded.on(this._animationLoaded.EventObject.COMPLETE, callback)
    }
  }
}