legacy/outils/scratch/ScratchProg.js

import { j3pClone } from 'src/legacy/core/functions'
import { notify } from 'sesajs/error'

class ScratchProg {
  /**
   * Constructeur du programme
   * @param {Object} Blockly
   * @param {Object} args
   * @param {Array} args.letabeduprog
   * @param {string} args.id
   * @param {boolean} args.isTest
   * @constructor
   */
  constructor (Blockly, { scratch, options = {}, numProgDeTabcodex = 0 }) {
    const { params } = scratch
    this.vite = Boolean(options.vite)
    this.sortie = options.sortie
    this.workspace = options.workspace
    params.leWork = this.workspace
    params.cacheTest = options.cacheTest
    this.cacheTest = options.cacheTest
    params.scratchProgDonnees.workspace = this.workspace
    params.scratchProgDonnees.tabcodeX = options.tabcodeX
    params.scratchProgDonnees.valPourGetUs = j3pClone(options.valGetUs)
    params.scratchProgDonnees.valAleaVerif = options.valAleaVerif

    params.scratchProgDonnees.yaErreurMtg = undefined
    params.scratchProgDonnees.nomsAleaChar = ['¶', '©', '®', '™', '♠', '♣', '♥', '♦', '↑', '↓', '↔']
    params.scratchProgDonnees.nomsAlea = []
    params.scratchProgDonnees.nomsAleaChar.forEach(element => {
      params.scratchProgDonnees.nomsAlea.push(element, element + "'", element + '"')
      for (let i = 0; i < 10; i++) {
        params.scratchProgDonnees.nomsAlea.push(element + i, element + i + "'", element + i + '"')
      }
    })
    params.scratchProgDonnees.nomsAleaBase = j3pClone(params.scratchProgDonnees.nomsAlea)
    const objet = this
    if (scratch.pasapas) {
      objet.ModePasapas = scratch.pasapas.checked
      scratch.pasapas.disabled = true
    }
    params.scratchProgDonnees.blokinput = false
    params.scratchProgDonnees.x = ''
    params.scratchProgDonnees.y = ''
    params.scratchProgDonnees.z = ''
    params.scratchProgDonnees.valGetDon = []
    this.tab = scratch.copieDe(options.tabcodeX[numProgDeTabcodex])

    // console.debug('tabcodeX', params.scratchProgDonnees.tabcodeX)
    // console.debug('xmlwork', scratch.Blockly.Xml.workspaceToDom(params.scratchProgDonnees.workspace).innerHTML)

    if (!params.modeCompare) scratch.traceSortieBase({ sortie: this.sortie })
    scratch.remiseAzero()

    params.toSouvSuite = []
    scratch.remplaceMake(this.tab)

    this.where = 0
    this.chrono = null
    this.dansquoi = [{ type: 'main', where: 0 }]
    this.before = ''
    params.scratchProgDonnees.yaEuVerif = false

    params.valAlea = j3pClone(options.valAlea)
    params.scratchProgDonnees.reponse = 'NaN'
    params.scratchProgDonnees.Valeursutilisees = []
    params.scratchProgDonnees.resetflag = true

    this.k = []
    this.memstack = ''

    function scratchFoncBoutSuiv () {
      if (params.scratchProgDonnees.pause) {
        setTimeout(() => {
          scratchFoncBoutSuiv()
        }, 500)
      } else {
        params.BoutPasSuiv.push(objet.exeaction)
        scratch.bouAaPaPa.classList.add('bouturg')
        scratch.lesdivs.PASAPASBOOT.style.display = ''
      }
    }
    this.elembywhere = function (el) {
      while (objet.dansquoi.length > objet.comcompte + 1) {
        if (objet.dansquoi[objet.comcompte + 1].type === 'boucle') {
          el = scratch.copieDe(el[objet.dansquoi[objet.comcompte + 1].where].boucle)
        }
        if (objet.dansquoi[objet.comcompte + 1].type === 'boucleF') {
          el = scratch.copieDe(el[objet.dansquoi[objet.comcompte + 1].where].boucle)
        }
        if (objet.dansquoi[objet.comcompte + 1].type === 'boucleU') {
          el = scratch.copieDe(el[objet.dansquoi[objet.comcompte + 1].where].boucle)
        }
        if (objet.dansquoi[objet.comcompte + 1].type === 'sioui') {
          el = scratch.copieDe(el[objet.dansquoi[objet.comcompte + 1].where].sioui)
        }
        if (objet.dansquoi[objet.comcompte + 1].type === 'sinon') {
          el = scratch.copieDe(el[objet.dansquoi[objet.comcompte + 1].where].sinon)
        }
        objet.comcompte++
      }
      return el[objet.where]
    }
    this.trouveprochainordre = function () {
      function execute (unelem) {
        try {
          if (objet.memstack) {
            objet.workspace.glowBlock(objet.memstack, false)
          }
          if (unelem) {
            objet.workspace.glowBlock(unelem.id, true)
            objet.memstack = unelem.id
          }
        } catch (error) {
          // eslint-disable-next-line no-console
          console.log(error)
        }
        if (!unelem) return { result: 'fin' }
        if (unelem.type === 'Mb') return { result: 'Mb', name: unelem.nom }
        if (unelem.type === 'event') return { result: 'event' }
        if (unelem.type === 'boucle') return { result: 'boucle' }
        if (unelem.type === 'boucleF') return { result: 'boucleF' }
        if (unelem.type === 'boucleU') return { result: 'boucleU' }
        if (unelem.type === 'control_stop') return { result: 'control_stop' }
        if (unelem.type === 'si') return { result: 'si' }
        if (unelem.type === 'setValPerso') {
          params.scratchProgDonnees.x = unelem.valX
          params.scratchProgDonnees.y = unelem.valY
          params.scratchProgDonnees.z = unelem.valZ
          return { result: 'setValPerso' }
        }
        return unelem.javascript()
      }
      const elemencours = objet.elembywhere(scratch.copieDe(objet.tab))
      let rep
      this.lecompteur++
      if (params.scratchProgDonnees.yaErreurMtg) {
        rep = { result: 'prob', quoi: params.scratchProgDonnees.yaErreurMtg }
      } else {
        objet.comcompte = 0
        rep = execute(elemencours)
      }
      if (this.lecompteur === 2000) {
        notify('ya + de 2000 Tommy', { prog: objet.tab, result: rep })
        objet.destroy()
        const fflis = scratch.stopTout.bind(scratch)
        fflis()
        scratch.scratchVerifRun(objet.mod)
        return
      }
      if (rep.result === 'ordrew') {
        objet.where++
        params.scratchProgDonnees.pause = true
        if (this.cacheTest || params.cacheTest) params.scratchProgDonnees.pause = false
        return true
      }
      if (rep.result === 'event') {
        objet.where++
        return true
      }
      if (rep.result === 'ordre') {
        objet.where++
        return true
      }
      if (rep.result === 'boucle') {
        let numberName
        try {
          numberName = scratch.vireGuillemets(Blockly.JavaScript.valueToCode(elemencours.repete, 'TIMES', Blockly.JavaScript.ORDER_ATOMIC))
        } catch (e) {
          numberName = ' '
        }
        if (numberName === ' ' || numberName === '' || isNaN(numberName) || Number(numberName) < 0) {
          rep.result = 'prob'
          rep.quoi = 'Je ne parviens pas à<br> comprendre le nombre de répétitions !'
        } else {
          if (!elemencours.boucle) {
            objet.where++
            return { tempo: false, cont: true }
          }
          objet.dansquoi.push({
            type: 'boucle',
            kmax: Number(numberName),
            k: 1,
            itk: 1,
            where: objet.where,
            nom: 'boucle'
          })
          this.k.push(1)
          objet.where = 0
          if (Number(numberName) < 1) {
            objet.k[objet.k.length - 1]++
            if (objet.k[objet.k.length - 1] > objet.dansquoi[objet.dansquoi.length - 1].kmax) {
              objet.where = objet.dansquoi[objet.dansquoi.length - 1].where + 1
              objet.dansquoi.pop()
              objet.k.pop()

              return { tempo: false, cont: true }
            } else {
              objet.where = objet.dansquoi[objet.dansquoi.length - 1].where + 1
              return { tempo: false, cont: true }
            }
          }
          return { tempo: false, cont: true }
        }
      }
      if (rep.result === 'boucleF') {
        if (!elemencours.boucle) {
          params.scratchProgDonnees.avertissements.push('Aucune instruction à répéter !')
          return 'PROB'
        }
        objet.dansquoi.push({
          type: 'boucleF',
          where: objet.where,
          nom: 'boucleF'
        })
        objet.where = 0
        return { tempo: false, cont: true }
      }
      if (rep.result === 'boucleU') {
        if (!elemencours.boucle) {
          params.scratchProgDonnees.avertissements.push('Aucune instruction à répéter !')
          return 'PROB'
        }
        const cond = scratch.vireGuillemets(Blockly.JavaScript.valueToCode(elemencours.repete, 'CONDITION', Blockly.JavaScript.ORDER_ATOMIC))
        if (cond !== 'vrai') {
          objet.dansquoi.push({
            type: 'boucleU',
            where: objet.where,
            nom: 'boucleU',
            id: elemencours.id,
            repete: elemencours.repete,
            workspace: this.workspace
          })
          objet.where = 0
          return { tempo: false, cont: true }
        } else {
          objet.where++
          return { tempo: false, cont: true }
        }
      }
      if (rep.result === 'boucleF') {
        if (!elemencours.boucle) {
          objet.avertissements = ['Aucune instruction à répéter !']
          return 'PROB'
        }
        objet.dansquoi.push({
          type: 'boucleF',
          where: objet.where,
          nom: 'boucleF'
        })
        objet.where = 0
        return { tempo: false, cont: true }
      }
      if (rep.result === 'si') {
        /// faut tester la cond
        let cond
        if (objet.mod !== 'coco') {
          cond = scratch.vireGuillemets(Blockly.JavaScript.valueToCode(this.workspace.getBlockById(elemencours.id), 'CONDITION', Blockly.JavaScript.ORDER_ATOMIC))
        } else { cond = scratch.vireGuillemets(Blockly.JavaScript.valueToCode(params.scratchProgDonnees.workspaceco.getBlockById(elemencours.id), 'CONDITION', Blockly.JavaScript.ORDER_ATOMIC)) }
        if (cond === 'erreur block vide') {
          params.scratchProgDonnees.avertissements.push('Il manque une condition !')
          return 'PROB'
        }
        if (cond === 'vrai') {
          if (!elemencours.sioui) {
            objet.where++
            return { tempo: false, cont: true }
          }
          objet.dansquoi.push({ type: 'sioui', where: objet.where, nom: 'sioui' })
          objet.where = 0
          return { tempo: false, cont: true }
        } else {
          if (!elemencours.sinon) {
            objet.where++
            return { tempo: false, cont: true }
          }
          objet.dansquoi.push({ type: 'sinon', where: objet.where, nom: 'sinon' })
          objet.where = 0
          return { tempo: false, cont: true }
        }
      }
      if (rep.result === 'fin') {
        if (objet.dansquoi[objet.dansquoi.length - 1].type === 'boucle') {
          objet.k[objet.k.length - 1]++
          if (objet.k[objet.k.length - 1] > objet.dansquoi[objet.dansquoi.length - 1].kmax) {
            objet.where = objet.dansquoi[objet.dansquoi.length - 1].where + 1
            objet.dansquoi.pop()
            objet.k.pop()
            return { tempo: false, cont: true }
          } else {
            objet.where = 0
            return { tempo: false, cont: true }
          }
        }
        if (objet.dansquoi[objet.dansquoi.length - 1].type === 'sioui') {
          objet.where = objet.dansquoi[objet.dansquoi.length - 1].where + 1
          objet.dansquoi.pop()
          return { tempo: false, cont: true }
        }
        if (objet.dansquoi[objet.dansquoi.length - 1].type === 'sinon') {
          objet.where = objet.dansquoi[objet.dansquoi.length - 1].where + 1
          objet.dansquoi.pop()
          return { tempo: false, cont: true }
        }
        if (objet.dansquoi[objet.dansquoi.length - 1].type === 'boucleU') {
          const cond = scratch.vireGuillemets(Blockly.JavaScript.valueToCode(objet.dansquoi[objet.dansquoi.length - 1].repete, 'CONDITION', Blockly.JavaScript.ORDER_ATOMIC))
          if (cond !== 'vrai') {
            objet.where = 0
            return { tempo: false, cont: true }
          } else {
            objet.where = objet.dansquoi[objet.dansquoi.length - 1].where + 1
            objet.dansquoi.pop()
            return { tempo: false, cont: true }
          }
        }
        if (objet.dansquoi[objet.dansquoi.length - 1].type === 'boucleF') {
          objet.where = 0
          return { tempo: false, cont: true }
        }
        if (objet.dansquoi[objet.dansquoi.length - 1].type === 'main') {
          return 'FIN'
        }
      }
      if (rep.result === 'setValPerso') {
        objet.where++
        return { tempo: false, cont: true }
      }
      if (rep.result === 'control_stop') {
        return 'FIN'
      }
      if (rep.result === 'prob') {
        params.scratchProgDonnees.avertissements.push(rep.quoi)
        return 'PROB'
      }
    }

    this.exeaction = function () {
      if (params.scratchProgDonnees.fostop) {
        params.scratchProgDonnees.sortieAvecProb = true
        params.scratchProgDonnees.avertissements.push('Tu as interrompu le programme')
        scratch.scratchVerifRun()
        return
      }
      if (params.scratchProgDonnees.fostopErreur) {
        params.scratchProgDonnees.sortieAvecProb = true
        params.scratchProgDonnees.avertissements.push(params.scratchProgDonnees.fostopErreurText)
        scratch.scratchVerifRun()
        return
      }
      if (params.scratchProgDonnees.pause) {
        objet.chrono = setTimeout(objet.exeaction, 1000)
        return
      }
      if (params.grosStop) return
      const quoifaire = objet.trouveprochainordre()
      // console.debug('quoifaire', quoifaire)
      scratch.testFlag()
      if (quoifaire === 'FIN') {
        params.scratchProgDonnees.sortieAvecProb = false
        scratch.scratchVerifRun()
        return
      }
      if (quoifaire === 'PROB') {
        params.scratchProgDonnees.sortieAvecProb = true
        params.scratchProgDonnees.avertissements.push('Je ne peux pas exécuter cet ordre !<BR>' + params.scratchProgDonnees.avertissements[params.scratchProgDonnees.avertissements.length - 1])
        scratch.scratchVerifRun()
        return
      }
      if (!objet.ModePasapas) {
        if (quoifaire === true && (!objet.vite)) {
          objet.chrono = setTimeout(objet.exeaction, 1000)
        } else {
          objet.exeaction()
        }
      } else {
        scratchFoncBoutSuiv()
      }
    }

    this.exeaction()
  }
}

export default ScratchProg