import { defaultData } from "../script/defaultData";
import { asyncDelay, jelly } from "../script/utils";
import { letterData, letterWidthData } from "../script/letterPointData";
import BgManager from "../script/BgManager";
import { getPosByAngle, getAngleByPos, getSprNode, delayCall, showBtnAnima, playAudio, playAudioByUrl, onHomeworkFinish, showTrebleFirework } from "../script/util";
import {letter_data} from "./letter_data";

cc.Class({
  extends: cc.Component,

  properties: {
  
  },

  // 生命周期 onLoad
  onLoad() {
    this.initSceneData();
    this.initSize();
  },

  _designSize: null,
  _frameSize: null,
  _mapScaleMin: null,
  _mapScaleMax: null,
  _cocosScale: null,
  canvas: null,
  initSize() {
    // 注意cc.winSize只有在适配后(修改fitHeight/fitWidth后)才能获取到正确的值,因此使用cc.getFrameSize()来获取初始的屏幕大小
    let screen_size =
      cc.view.getFrameSize().width / cc.view.getFrameSize().height;
    let design_size =
      cc.Canvas.instance.designResolution.width /
      cc.Canvas.instance.designResolution.height;
    let f = screen_size >= design_size;
    cc.Canvas.instance.fitHeight = f;
    cc.Canvas.instance.fitWidth = !f;

    const frameSize = cc.view.getFrameSize();
    this._frameSize = frameSize;

    this._designSize = cc.view.getDesignResolutionSize();

    let sx = cc.winSize.width / frameSize.width;
    let sy = cc.winSize.height / frameSize.height;
    this._cocosScale = Math.min(sx, sy);

    sx = frameSize.width / this._designSize.width;
    sy = frameSize.height / this._designSize.height;
    this._mapScaleMin = Math.min(sx, sy) * this._cocosScale;
    this._mapScaleMax = Math.max(sx, sy) * this._cocosScale;

    this.canvas = cc.find("Canvas");

    // cc.log('cc.Canvas: ', cc.Canvas);
  },

  _imageResList: null,
  _audioResList: null,
  _animaResList: null,
  initSceneData() {
    this._imageResList = [];
    this._audioResList = [];
    this._animaResList = [];
  },

  // 生命周期 start
  start() {
    let getData = this.getData.bind(this);
    if (window && window.courseware) {
      getData = window.courseware.getData;
    }

    getData((data) => {
      console.log("data:", data);
      this.data = data || this.getDefaultData();
      this.data = JSON.parse(JSON.stringify(this.data));
      this.preloadItem();
    });
  },

	getData(func) {
		if (window && window.courseware) {
			window.courseware.getData(func, 'dfzx_cocos_trace_letter');
			return;
		}

		const middleLayer = cc.find('middleLayer');
		if (middleLayer) {
			const middleLayerComponent = middleLayer.getComponent('middleLayer');
			middleLayerComponent.getData(func);
			return;
		}

		func(this.getDefaultData());
	},

  getDefaultData() {
    return {"style":"America","batch":"one","groupArr":[{"letterArr":[{"letter":"A"},{"letter":"bc","audio_url":"http://staging-teach.cdn.ireadabc.com/fbe2f23b9eb191a9330f99800e0d54d5.mp3"},{"letter":"d"}]},{"letterArr":[{"letter":"ad","audio_url":"http://staging-teach.cdn.ireadabc.com/cf5077b8cbcaa1dc664df569d4af6043.mp3"},{"letter":"X"},{"letter":"Y"},{"letter":"z"}]}]}

    // console.log("defaultData = " + defaultData);
    // return defaultData;
  },

  preloadItem() {
    this.addPreloadImage();
    this.addPreloadAudio();
    this.addPreloadAnima();
    this.preload();
  },

  addPreloadImage() {
    // this._imageResList.push({ url: this.data.pic_url });
  },

  addPreloadAudio() {
    const groupArr = this.data.groupArr;
    for (let i=0; i<groupArr.length; i++) {
      const letterArr = groupArr[i].letterArr;
      for (let j=0; j<letterArr.length; j++) {
        if (letterArr[j].audio_url) {
          this._audioResList.push({ url: letterArr[j].audio_url });
        }
      }

    }

    console.log("this._audioResList: ", this._audioResList);
  },

  addPreloadAnima() {},

  preload() {
    const preloadArr = this._imageResList
      .concat(this._audioResList)
      .concat(this._animaResList);
    cc.assetManager.loadAny(preloadArr, null, null, (err, data) => {
      this.loadEnd();
      if (window && window["air"]) {
        window["air"].hideAirClassLoading();
      }
      cc.debug.setDisplayStats(false);
    });
  },

  loadEnd() {
    this.initData();
    this.initAudioEffect();
    this.initView();
    this.initListener();

    console.log("version: ET_07");

    // this.showLetterAnimation();
    // this.startEditMode();
  },

  letterPosList: null,
  curGroupIndex: null,

  curPointArr: null,
  pointGroup: null,
  letterData: null,
  checkTouchLen: null,
  dotWidth: null,
  traceWidth: null,

  dotColor: null,
  foodDisMin: null,
  arrowDisMin: null,

  curGroupDataIndex: null,
  curLetterDataIndex: null,
  initData() {

    this.checkTouchLen = 50;

    this.dotWidth = 5;
    this.traceWidth = 49;

    this.debugMode = false;

    this.curGroupIndex = 0;

    this.curPointArr = [];
    this.pointGroup = [{pointArr: this.curPointArr}];

    this.dotColor = '#fd9c7c';
    this.foodDisMin = 15;
    this.arrowDisMin = 7;


    this.curGroupDataIndex = 0;
    this.curLetterDataIndex = 0;

    // console.log("letter_data: " , letter_data);
    this.letterData = JSON.parse(JSON.stringify(letter_data));
  },

 
	finish: null,
	rightClip: null,
	appearClip: null,
	btnClip: null,
	changeClip: null,
	monsterClip: null,
	writeClip: null,
	starCountClip: null,
	bigStarClip: null,
	initAudioEffect() {
	
		this.finishClip = cc.find('Canvas/res/audio/finish').getComponent(cc.AudioSource).clip;
		this.rightClip = cc.find('Canvas/res/audio/right').getComponent(cc.AudioSource).clip;
		this.appearClip = cc.find('Canvas/res/audio/appear').getComponent(cc.AudioSource).clip;
		this.btnClip = cc.find('Canvas/res/audio/btn').getComponent(cc.AudioSource).clip;
		this.changeClip = cc.find('Canvas/res/audio/change').getComponent(cc.AudioSource).clip;
		this.monsterClip = cc.find('Canvas/res/audio/monster').getComponent(cc.AudioSource).clip;
		this.writeClip = cc.find('Canvas/res/audio/write').getComponent(cc.AudioSource).clip;
		this.starCountClip = cc.find('Canvas/res/audio/star_count').getComponent(cc.AudioSource).clip;
		this.bigStarClip = cc.find('Canvas/res/audio/big_star').getComponent(cc.AudioSource).clip;
		
    this.initLetterAudio();
	},

  letterAudioData: null,
  initLetterAudio() {
    const arr = [
      'A',
      'B', 
      'C', 
      'D',
      'E',
      'F', 
      'G', 
      'H',
      'I',
      'J',
      'K',
      'L',
      'M',
      'N',
      'O',
      'P',
      'Q',
      'R',
      'S',
      'T',
      'U',
      'V',
      'W',
      'X',
      'Y',
      'Z',
    ];

    const letterAudioData = {};
    for (let i=0; i<arr.length; i++) {
      letterAudioData[arr[i]] = cc.find('Canvas/res/audio/letter/big/' + arr[i]).getComponent(cc.AudioSource).clip;
    }
    this.letterAudioData = letterAudioData;
    // console.log('letterAudioData: ', letterAudioData);
  },


  initListener() {
    console.log("initListener");

  
    const btnBack = cc.find("Canvas/EditModeNode/BtnBack");
    btnBack.on("click", () => {
      this.cleanCurPoint();
    });
    const btnNext = cc.find("Canvas/EditModeNode/BtnNext");
    btnNext.on("click", () => {
      this.addNextPointArr();
    });

    const btnShow = cc.find("Canvas/EditModeNode/BtnShow");
    btnShow.on("click", () => {
      this.showTraceAnim();
    });

    const btnSave = cc.find("Canvas/EditModeNode/BtnSave");
    btnSave.on("click", () => {
      this.savePointGroup();
    });

    const btnTrace = cc.find("Canvas/EditModeNode/BtnTrace");
    btnTrace.on("click", () => {
      this.setDebugTraceMode();
    });
  },

  debugMode: false,
  letter: null,
  initView() {

    this.initBg();

    this.initBtn();

    this.initStar();

    console.log('this.data: ' , this.data);
    
    this.curLetterData = this.getCurLetterData();
    // this.setLetter(this.curLetterData.letter);
    this.setLetter('iw');

    this.startEditMode();
  },

  bgManager: null,
  panel: null,
  bgLayer: null,
  initBg() {
    if (!this.bgManager) {
      this.bgManager = new BgManager();
      this.bgManager.setContext({
        bgWidth: this.canvas.width,
        bgHeight: this.canvas.height,
        mapScaleMin: this._mapScaleMin,
        mapScaleMax: this._mapScaleMax,
      });
    }
  

    const bgLayer = new cc.Node();
    this.bgLayer = bgLayer;
    this.canvas.addChild(bgLayer);

    this.addBgEdge(bgLayer);

    this.bgLayer = bgLayer;

    const bg = this.bgManager.getNext();
    bgLayer.addChild(bg);

    const panel = getSprNode('panel');
    panel.scale = this._mapScaleMin;
    panel.y = 15 * this._mapScaleMin;
    this.bgLayer.addChild(panel);
    if (this.debugMode) {
      panel.active = false;
    }
    this.panel = panel;
  },

  addBgEdge(bgLayer) {

    // const node = new cc.Node();
    // node.addComponent(cc.Graphics);
  },

  playBtn: null,
  replayBtn: null,
  initBtn() {
    const play = getSprNode("btn_letsplay");
    play.x = - 350 * this._mapScaleMin;
    play.y = - 280 * this._mapScaleMin;
    this.canvas.addChild(play, 5);
    this.playBtn = play;

    const replay = getSprNode("btn_replay");
    replay.x = 370 * this._mapScaleMin;
    replay.y = play.y;
    this.canvas.addChild(replay, 5);
    this.replayBtn = replay;

    play.active = false;
    replay.active = false;

    play.on(cc.Node.EventType.TOUCH_START, () => {

      playAudio(this.btnClip);

      if (this.data.batch == 'all') {
        this.startTraceAllLetter();
      } else {
        this.startTrace();
      }
  
      this.hideBtn();
    })


    replay.on(cc.Node.EventType.TOUCH_START, () => {

      if (this.data.batch == 'all') {
        this.removeAllLetterNode();
        this.replayAllLetterAnim();
      } else {
        this.cleanLetterAnim();
        this.showLetterAnimByNodeArr();
      }

      this.hideBtn();
      playAudio(this.btnClip);

    })

    

  },

  replayAllLetterAnim() {

    this.isGameEnd = false;
    this.curGroupDataIndex = 0;
    this.curLetterDataIndex = 0;

    this.curLetterData = this.getCurLetterData();
    this.setLetter(this.curLetterData.letter)

  },


  cleanLetterAnim() {

    for (let i=0; i<this.letterNodeArr.length; i++) {
      this.dotReset(this.letterNodeArr[i].pointGroup);
    }
  },

  initStar() {
    console.log(' in initStar');
    // console.log(' in initStar, this.data.groupArr.length: ', this.data.groupArr.length);
    const starNode = cc.find("Canvas/starNode");
    starNode.zIndex = 20;
    const script = starNode.getComponent("star");
    script.bgHeight = this.canvas.height;
    script.count = this.data.groupArr.length;

    console.log(' in initStar end');
  },

  addStar() {
    if (!this.traceMode) {
      return;
    }
    const starNode = cc.find("Canvas/starNode");
    const script = starNode.getComponent("star");
    script.add();
    
  },

  letterNodeArr: null,
  setLetter(letter, delayTime=0, isShowAnim=true) {
    // this.letter = letter;

    this.dotColor = '#fd9c7c';

    if (letter.length == 2) {



      const letter1 = this.addLetterItem(letter[0], -1);
      const letter2 = this.addLetterItem(letter[1], 1);
      
      this.letterNodeArr = [letter1, letter2];

      this.refreshLetterPos();
      
    } else {
      const letterNode = this.addLetterItem(letter);
   
      this.letterNodeArr = [letterNode];
    }

    if (isShowAnim) {
      delayCall(delayTime, () => {
        this.showLetterAnimByNodeArr();
      })
    } else {
      playAudio(this.appearClip);
    }
  

  },

  refreshLetterPos() {
    const arr = this.letterNodeArr;
    let totalW = 0;
    for (let i=0; i<arr.length; i++) {
      totalW += arr[i].emptyNode.width;
    }
    totalW *= this._mapScaleMin;

    let baseX = -totalW / 2;
    for (let i=0; i<arr.length; i++) {
      arr[i].emptyNode.x = baseX + arr[i].emptyNode.width * arr[i].emptyNode.scale / 2;
      arr[i].x = arr[i].emptyNode.x + arr[i].subX;
      baseX += arr[i].emptyNode.width * arr[i].emptyNode.scale;
    }
  },

  async showLetterAnimByNodeArr() {
    if (this.debugMode) {
     return;
    }


    const showOne = async (letterNode) => {
      
      return new Promise((resolve, reject) => {
        try {
          this.showOneLetterAnim(letterNode.letter, letterNode, () => {
            resolve();
          });
        } catch (error) {
          reject(error);
        }
      })
    
    }

   
    for (let i=0; i<this.letterNodeArr.length; i++) {
      await showOne(this.letterNodeArr[i]);
    }

    if (this.data.batch == 'all') {
      this.showNextLetterAnim();
    } else {
      this.showBtn();
    }

  },

  showNextLetterAnim() {


    this.curLetterDataIndex ++;
    this.curLetterData = this.getCurLetterData();
    if (this.curLetterData) {
      this.removeAllLetterNode();
      this.setLetter(this.curLetterData.letter, 1);
      playAudio(this.appearClip);
      // this.showChangeLayerAnim();
    } else {
      this.showBtn();
    }
  },

  removeAllLetterNode() {
    for (let i=0; i<this.letterNodeArr.length; i++) {
      this.letterNodeArr[i].removeFromParent();
      this.letterNodeArr[i].emptyNode.removeFromParent();
    }
  },

  showBtn() {

    this.playBtn.active = true;
    this.replayBtn.active = true;

    this.playBtn.opacity = 0;
    cc.tween(this.playBtn)
      .to(0.2, {opacity: 255}, {easing: "sineOut"})
      .start();

    this.replayBtn.opacity = 0;
    cc.tween(this.replayBtn)
      .to(0.2, {opacity: 255}, {easing: "sineOut"})
      .start();
  },

  hideBtn() {

    this.playBtn.active = false;
    this.replayBtn.active = false;
  },

  curLetterNode: null,
  isBigLetter: null,
  isTouch: null,
  addLetterItem(letter, offX = 0) {

    const tmpOffY = {
      "c": 4,
      "e": 5,
      "f": 1,
      "g": -1.8,
      "h": 4,
      "i": 2,
      "j": 5.6,
      "k": 2,
      "l": 3,
      "m": 2.5,
      "n": 2,
      "o": 3.5,
      "p": 1,
      "q": 1,
      "r": 3,
      "s": 1.2,
      "t": 2,
      "u": 2.5,
      "v": 2,
      "w": 1.5,
      "x": 1.6,
      "y": -4,
      "z": 2.2,

      "B": -1.8,
      "C": -1,
      "D": -1.5,
      "E": -0.7,
      "F": -1,
      "G": -2.5,
      "I": -4.7,
      "J": -1.6,
      "K": -1,
      "L": -0.5,
      "M": -1.5,
      "O": -0.9,
      "P": -2,
      "Q": -1,
      "R": -6,
      "S": -1,
      "T": -3,
      "V": -1,
      "Z": -2,
    }

    const tmpOffX = {
      "a": 1,
      "d": 1,
      "e": 0.8,
      "p": 1,
      "q": 0.5,
      "r": 0.5,
      "s": 1,
      "u": 1,
      "v": 2,
      "x": 0.5,
      "y": -2,
      "z": 1,

      "A": -0.5,
      "E": 0.5,
      "F": 1,
      "G": 1,
      "H": -1,
      "M": 1,
      "N": 1,
      "O": 1.2,
      "P": 1,
      "R": 4,
      "S": -0.5,
      "W": -1,
      "X": -0.2,
    }

    // this.letter = letter = 'R';
    

    let key = letter;
    let subY = (tmpOffY[letter] || 0) * this._mapScaleMin;
    let subX = (tmpOffX[letter] || 0) * this._mapScaleMin;
    if (/[a-z]/.test(letter)) {
      this.isBigLetter = false;
      key += '2';
      subY += -12 * this._mapScaleMin;
    } else {
      this.isBigLetter = true;
      key = letter.toLowerCase();
    }

    const tmpNode = getSprNode('letter/' + key);
    const letterNode = new cc.Node();
    letterNode.width = 639;
    letterNode.height = 594;
    letterNode.scale = this._mapScaleMin;
    letterNode.letter = letter;
    letterNode.zIndex = 1;
    this.bgLayer.addChild(letterNode);

    this.addMaskNode(letterNode, 'letter/' + key)


    letterNode.scale *= 75 / 90;
    letterNode.y = 5 * this._mapScaleMin;
    const emptyNode = this.addEmptyNode('letter_empty/' + key);
    letterNode.emptyNode = emptyNode;

    offX *= emptyNode.width / 2 ;
    emptyNode.x = offX;

    // if (!this.traceMode) {

    // }
  
    letterNode.y += subY;
    letterNode.x += subX + offX;
    letterNode.subX = subX;

    // this.curLetterNode = letterNode;

    letterNode.on(cc.Node.EventType.TOUCH_START, (e) => {
      if (!this.traceMode) {
        return;
      }

      if (letterNode.isTraceEnd) {
        return;
      }

      if (!this.curLetterNode) {

        // console.log('~~~curletterNode: ', letterNode);
        if (this.debugMode) {
          this.curLetterNode = letterNode;
        }

       

        // return;
      }

      if (this.curLetterNode != letterNode && !this.debugMode) {
        return;
      }



      console.log('touch start');
      this.letterTouchDown(letterNode, e);

    })

    letterNode.on(cc.Node.EventType.TOUCH_MOVE, (e) => {

      if (!this.traceMode) {
        return;
      }

      if (!this.curLetterNode) {
        return;
      }

      if (this.curLetterNode != letterNode && !this.debugMode) {
        return;
      }
      this.letterTouchMove(letterNode, e);

    })

    letterNode.on(cc.Node.EventType.TOUCH_END, (e) => {
      if (!this.traceMode) {
        return;
      }

      if (!this.curLetterNode) {
        return;
      }

      if (this.curLetterNode != letterNode && !this.debugMode) {
        return;
      }
      this.letterTouchEnd(letterNode, e);

    })

    letterNode.on(cc.Node.EventType.TOUCH_CANCEL, (e) => {
      if (!this.traceMode) {
        return;
      }

      if (!this.curLetterNode) {
        return;
      }

      if (this.curLetterNode != letterNode && !this.debugMode) {
        return;
      }
      this.letterTouchEnd(letterNode, e);

    })

    return letterNode;
  },

  cleanOtherLetter() {
    for (let i=0; i<this.letterNodeArr.length; i++) {
      if (this.letterNodeArr[i] != this.curLetterNode && !this.letterNodeArr[i].isTraceEnd) {
        this.removeDecorate(this.letterNodeArr[i]);
      }
    }
  },


  addDecorate(letterNode = null) {

    if (this.debugMode) {
      return;
    }

    this.removeDecorate(letterNode);

    if (!letterNode) {
      letterNode = this.curLetterNode;
    }
    const node = letterNode;
    const decorateNode = new cc.Node();
    node.addChild(decorateNode);
    node.decorateNode = decorateNode;
    decorateNode.letterNode = node;

 
    this.addArrow(decorateNode);
    this.addFood(decorateNode);

    node.monster = this.addMonster(decorateNode);

  },

  removeDecorate(node=null) {

    if (!node) {
      node = this.curLetterNode;
    }

    if (node.decorateNode) {
      node.decorateNode.removeFromParent();
      node.decorateNode = null;
    }
  },


  curMonster: null,
  addMonster(decorateNode) {

    let subName = '_1';
    if (!this.isBigLetter) {
      subName = '_2'
    }
    const monster = getSprNode('monster' + subName);
    monster.anchorY = 0.4;
    decorateNode.addChild(monster);
    this.curMonster = monster;

    const letterNode = decorateNode.letterNode;
    monster.on(cc.Node.EventType.TOUCH_START, () => {

      if (!this.curLetterNode) {
        this.curLetterNode = letterNode;
        this.curLetterNode.zIndex = 3;
        if (!this.debugMode) {
          this.pointGroup = letterNode.pointGroup;
          this.curTracePointArr = letterNode.curTracePointArr;
          this.curMonster = letterNode.monster;
          this.curTracePointIndex = 0;
          this.curTraceGroupIndex = 0;
          this.isTraceEnd = false;
  
          this.cleanOtherLetter();
        }
      }

      playAudio(this.monsterClip);

    });

    this.refreshMonsterPos(this.curTracePointArr[0])
    return monster;
  },

  foodArr: null,
  addFood(decorateNode) {

    this.foodArr = [];

    let subName = '_1';
    if (!this.isBigLetter) {
      subName = '_2'
    }

    const foodPosArr = this.getFoodPosArr();
    foodPosArr.shift();
    for (let i=0; i<foodPosArr.length; i++) {
      const food = getSprNode('food' + subName);
      food.x = foodPosArr[i].x;
      food.y = foodPosArr[i].y;
      foodPosArr[i].food = food;
      decorateNode.addChild(food)
      this.foodArr.push(food);
    }
  },


  addArrow(decorateNode) {

    const arrowPosArr = this.getArrowPosArr();

    arrowPosArr.shift();
    arrowPosArr.pop()

    for (let i=0; i<arrowPosArr.length; i++) {
      const arrow = getSprNode('arrow');
      arrow.x = arrowPosArr[i].x;
      arrow.y = arrowPosArr[i].y;
      arrow.angle = arrowPosArr[i].arrowAngle;
      decorateNode.addChild(arrow)

      arrow.opacity = 0;

      delayCall(i * 0.2, () => {
        this.addArrowAnim(arrow);
      })
    }
  },

  addArrowAnim(arrow, index) {
    cc.tween(arrow)
      .to(0.5, {opacity: 255}, {easing: "sineOut"})
      .delay(0.5)
      .to(0.5, {opacity: 0}, {easing: "sineIn"})
      .delay(2)

      .union()
      .repeatForever()
      .start();
    
  },

  getArrowPosArr() {
    const arr = this.curTracePointArr;
    
    if (arr.length < 10) {
      return [];
    }

    const firstPos = arr[0];
    const lastPos = arr[arr.length - 1];

    const arrowPosArr = [firstPos, lastPos];
    this.checkAddArrowPos(firstPos, lastPos, arrowPosArr);

    return arrowPosArr;
  },

  checkAddArrowPos(startPos, endPos, arrowPosArr) {
    const startIndex = this.curTracePointArr.indexOf(startPos);
    const endIndex = this.curTracePointArr.indexOf(endPos);

    if (endIndex - startIndex > this.arrowDisMin * 2) {

      const centerPosIndex = endIndex - Math.ceil((endIndex - startIndex) / 2);
      const centerPos = this.curTracePointArr[centerPosIndex];

      const endArrowIndex = arrowPosArr.indexOf(endPos);
      arrowPosArr.splice(endArrowIndex, 0, centerPos);

      const tmpPos1 = this.curTracePointArr[centerPosIndex - 1] || centerPosIndex;
      const tmpPos2 = this.curTracePointArr[centerPosIndex + 1] || centerPosIndex;
  
      centerPos.arrowAngle = getAngleByPos(tmpPos1.x, tmpPos1.y, tmpPos2.x, tmpPos2.y);

      this.checkAddArrowPos(startPos, centerPos, arrowPosArr);
      this.checkAddArrowPos(centerPos, endPos, arrowPosArr);
    }
  },


  getFoodPosArr() {
    const arr = this.curTracePointArr;

    const firstPos = arr[0];
    const lastPos = arr[arr.length - 1];


    const foodPosArr = [firstPos];
    if (arr.length < 10) {
      return foodPosArr
    }

    foodPosArr.push(lastPos);

    this.checkAddCenterFoodPos(firstPos, lastPos, foodPosArr)

    // console.log('foodPosArr: ', foodPosArr);
    return foodPosArr;

  },

  checkAddCenterFoodPos(startPos, endPos, foodPosArr) {
    const startIndex = this.curTracePointArr.indexOf(startPos);
    const endIndex = this.curTracePointArr.indexOf(endPos);
    if (endIndex - startIndex > this.foodDisMin * 2) {
      // const centerPosIndex = endIndex - this.foodDisMin;
      const centerPosIndex = endIndex - Math.ceil((endIndex - startIndex) / 2);
      const centerPos = this.curTracePointArr[centerPosIndex];

      const endFoodIndex = foodPosArr.indexOf(endPos);
      foodPosArr.splice(endFoodIndex, 0, centerPos);

      this.checkAddCenterFoodPos(startPos, centerPos, foodPosArr);
      this.checkAddCenterFoodPos(centerPos, endPos, foodPosArr);

      // const startFoodIndex = foodPosArr.indexOf(startPos);


    }
  },


  letterTouchDown(letterNode, e) {

    this.isTouch = true;

    const pos = e.getLocation();
    let px = pos.x - letterNode.x - this.canvas.width / 2;
    let py = pos.y - letterNode.y - this.canvas.height / 2;
    px /= letterNode.scale;
    py /= letterNode.scale;

    
    if (this.debugMode) {
      this.addTracePoint(px, py);
      return;
    }

    if (this.traceMode) {
      this.checkTouchPoint(px, py)
      return;
    }
 
  },

  letterTouchMove(letterNode, e) {

    // console.log('this.isTouch: ',this.isTouch);
    if (!this.isTouch) {
      return;
    }

    if (this.debugMode) {
      return;
    }


    const pos = e.getLocation();
    let px = pos.x - letterNode.x - this.canvas.width / 2;
    let py = pos.y - letterNode.y - this.canvas.height / 2;
    px /= letterNode.scale;
    py /= letterNode.scale;

    if (this.traceMode) {
      this.checkTouchPoint(px, py)
    }

    // playAudio(this.writeClip);
  },

  letterTouchEnd(letterNode, e) {

    if (!this.isTouch) {
      return;
    }

    if (this.debugMode) {
      return;
    }

    const pos = e.getLocation();
    let px = pos.x - letterNode.x - this.canvas.width / 2;
    let py = pos.y - letterNode.y - this.canvas.height / 2;
    px /= letterNode.scale;
    py /= letterNode.scale;

    if (this.traceMode) {
      this.checkTouchLastDot();
    }
  },


  traceStartDot: null,
  addTracePoint(px, py) {

    // console.log(' in addTracePoint ')
    const dot = this.drawDot(this.dotWidth);
    dot.x = px;
    dot.y = py;
    this.curLetterNode.maskNode.addChild(dot);

    if (!this.traceStartDot) {
      this.traceStartDot = dot;
    } else {
      this.autoCreateTraceP(this.traceStartDot, dot);
      this.traceStartDot = dot;
    }

  },

  autoCreateTraceP(startDot, endDot) {
    const minLen = 10;

    this.addCurPoint(startDot);
    
    let angle = getAngleByPos(startDot.x, startDot.y, endDot.x, endDot.y);
    let totalLen = Math.sqrt( Math.pow(startDot.x - endDot.x, 2) + Math.pow(startDot.y - endDot.y, 2))
    let curLen = minLen;
    while (totalLen > curLen) {

      const pos = getPosByAngle(angle, curLen);

      const dot = this.drawDot(this.dotWidth);
      dot.x = startDot.x + pos.x;
      dot.y = startDot.y - pos.y;
      this.curLetterNode.maskNode.addChild(dot);

      this.addCurPoint(dot);


      curLen += minLen;
    }

    this.addCurPoint(endDot);

  },

  addCurPoint(dot) {
    this.curPointArr.push(dot);
  },

  cleanCurPoint() {
    const pointArr = this.curPointArr;
    for (let i=0; i<pointArr.length; i++) {
      pointArr[i].removeFromParent();
    }
    pointArr.length = 0;
    this.traceStartDot = null;
  },

  addNextPointArr() {

    const curPointArr = [];
    this.curPointArr = [] // curPointArr;
    // this.pointGroup.push(curPointArr);
    this.pointGroup.push({pointArr: this.curPointArr});

    this.traceStartDot = null;
  },

  async showTraceAnim() {

    if (this.pointGroup.length == 1 && this.curPointArr.length == 0) {
      this.setDataToGroup();
    }

    this.dotReset(this.pointGroup);

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

      const pointArr = this.pointGroup[i].pointArr;


      for (let j=0; j<pointArr.length; j++) {
        const dot = pointArr[j];
        dot.active = true; 
        // dot.scale = 92 / 10;
        const ctx = dot.getComponent(cc.Graphics);
        ctx.circle(0, 0, this.traceWidth);
        ctx.fill();

        await asyncDelay(0.02);
      }
    }
  },
  
  setDataToGroup(letter, letterNode) {
    

    if (!letter) {
      letter = this.letter;
    }
    
    if (letterNode) {
      if (letterNode.pointGroup) {
        this.cleanPointGroup(letterNode.pointGroup);
      }
    } else {
      this.cleanPointGroup();
      return;
    }

    const dataPointGroup = this.letterData[letter];

    this.pointGroup = [];

    // console.log('in setDataToGroup: ', dataPointGroup);
    for (let i=0; i<dataPointGroup.length; i++) {

      const curPointArr = [];
      const targetPointArr = dataPointGroup[i];
      // console.log('targetPointArr: ', targetPointArr);
      for (let j=0; j<targetPointArr.length; j++) {
        const dot = this.drawDot(this.dotWidth);
        dot.x = targetPointArr[j].x;
        dot.y = targetPointArr[j].y;
        letterNode.maskNode.addChild(dot);
        curPointArr.push(dot);
      }

      this.pointGroup.push({pointArr: curPointArr});
      
    }

    letterNode.pointGroup = this.pointGroup
  },

  cleanPointGroup(pointGroup) {

    if (!pointGroup) {
      pointGroup = this.pointGroup;
    }

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

      const pointArr = pointGroup[i].pointArr;
      for (let i=0; i<pointArr.length; i++) {
        pointArr[i].removeFromParent();
      }
    }
  },

  cleanCurGroup() {
    const pointArr = this.pointGroup[this.curTraceGroupIndex].pointArr;
    for (let i=0; i<pointArr.length; i++) {
      pointArr[i].removeFromParent();
    }
  },

  setOneGroup() {

    const dataPointGroup = this.letterData[this.curLetterNode.letter];

    // console.log('in setDataToGroup: ', dataPointGroup);

    const i = this.curTraceGroupIndex;
    const curPointArr = [];
    const targetPointArr = dataPointGroup[i];

    for (let j=0; j<targetPointArr.length; j++) {
      const dot = this.drawDot(this.dotWidth);
      dot.x = targetPointArr[j].x;
      dot.y = targetPointArr[j].y;
      this.curLetterNode.maskNode.addChild(dot);
      curPointArr.push(dot);
    }

    this.pointGroup[i] = {pointArr: curPointArr};
    

  },


  savePointGroup() {

    let tmpPointGroup = [];
    for (let i=0; i<this.pointGroup.length; i++) {

      const tmpPointArr =[];
      const pointArr = this.pointGroup[i].pointArr;

      for (let j=0; j<pointArr.length; j++) {
        const dot = pointArr[j];
        tmpPointArr.push({x: Math.round(dot.x * 100) / 100, y: Math.round(dot.y * 100) / 100})
      }
      tmpPointGroup.push(tmpPointArr);
    }
    

    
    console.log(JSON.stringify(tmpPointGroup));
  },

  dotReset(pointGroup) {

    // console.log('this.pointGroup: ', this.pointGroup);

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

      const pointArr = pointGroup[i].pointArr;

      for (let j=0; j<pointArr.length; j++) {
        const dot = pointArr[j];
        const ctx = dot.getComponent(cc.Graphics);
        ctx.clear();
      }
    }
  },


  addMaskNode(node, key) {


    const sprNode = getSprNode(key)
    const sf = sprNode.getComponent(cc.Sprite).spriteFrame;

    const maskNode = new cc.Node();
    const mask = maskNode.addComponent(cc.Mask);
    mask.spriteFrame = sf;
    mask.type = cc.Mask.Type.IMAGE_STENCIL;
    node.addChild(maskNode);

    maskNode.width = node.width;
    maskNode.height = node.height;

  
    const bgWhite = this.drawRect(maskNode.width, maskNode.height);
    maskNode.addChild(bgWhite);

    // sprNode.opacity = 220;
    // maskNode.parent.addChild(sprNode, 50)

    node.maskNode = maskNode;
  },


  addEmptyNode(key, tmpX = 0) {

    const sprNode = getSprNode(key)
    sprNode.scale = this._mapScaleMin;
    sprNode.x = tmpX
    // sprNode.opacity = 50;
    this.bgLayer.addChild(sprNode);


    if (this.debugMode) {
      sprNode.active = false;
    }

    
    return sprNode;
  },


  drawDot(r = 50) {
    const dotNode = new cc.Node();
    const ctx = dotNode.addComponent(cc.Graphics);
    const color = new cc.Color();
    color.fromHEX(this.dotColor);
    ctx.fillColor = color;
    ctx.circle(0, 0, r)
    ctx.fill();
    if (!this.debugMode) {
      dotNode.active = false;
    }
    return dotNode;
  },

  drawRect(w, h, color=null) {
    const dotNode = new cc.Node();
    dotNode.opacity = 50;
    const ctx = dotNode.addComponent(cc.Graphics);
    if (!color) {
      color = cc.Color.WHITE;
    }
    ctx.fillColor = color
    ctx.rect(-w/2, -h/2, w, h)
    ctx.fill();
    return dotNode;
  },


  setDebugTraceMode() {
    this.traceMode = !this.traceMode;
    this.isTraceEnd = false;

    this.cleanPointGroup();
    if (this.traceMode) {
      this.dotColor = '#f5e699';
      this.initTraceMode();
      // this.addDecorate();
      this.panel.active = false;

    } else {
      this.dotColor = '#fd9c7c';
      // this.removeDecorate()
      this.panel.active = true;
    }
  },

  traceMode: null,
  setTraceMode() {
    this.traceMode = !this.traceMode;
    this.isTraceEnd = false;

    this.cleanPointGroup();
    if (this.traceMode) {
      this.dotColor = '#f5e699';
      this.initTraceMode();
      this.addDecorate();
      this.panel.active = false;

    } else {
      this.dotColor = '#fd9c7c';
      this.removeDecorate()
      this.panel.active = true;
    }
  },

  curTracePointIndex: null,
  curTraceGroupIndex: null,
  curTracePointArr: null,
  initTraceMode() {

    this.setDataToGroup();
    

    this.curTracePointIndex = 0;
    this.curTraceGroupIndex = 0;
    this.curTracePointArr = this.pointGroup[0].pointArr;
  },


  checkTouchPoint(px, py) {
    
    if (this.isTraceEnd) {
      return;
    }

    const targetP = this.getCurCheckPoint();

    let p1 = cc.v2(px, py)
    let p2 = cc.v2(targetP.x, targetP.y);
    let distance = p1.sub(p2).mag();


    // console.log('distance: ', distance);


    if (distance < this.checkTouchLen) {
      this.touchedDot(targetP);

      this.checkTouchPoint(px, py);
    }
  },

  getCurCheckPoint() {

    const group = this.pointGroup[this.curTraceGroupIndex];
    const point = group.pointArr[this.curTracePointIndex];
    return point;
  },

  touchedDot(dot) {
    const ctx = dot.getComponent(cc.Graphics);
    ctx.clear();
    ctx.circle(0, 0, this.traceWidth);
    ctx.fill();
    dot.active = true;

    this.curTracePointIndex ++;

    if (!this.curTracePointArr[this.curTracePointIndex]) {
      // this.changeNewTraceGroup();
      this.traceEnd();
    }

    this.refreshMonsterPos(dot);
    this.checkTouchFood(dot);

      
    if (this.isTraceEnd) {
      this.traceSuccess();
    }
  },

  checkTouchFood(dot) {
    if (dot.food) {
      this.showTouchFoodAnim(dot.food);
    }
  },

  showTouchFoodAnim(food) {
    food.active = false;
    this.showDragSuccessAnim()
  },

  refreshMonsterPos(dot) {
    this.curMonster.x = dot.x;
    this.curMonster.y = dot.y;
  },

  changeNewTraceGroup() {
    this.curTraceGroupIndex ++;
    this.curTracePointIndex = 0;
    this.curTracePointArr = this.pointGroup[this.curTraceGroupIndex]?.pointArr;
    if (!this.curTracePointArr) {
      this.traceEnd();
    }

  },

  isTraceEnd: null,
  traceEnd() {
    this.isTraceEnd = true;
    console.log(' trace end ;')
  },

  checkTouchLastDot() {

    // console.log(' in checkTouchLastDot')

    if (!this.isTraceEnd) {
      this.traceFail();
    }
    
  },

  traceFail() {

    console.log(' in traceFail')

    this.cleanCurGroup();
    this.setOneGroup();


    this.curTracePointIndex = 0;
    this.curTracePointArr = this.pointGroup[this.curTraceGroupIndex].pointArr;
    

    // this.cleanPointGroup();

    // this.initTraceMode();
    this.addDecorate();


  },

  traceSuccess() {

    this.isTraceEnd = false;
    this.isTouch = false;
    
    this.curTraceGroupIndex ++;
    this.curTracePointIndex = 0;
    this.curTracePointArr = this.pointGroup[this.curTraceGroupIndex]?.pointArr;
    if (!this.curTracePointArr) {
      this.letterTraceEnd();
    } else {
      this.addDecorate();
    }
  },



  async showOneLetterAnim(letter, letterNode, cb=null) {

    
    this.setDataToGroup(letter, letterNode);

    this.dotReset(letterNode.pointGroup);

    const pointGroup = letterNode.pointGroup;

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

      const pointArr = pointGroup[i].pointArr;
      playAudio(this.writeClip);

      for (let j=0; j<pointArr.length; j++) {
        const dot = pointArr[j];
        dot.active = true; 
        // dot.scale = 92 / 10;
        const ctx = dot.getComponent(cc.Graphics);
        ctx.circle(0, 0, this.traceWidth);
        ctx.fill();

        await asyncDelay(0.015);
      }

    }

    if (cb) {
      cb()
    }
    
  },

  startTraceAllLetter() {

    this.removeAllLetterNode();

    this.isGameEnd = false;
    this.curGroupDataIndex = 0;
    this.curLetterDataIndex = 0;

    this.curLetterData = this.getCurLetterData();
    this.setLetter(this.curLetterData.letter, 0, false)

    this.traceMode = true;
    this.isTraceEnd = false;
    this.dotColor = '#f5e699';
    this.panel.active = false;


    this.initAllTrace();
    this.addAllDecorate();


  },
 
  startTrace() {

    this.traceMode = true;
    this.isTraceEnd = false;
    this.dotColor = '#f5e699';
    this.panel.active = false;

    this.initAllTrace();

    this.addAllDecorate();

  },

  initAllTrace() {
    for (let i=0; i<this.letterNodeArr.length; i++) {
      const letterNode = this.letterNodeArr[i];
      this.setDataToGroup(letterNode.letter, letterNode);

      letterNode.scale = this._mapScaleMin;
      letterNode.emptyNode.active = false;
      // if (letterNode.x != 0) {
      //   if (letterNode.x > 0) {
      //     letterNode.x = letterNode.width / 2 * letterNode.scale;
      //   } else {
      //     letterNode.x = -letterNode.width / 2 * letterNode.scale;
      //   }
      // }
   
      letterNode.x *= 90 / 75;

      letterNode.curTracePointIndex = 0;
      letterNode.curTraceGroupIndex = 0;
      letterNode.curTracePointArr = letterNode.pointGroup[0].pointArr;
    }


    this.curTracePointIndex = 0;
    this.curTraceGroupIndex = 0;
    this.curTracePointArr = [];
  },

  addAllDecorate() {
    if (this.debugMode) {
      return;
    }

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

      const letterNode = this.letterNodeArr[i];
      if (!letterNode.isTraceEnd) {
        this.removeDecorate(letterNode);

        const decorateNode = new cc.Node();
        letterNode.addChild(decorateNode);
        letterNode.decorateNode = decorateNode;
        decorateNode.letterNode = letterNode;
  
        this.curTracePointArr = letterNode.curTracePointArr;
  
        this.addArrow(decorateNode);
        this.addFood(decorateNode);
  
        letterNode.monster = this.addMonster(decorateNode);
      }
     
    }


  },

  letterTraceEnd() {
    this.traceEnd();

    this.curLetterNode.isTraceEnd = true;
    this.curLetterNode.zIndex = 0;

    this.removeDecorate(this.curLetterNode);
    this.curLetterNode = null;
    

    for (let i=0; i<this.letterNodeArr.length; i++) {
      if (!this.letterNodeArr[i].isTraceEnd) {
        this.addAllDecorate();
        return;
      }
    }


    if (this.data.batch == 'all') {
      this.setNextLetterNotAnim();
    } else {
      this.changeNextLetter();
    }


    console.log(' in letterTraceEnd');
  },


  setNextLetterNotAnim() {


    this.curLetterDataIndex ++;
    this.curLetterData = this.getCurLetterData();
    if (this.curLetterData) {

      this.removeAllLetterNode();
      
      this.setLetter(this.curLetterData.letter, 0, false);
      
      this.isTraceEnd = false;
      this.dotColor = '#f5e699';
      this.panel.active = false;
  
      this.initAllTrace();
      this.addAllDecorate();
    }
  
  },
  
  oldBgLayer: null,
  changeNextLetter() {

    const oldBgLayer = this.bgLayer;
    oldBgLayer.zIndex = 5;
    this.oldBgLayer = oldBgLayer;


    this.initNewLetter();

  },

  showChangeLayerAnim() {

    cc.tween(this.oldBgLayer)
      .to(1.2, {y: this.canvas.height}, {easing:"cubicIn"})
      .call(() => {
        this.oldBgLayer.removeFromParent();
      })
      .start();

      playAudio(this.changeClip);
  },

  curLetterData: null,
  initNewLetter() {

    
    this.initBg();

    this.curLetterDataIndex ++;
    this.curLetterData = this.getCurLetterData();
    if (this.curLetterData) {
      this.traceMode = false;

      this.setLetter(this.curLetterData.letter, 2);
      this.showChangeLayerAnim();
    }
  
  },

  getCurLetterData() {
    if (this.isGameEnd) {
      return;
    }

    const group = this.data.groupArr[this.curGroupDataIndex];
    const letterData = group.letterArr[this.curLetterDataIndex];

    if (!letterData) {
      this.curGroupDataIndex ++;
      this.curLetterDataIndex = 0;
      this.checkGameEnd();
      return this.getCurLetterData();
    }
    return letterData;
  },

  checkGameEnd() {
    const group = this.data.groupArr[this.curGroupDataIndex];
    if (!group) {
      this.addStar();
      this.gameEnd();
    } else {
      this.addStar();
    }
  },

  isGameEnd: null,
  gameEnd() {
    this.isGameEnd = true;

    if (this.traceMode) {
      this.showEndAnim();
    }
  },

  async showEndAnim() {

    await asyncDelay(0.5);

		const camera = cc.find('Canvas/Main Camera');
		camera.zIndex = 100;

		showTrebleFirework(camera, cc.find('RibbonNodeBase').children);
    playAudio(this.finishClip);

		onHomeworkFinish();
  },


	showDragSuccessAnim() {

    const worldPos = this.curMonster.parent.convertToWorldSpaceAR(this.curMonster.getPosition());
    const localPos = this.curLetterNode.convertToNodeSpaceAR(worldPos);

		const resDragonBone = cc.find("Canvas/res/anim/right")
		const d = cc.instantiate(resDragonBone)
    d.x = localPos.x;
    d.y = localPos.y;
		this.curLetterNode.addChild(d, 20);

		playAudio(this.rightClip, null, 0.2);

    if (this.curLetterData.audio_url) {
      playAudioByUrl(this.curLetterData.audio_url);

    } else {
      const key = this.curLetterNode.letter.toUpperCase();
      playAudio(this.letterAudioData[key]);
    }
   
	},


  editMode: false,
  startEditMode() {
    if (!this.debugMode) {
      return;
    }
    const node = cc.find("Canvas/EditModeNode");
    node.zIndex = 20;
    node.active = true;
    this.editMode = true;

  },

});
