<script>

// https://brm.io/matter-js/docs/classes/Engine.html
// import {
//   // Engine,
//   // Render,
//   // World,
//   Bodies,
//   Body,
//   Events,
//   Composite,
//   // Composites,
//   // Constraint,
//   // Vertices,
//   // Mouse,
//   // MouseConstraint,
//   // Query,
//   // Common
// } from "matter-js";

import Matter from "matter-js";
import MatterAttractors from "matter-attractors";
// Matter.use(MatterAttractors);
// import polydecomp from "poly-decomp";

import paper from 'paper';

// import { easeInOutQuad, easeInOutQuart } from 'easing-utils';
import Tween from "@tweenjs/tween.js";

import { mapState, mapActions } from 'pinia'
import { ConcernementsStore } from '@/stores/concernements'
import { CommonStore } from '@/stores/common'

import iconAction from "@/assets/icons/action.svg"
import iconDoleancer from "@/assets/icons/doleancer.svg"
import iconProximite from "@/assets/icons/proximite.svg"
import iconPuissanceagir from "@/assets/icons/puissancedagir.svg"
import iconSuperposition from "@/assets/icons/superposition.svg"
import iconTerraindevie from "@/assets/icons/terraindevie.svg"

export default {
  inject: ['canvasMap', 'matterEngine'],
  data() {
    return {
      id: null,
      entities: null,
      canvas: null,
      ctx: null,
      pos : {
        x: 0,
        y: 0
      },
      ray: 100,
      time: 0,
      salientPoints: [],
      scale: 1,
      prev_scale: 1,
      opacity: 0,
      tween: null,
      body: null,
      body_parts: [],
      constraint: null,
      is_hover: false,
      //
      paper_objects: {}
    }
  },
  props: ['concernement', 'is_opened'],
  computed: {
    ...mapState(ConcernementsStore,['map_mode']),
    ...mapState(ConcernementsStore,['concernementsByID']),
    ...mapState(ConcernementsStore,['opened']),
    ...mapState(ConcernementsStore,['opened_entite_id']),
    ...mapState(CommonStore,['hover_elmt'])
  },
  created () {
    // console.log(`ConcernementsMapItem ${this.concernement.id} created`, this.canvasMap, this.matterEngine);
    this.id = this.concernement.id
    this.entites = this.concernement.entites
    this.entites_byid = this.concernement.entites_byid
    // console.log(`ConcernementsMapItem ${this.concernement.id} $route`, this.id, this.$route);
    // if (this.$route.name === 'concernement'
    //   && parseInt(this.$route.params.id) === this.id
    //   && typeof this.$route.params.eid !== "undefined") {
    //     // console.log("we have an entity");
    //     this.opened_entite_id = parseInt(this.$route.params.eid);
    // }
    
    // disable concernement if less than 3 entite
    if(this.entites.length < 3){
      this.hideShowConcernement(this.concernement.id, false);
    } else{
      this.parsePoints()
      // this.getSalientPoints()
      this.getJarvisEnvelopeConvexe()

      if (this.canvasMap) {
        this.initCanvasMap()
      }  
    }

    // if (this.salientPoints.length > 3) { // do not build item if it doesn't get enougth salient points
    // } else {
    //   this.hideShowConcernement(this.concernement.id, false);
    // }

  },
  // mounted() {
  //   console.log(`ConcernementsMapItem ${this.concernement.id} mounted`, this.canvasMap.canvas);
    
  // },
  watch: {
    // canvasMap (n, o) {
    //   console.log("concernementItem watch canvasMap", o, n);
    // }
    canvasMap: {
      handler (n, o){
        // console.log("concernementItem watch canvasMap.ctx", typeof this.canvas, o, n);
        if (!this.canvas) {
          this.initCanvasMap()
        }
      },
      deep: true
    },
    is_opened: {
      handler (n, o) {
        if(n){ // opened
          this.openClose(true);
        }else{ // closed
          this.openClose(false)
        }
      },
      deep: true
    },
    map_mode: {
      handler (n, o) {
        console.log('watch map_mode', o, n);
        if (n === 'terraindevie' && !this.opened) {
          this.applyShuffleForces(); // apply a little force to check the map when returning to terrain de vie
        }
      },
      deep: true
    },
    hover_elmt: {
      handler (n, o) {
        // console.log(`watch hover_elmt ${this.id}`, o, n);
        if (n && n.type === 'concernement' && n.id === this.id) {
          this.is_hover = true;
        } else {
          this.is_hover = false;
        }
      },
      deep: true
    }
  },
  methods: {
    ...mapActions(CommonStore,['setHoverElmt']),
    ...mapActions(ConcernementsStore,['openCloseConcernements']),
    ...mapActions(ConcernementsStore,['hideShowConcernement']),
    parsePoints (){
      // converts data (menace/maintien, actuel/future, prise) into atcual position x,y
      for (let i = 0; i < this.entites.length; i++) {
        let entite = this.entites[i]
        // console.log('entite', entite);
        
        this.entites[i].display = {
          alpha: null,
          ray: null
        }
        // RAYON
        // https://stackoverflow.com/questions/5731863/mapping-a-numeric-range-onto-another
        // slope = (output_end - output_start) / (input_end - input_start)
        // output = output_start + slope * (input - input_start)
        // from range 0 -> 100 to range 0 -> this.ray
        let init_max = 100
        let slope = this.ray / init_max
        this.entites[i].display.ray = slope * (init_max - entite.prise);
        // if (this.concernement.id === 28) {
        //   console.log(`entity prise: ${entite.prise} | ray: ${this.entites[i].display.ray}`);
        // }
        

        // ANGLE
        // -90 <= mm <= 90
        if (entite.actuelfuture) {
          // future en haut : 180 <= a <= 360
          // from -90 -> 90 to range 180 -> 360
          this.entites[i].display.alpha = entite.menacemaintien + 270
        } else {
          // actuel: en bas : O <= a <= 180
          // from -90 -> 90 to range 180 -> 0
          this.entites[i].display.alpha = -1 * entite.menacemaintien + 90
        }

        // POSITION X Y (par rapport au centre du concernement)
        this.entites[i].display.pos = {
          x: this.entites[i].display.ray * Math.cos(this.entites[i].display.alpha * (Math.PI/180)),
          y: this.entites[i].display.ray * Math.sin(this.entites[i].display.alpha * (Math.PI/180))
        }

        this.entites_byid[entite.entite.id].display = this.entites[i].display;
      }
    },
    getSalientPoints_OLD() {
      // debugger
      // console.log(this.entites);
      let arc = 360/30;
      // loop through arcs
      // for (let i = 360/arc; i >= 0 ; i--) {
      for (let i = 0; i <= 360/arc ; i++) {
        // loop through entities to find the farest on the arc
        let max_r = 0;
        let farest = null;
        for (let j = 0; j < this.entites.length; j++) {
          let entite = this.entites[j];
          if(arc*i <= entite.display.alpha && entite.display.alpha <= arc*i+arc) { // if entity is in arc
            if (entite.display.ray > max_r) { //  && entite.display.ray > this.ray/2 // and farest from minimu
              // if entity is farest from precedent one 
              max_r = entite.display.ray;
              // recalcul x & y to get a little padding between entite and contour by increasing ray
              farest = {
                alpha: entite.display.alpha,
                ray: entite.display.ray,
                pos: {
                  x: (entite.display.ray + 3) * Math.cos(entite.display.alpha * (Math.PI/180)),
                  y: (entite.display.ray + 3) * Math.sin(entite.display.alpha * (Math.PI/180))
                }
              };
            }
          }
        }
        if (farest) {
          this.salientPoints.push(farest)
        }
      }
      // console.log(`this.salientPoints ${this.concernement.id}`, this.salientPoints);
    },
    getJarvisEnvelopeConvexe(){
      console.log(`getJarvisEnvelopeConvexe ${this.id}`, this.entites.length);
      // https://www.geeksforgeeks.org/convex-hull-using-jarvis-algorithm-or-wrapping/
      // the most left point
      let l, min_x = null;
      for (let i = 0; i < this.entites.length; i++) {
        let entite = this.entites[i];
        let x = entite.display.ray * Math.cos(entite.display.alpha * (Math.PI/180));
        if(!min_x || min_x > x){
          l = i;
          min_x = x;
        }
      }
      let p = l, q;
      do {
        console.log(`do while ${this.id}`, p);
        // Add current point to result
        let entite = this.entites[p];
        let farest = {
          alpha: entite.display.alpha,
          ray: entite.display.ray,
          pos: {
            x: (entite.display.ray) * Math.cos(entite.display.alpha * (Math.PI/180)),
            y: (entite.display.ray) * Math.sin(entite.display.alpha * (Math.PI/180))
          }
        };
        this.salientPoints.push(farest);


        // Search for a point 'q' such that 
        // orientation(p, q, x) is counterclockwise 
        // for all points 'x'. The idea is to keep 
        // track of last visited most counterclock-
        // wise point in q. If any point 'i' is more 
        // counterclock-wise than q, then update q.
        q = (p + 1) % this.entites.length;
        for (let i = 0; i < this.entites.length; i++) {
          let p_x = (this.entites[p].display.ray + 3) * Math.cos(this.entites[p].display.alpha * (Math.PI/180));
          let p_y = (this.entites[p].display.ray + 3) * Math.sin(this.entites[p].display.alpha * (Math.PI/180));
          let i_x = (this.entites[i].display.ray + 3) * Math.cos(this.entites[i].display.alpha * (Math.PI/180));
          let i_y = (this.entites[i].display.ray + 3) * Math.sin(this.entites[i].display.alpha * (Math.PI/180));
          let q_x = (this.entites[q].display.ray + 3) * Math.cos(this.entites[q].display.alpha * (Math.PI/180));
          let q_y = (this.entites[q].display.ray + 3) * Math.sin(this.entites[q].display.alpha * (Math.PI/180));
          
          let val = (i_y - p_y) * (q_x - i_x) - (i_x - p_x) * (q_y - i_y);
          
          // If i is more counterclockwise than current q, then update q
          if (val > 0){
            q = i;
          }
        }

        // Now q is the most counterclockwise with
        // respect to p. Set p as q for next iteration, 
        // so that q is added to result 'hull'
        p = q;
      } while (p != l);

    },
    initCanvasMap (){
      // console.log(`ConcernementsMapItem ${this.concernement.id} initCanvasMap`);
      // record canvas and ctx for rendering (drawing)
      this.canvas = this.canvasMap.canvas
      this.ctx = this.canvasMap.ctx
      // this.paper = this.canvasMap.paper

      // define init position of the item
      this.pos = this.getRandomPos();
      //
      this.initMatterBody()
      //
      this.initPaperObjects()
    },
    getRandomPos(){
      let pad = 200;
      return {
        x: pad + this.ray/2 + Math.random()*(this.canvas.width - this.ray - pad),
        y: pad + this.ray/2 + Math.random()*(this.canvas.height - this.ray - pad)
      };
    },
    initMatterBody (){
      
      // MATTER
      // create the matter body and add it to the engine
      if (!this.body) {
        // console.log('concernementItem creating body');

        // https://github.com/liabru/matter-attractors/issues/8        
        // https://github.com/liabru/matter-attractors/blob/master/index.js
        // MatterAttractors.Attractors.gravityConstant = -5;
        
        // Create parts of the body : main big circle & entities
        this.body_parts = [
          Matter.Bodies.circle(0, 0, this.ray, {
            item_type: 'concernement',
            id: this.concernement.id,
          })
        ];

        // Create parts of the body : entities
        for (let i = 0; i < this.entites.length; i++) {
          // parts.push(Matter.Bodies.circle(this.pos.x+this.entites[i].display.pos.x, this.pos.y+this.entites[i].display.pos.y, 15, {
          //   item_type: 'entite',
          //   id: this.entites[i].id  
          // }))
          this.body_parts.push(Matter.Bodies.circle(this.entites[i].display.pos.x, this.entites[i].display.pos.y, 0.8, {
            item_type: 'entite',
            id: this.entites[i].entite.id,
            cid: this.concernement.id,
            agissante: this.entites[i].entite.agissante,
            isSensor: true
          }))
        }
        
        // Create parts of the body : besoins and responses
        this.createBesoinsBodyParts();
        
        // create the body
        this.body = Matter.Body.create({
          parts: this.body_parts,
          item_type: 'concernement',
          id: this.concernement.id,
          frictionAir: 0,
          // mass: Math.pow(3, this.entites.length),
          mass: 10,
          restitution: 0.15,
          collisionFilter: {
            group: -1
          },
          plugin: {
            attractors: [
              // there is a built in helper function for Newtonian gravity!
              // you can find out how it works in index.js
              MatterAttractors.Attractors.gravity
            ]
          }
        });
        Matter.Body.setPosition(this.body, this.pos);

        // add init velocity
        this.setInitBodyVelocity()
        // console.log('concernementItem mass', this.body.mass);
        Matter.Composite.add(this.matterEngine.world, this.body);
        // console.log('concernement body', this.body);

        // // listen for animate event dispatched from parent
        // this.canvas.addEventListener('animate', this.animate)

        // listen for afterUpdate event from Matter.Engine object
        Matter.Events.on(this.matterEngine, "beforeUpdate", this.onBeforeEngineUpdate);
        Matter.Events.on(this.matterEngine, "afterUpdate", this.onAfterEngineUpdate);
      }
    },
    setInitBodyVelocity(){
      let delta = 10;
      Matter.Body.setVelocity(this.body, {
        x: -delta + Math.random()*delta*2,
        y: -delta + Math.random()*delta*2
      });
    },
    createBesoinsBodyParts(){
      let res_fields = ['qui','quoi','ou','avec'];
      let arc = (360 / 16);               // unit arc
      let r = (this.ray * this.scale)/5;  // unit ray
      let br = r - r/3;                   // besoin ray

      for (let i = 0; i < this.concernement.besoins.length; i++) {
        let start_a = arc * i;              // angle depart (for reponses)
        let center_a = start_a + arc/2;     // angle central
        let x = Math.cos(center_a*(Math.PI/180)) * br;
        let y = Math.sin(center_a*(Math.PI/180)) * br;

        this.body_parts.push(Matter.Bodies.circle(x, y, 0.8, {
          item_type: 'besoin',
          id: this.concernement.besoins[i].id,
          cid: this.concernement.id,
          isSensor: true
        }));

        let res_arc = arc / (1 + this.concernement.besoins[i].reponses.length); // unit arc for responses depending responses number
        for (let j = 0; j < this.concernement.besoins[i].reponses.length; j++) {
          let res_a = start_a + res_arc * (j+1); // angle for response line
          for (let f = 0; f < res_fields.length; f++) { // loop through all 4 fields, keep only the last one filled
            if( this.concernement.besoins[i].reponses[j][res_fields[f]] // if field filled
              && (f === res_fields.length -1 || !this.concernement.besoins[i].reponses[j][res_fields[f+1]]) // and is last field or last field filled
              ){
              let rr = this.ray * this.scale - r*f - r/2; // reponse field ray
              let rx = Math.cos(res_a*(Math.PI/180)) * rr;
              let ry = Math.sin(res_a*(Math.PI/180)) * rr;
              
              this.body_parts.push(Matter.Bodies.circle(rx, ry, 0.8, {
                item_type: 'reponse',
                // field: res_fields[f],
                id: this.concernement.besoins[i].reponses[j].id,
                bid: this.concernement.besoins[i].id,
                cid: this.concernement.id,
                isSensor: true
              }));
            }
          }
        }
      }
    },
    // PAPER OBJECTS
    initPaperObjects(){
      this.paper_objects = new paper.Group({
        pivot: new paper.Point(this.pos),
        cid: this.id
      });
      this.paper_objects.addChild(this.setPaperBoussoleBG());
      this.paper_objects.addChild(this.setPaperContour());
      this.paper_objects.addChild(this.setPaperEntites());
      if (this.concernement.has_puissancedagir) {
        this.paper_objects.addChild(this.setPaperPuissanceagirBG());
        this.paper_objects.addChild(this.setPaperPuissanceagirICON());
        this.paper_objects.addChild(this.setPaperPuissanceagirBesoins());
      }
      if (this.concernement.has_agissantes) {
        this.paper_objects.addChild(this.setPaperAgissantes());
      }
      if (this.concernement.has_doleance) {
        this.paper_objects.addChild(this.setPaperDoleanceBG());
        this.paper_objects.addChild(this.setPaperDoleanceICON());
        this.paper_objects.addChild(this.setPaperDoleanceSteps());
      }
      console.log(`initPaperObjects ${this.id}`, this.paper_objects);

      this.initPaperEvents()
    },
    setPaperBoussoleBG(){
      // BOUSSOLE
      let children = [];
      let ray = this.ray*0.92*this.scale;

      // // // exterieur circle
      // children.push(new paper.Path.Circle({
      //   center: [this.pos.x, this.pos.y],
      //   radius: ray,
      //   strokeWidth: 2
      // }));

      // // interieur circle
      // children.push(new paper.Path.Circle({
      //   center: [this.pos.x, this.pos.y],
      //   radius: this.ray/2*this.scale,
      //   strokeWidth: 2
      // }));

      // cercles pointillés
      for (let i = 1; i < 9; i++) {
        let sw = i === 4 || i === 8 ? 2 : 1;
        let da = i === 4 || i === 8 ? null : [5,5];
        children.push(new paper.Path.Circle({
          center: [this.pos.x, this.pos.y],
          radius: ray/8*i,
          strokeColor: '#fff',
          strokeWidth: sw,
          dashArray: da
        }));
        
      }

      // axes
      // vertical
      children.push(new paper.Path.Line({
        from: [this.pos.x, this.pos.y - ray],
        to: [this.pos.x, this.pos.y + ray],
        strokeColor: '#fff',
        strokeWidth: 2
      }));
      // horizontal
      children.push(new paper.Path.Line({
        from: [this.pos.x - ray, this.pos.y],
        to: [this.pos.x + ray, this.pos.y],
        strokeColor: '#fff',
        strokeWidth: 2
      }))
      
      // fleches
      // haute
      children.push(new paper.Path({
        segments: [
          [this.pos.x - (8*this.scale), this.pos.y - ray + (8*this.scale)],
          [this.pos.x, this.pos.y - ray],
          [this.pos.x + (8*this.scale), this.pos.y - ray + (8*this.scale)],
        ],
        strokeWidth: 2,
        strokeColor: '#fff',
      }));
      // milieu
      children.push(new paper.Path({
        segments: [
        [this.pos.x - (8*this.scale), this.pos.y + (8*this.scale)],
        [this.pos.x, this.pos.y],
        [this.pos.x + (8*this.scale), this.pos.y + (8*this.scale)],
        ],
        strokeWidth: 2,
        strokeColor: '#fff',
      }));


      // MOINS - PLUS
      // PLUS
      // horizontal
      children.push(new paper.Path.Line({
        from: [this.pos.x + ray - (5 * this.scale), this.pos.y - ray],
        to: [this.pos.x + ray + (5 * this.scale), this.pos.y - ray],
        strokeWidth: 8,
        strokeColor: '#fff',
      }))
      // vertical
      children.push(new paper.Path.Line({
        from: [this.pos.x + ray, this.pos.y - ray - (5 * this.scale)],
        to: [this.pos.x + ray, this.pos.y - ray + (5 * this.scale)],
        strokeWidth: 8,
        strokeColor: '#fff',
      }))
      
      // MOINS
      // horizontal
      children.push(new paper.Path.Line({
        from: [this.pos.x - ray - (5 * this.scale), this.pos.y - ray],
        to: [this.pos.x - ray + (5 * this.scale), this.pos.y - ray],
        strokeWidth: 8,
        strokeColor: '#fff',
      }))

      let fontsize = 4;
      
      children.push(new paper.PointText({
        point: [this.pos.x + 4.5, this.pos.y - ray - 5],
        content: `entités qui menacent \u2194 entités qui maintiennent`,
        fontSize: fontsize,
        justification: 'center',
        fillColor: '#000',
      }))

      children.push(new paper.PointText({
        point: [this.pos.x - ray - 5, this.pos.y + 1],
        content: "axe d'intensité",
        fontSize: fontsize,
        justification: 'right',
        fillColor: '#000',
      }))

      children.push(new paper.PointText({
        point: [this.pos.x + ray + 5, this.pos.y - 4],
        content: "situation future",
        fontSize: fontsize,
        justification: 'left',
        fillColor: '#000',
      }))

      children.push(new paper.PointText({
        point: [this.pos.x + ray + 5, this.pos.y + 6],
        content: "situation actuelle",
        fontSize: fontsize,
        justification: 'left',
        fillColor: '#000',
      }))

      let t1 = new paper.PointText({
        point: [this.pos.x - ray/8*2.3, this.pos.y - ray/8*2.3],
        content: "avec prise",
        fontSize: fontsize,
        justification: 'center',
        fillColor: '#000',
      })
      t1.rotate(-45)
      children.push(t1)

      let t2 = new paper.PointText({
        point: [this.pos.x - ray/8*2.95, this.pos.y - ray/8*2.95],
        content: "sans prise",
        fontSize: fontsize,
        justification: 'center',
        fillColor: '#000',
      })
      t2.rotate(-45)
      children.push(t2)


      return new paper.Group({
        children: children,
        pivot: new paper.Point(this.pos),
        name: 'boussole_bg',
        locked: true,
      });

    },
    setPaperContour(){
      let getExentricPoint = (b,a,c) => {
        // get ac vecteur
        const ac  = { x: c.x - a.x, y: c.y - a.y }
        // get ac longueur ac
        const lac = Math.sqrt(Math.pow(ac.x, 2) + Math.pow(ac.y, 2));
        // get ab vecteur
        const ab  = { x: b.x - a.x, y: b.y - a.y }
        // get ab longeur
        const lab = Math.sqrt(Math.pow(ab.x, 2) + Math.pow(ab.y, 2));
        // get unit vecteur ab
        const vab = { x: ab.x/lab, y: ab.y/lab }
        // get an vecteur
        const an  = { x: vab.x*lac, y: vab.y*lac }
        // get n point
        const n   = { x: a.x + an.x, y: a.y+an.y }
        // get nc midle point
        const m   = { x: (c.x + n.x)/2, y: (c.y + n.y)/2 }
        // get ma vecteur
        const ma  = { x:a.x - m.x, y: a.y - m.y }
        // get longeur m->a
        const lma = Math.sqrt(Math.pow(ma.x, 2)+Math.pow(ma.y, 2))
        // get ma vecteur unitaire
        const vma = { x: ma.x/lma, y: ma.y / lma }
        const pad = 4;
        return [
          this.pos.x+(a.x+vma.x*pad)*this.scale,
          this.pos.y+(a.y+vma.y*pad)*this.scale
        ]

      }
      const first_point = getExentricPoint(
        this.salientPoints[this.salientPoints.length-1].pos,
        this.salientPoints[0].pos,
        this.salientPoints[1].pos
      );
      let segments = [first_point]; 
      for (let j = 1; j < this.salientPoints.length-1; j++) {
        // segments.push([this.pos.x+this.salientPoints[j].pos.x*this.scale*gap, this.pos.y+this.salientPoints[j].pos.y*this.scale*gap])
          segments.push(getExentricPoint(
            this.salientPoints[j-1].pos,
            this.salientPoints[j].pos,
            this.salientPoints[j+1].pos,
          ))
      }
      const last_point = getExentricPoint(
        this.salientPoints[this.salientPoints.length-2].pos,
        this.salientPoints[this.salientPoints.length-1].pos,
        this.salientPoints[0].pos
      );
      segments.push(last_point)
      segments.push(first_point)
      
      return new paper.Path({
        name: 'contours',
        segments: segments,
        fillColor: 'rgba(255,255,255,0.8)',
        // strokeColor: '#000',
        // strokeWidth: 1,
        pivot: new paper.Point(this.pos),
        cid: this.id
      });
    },
    setPaperEntites(){
      let g = new paper.Group({
        pivot: new paper.Point(this.pos),
        name: 'entites'
      });
      for (let i = 0; i < this.body.parts.length; i++) {
        if (this.body.parts[i].item_type === 'entite') {
          let part = this.body.parts[i];
          g.addChild(new paper.Path.Circle({
            center: [part.position.x, part.position.y],
            radius: 0.5, //0.3
            fillColor: '#000',
            item_id: part.id,
            item_type: 'entite'
          }))
        }
      }
      return g;
    },
    setPaperPuissanceagirBG(){
      let children = [];

      for (let i = 1; i < 6; i++) {
        children.push(new paper.Path.Circle({
          center: [this.pos.x, this.pos.y],
          radius: ((this.ray*this.scale)/5)*i,
          strokeWidth: 0.5
        }));
      }

      for (let j = 0; j < 4; j++) {
        let a  = (90 / 4) * j;
        // diagonale
        // https://fr.wikipedia.org/wiki/Trigonom%C3%A9trie#/media/Fichier:Unit_circle_angles_color.svg
        // https://fr.wikipedia.org/wiki/Identit%C3%A9_trigonom%C3%A9trique_pythagoricienne#Preuve_utilisant_le_cercle_unit%C3%A9
        // radians = degrees * (pi/180)
        // degrees = radians * (180/pi)
        let x = Math.cos(a*(Math.PI/180)) * this.ray * this.scale;
        let y = Math.sin(a*(Math.PI/180)) * this.ray * this.scale;
        
        children.push(new paper.Path.Line({
          from: [this.pos.x + x, this.pos.y + y],
          to: [this.pos.x - x, this.pos.y - y],
          strokeWidth: 1,
          dashArray: [5,5]
        }))

        children.push(new paper.Path.Line({
          from: [this.pos.x - y, this.pos.y + x],
          to: [this.pos.x + y, this.pos.y - x],
          strokeWidth: 1,
          dashArray: [5,5]
        }))

      }
      
      children.push(new paper.Path.Circle({
        center: [this.pos.x, this.pos.y],
        radius: this.ray*this.scale,
        strokeWidth: 2,
        fillColor: `rgba(255,255,255,0.6)`
      }));


      return new paper.Group({
        children: children,
        pivot: new paper.Point(this.pos),
        name: 'puissanceagir_bg',
        // locked: true,
        style: {
          strokeColor: '#fff'
        }
      });
    },
    setPaperPuissanceagirICON(){
      let children = [];

      let svgIcon = paper.project.importSVG(iconPuissanceagir);
      children.push(svgIcon);
      svgIcon.position = this.pos;
      
      return new paper.Group({
        children: children,
        pivot: new paper.Point(this.pos),
        name: 'puissanceagir_icon',
        locked: true,
        style: {
          strokeColor: '#000',
          strokeWidth: 1,
          fillColor: null
        }
      });
    },
    setPaperPuissanceagirBesoins(){
      let g = new paper.Group({
        pivot: new paper.Point(this.pos),
        name: 'puissanceagir_besoins'
      });

      for (let i = 0; i < this.body.parts.length; i++) {
        if (this.body.parts[i].item_type === 'besoin' || this.body.parts[i].item_type === 'reponse') {
          let part = this.body.parts[i];
          
          switch (part.item_type) {
            case 'besoin':
              g.addChild(
                new paper.Path({
                  segments: this.getDiamondSegments(part.position.x, part.position.y, 1),
                  fillColor: '#000',
                  pivot: new paper.Point(this.pos),
                  item_id: part.id,
                  item_type: 'besoin'
                })
              )
              break;
            case 'reponse':
              g.addChild(
                new paper.Path({
                  segments: this.getDiamondSegments(part.position.x, part.position.y, 1),
                  fillColor: '#eee',
                  strokeColor: "#000",
                  strokeWidth: 1,
                  pivot: new paper.Point(this.pos),
                  item_id: part.id,
                  item_bid: part.bid,
                  item_cid: part.cid,
                  item_type: 'reponse'
                })
              )
              break;
          }
        }
      }

      return g;
    },
    getDiamondSegments(x,y,r){
      return [
        [x, y - r],
        [x + r, y],
        [x, y + r],
        [x - r, y],
        [x, y - r]
      ];
    },
    setPaperAgissantes(){
      let g = new paper.Group({
        pivot: new paper.Point(this.pos),
        name: 'agissantes'
      });
      for (let i = 0; i < this.body.parts.length; i++) {
        if (this.body.parts[i].item_type === 'entite' && this.body.parts[i].agissante) {
          let part = this.body.parts[i];
          g.addChild(new paper.Path.Circle({
            center: [part.position.x, part.position.y],
            radius: 0.3, //0.3
            fillColor: '#000',
            strokeColor: '#000',
            strokeWidth: 3,
            item_id: part.id,
            item_type: 'entite'
          }))
        }
      }
      return g;
    },
    setPaperDoleanceBG(){
      var r = this.ray * this.scale * 0.8;  // ray
      var dr = r/2;                         // demi ray
      var pcr = 2*this.scale;               // petits cercle rayon

      // https://fr.wikipedia.org/wiki/Trigonom%C3%A9trie#/media/Fichier:Unit_circle_angles_color.svg
      // https://fr.wikipedia.org/wiki/Identit%C3%A9_trigonom%C3%A9trique_pythagoricienne#Preuve_utilisant_le_cercle_unit%C3%A9
      // radians = degrees * (pi/180)
      // degrees = radians * (180/pi)
      // Points for 45° axes
      let m = Math.sin(45*(Math.PI/180)) * r;   // x = y for rayon
      let n = Math.sin(45*(Math.PI/180)) * r/2; // x = y for demi rayon
      // console.log('m', m);

      // points for legende arcs
      var lar = r*1.1;                       // legendes arcs rayon
      let o = Math.cos(22.5*(Math.PI/180)) * lar; // x @ 22.5° for legende arc rayon
      let p = Math.sin(22.5*(Math.PI/180)) * lar; // y @ 22.5° for legende arc rayon
      let q = Math.sin(45*(Math.PI/180)) * lar;   // x = y  @ 45° for legende arc rayon

      var ltr = lar + 4;                       // legendes texts rayon
      let o_t = Math.cos(22.5*(Math.PI/180)) * ltr; // x @ 22.5° for legende text rayon
      let p_t = Math.sin(22.5*(Math.PI/180)) * ltr; // y @ 22.5° for legende text rayon
      let q_t = Math.sin(45*(Math.PI/180)) * ltr;   // x = y  @ 45° for legende text rayon

      let style = {
        strokeColor: '#fff',
        strokeWidth: 1
      }
      let felchesstyle = {
        strokeColor: '#fff',
        strokeWidth: 2
      }

      let legende_style = {
        strokeColor: '#000',
        strokeWidth: 1
      }

      let fontsize = 2.1;

      let children = [
        // ARCS EXTERIEURS
        // haut gauche
        new paper.Path.Arc({
          from: [this.pos.x - r, this.pos.y - pcr],
          through: [this.pos.x - m, this.pos.y - m],
          to: [this.pos.x - pcr, this.pos.y - r],
          style: style
        }),
        // haut droite
        new paper.Path.Arc({
          from: [this.pos.x + pcr, this.pos.y - r],
          through: [this.pos.x + m, this.pos.y - m],
          to: [this.pos.x + r, this.pos.y - pcr],
          style: style
        }),
        // bas droite
        new paper.Path.Arc({
          from: [this.pos.x + r, this.pos.y + pcr],
          through: [this.pos.x + m, this.pos.y + m],
          to: [this.pos.x + pcr, this.pos.y + r],
          style: style
        }),
        // bas gauche
        new paper.Path.Arc({
          from: [this.pos.x - pcr, this.pos.y + r],
          through: [this.pos.x - m, this.pos.y + m],
          to: [this.pos.x - r, this.pos.y + pcr],
          style: style
        }),
        //
        // cercle interieur
        new paper.Path.Circle({
          center: [this.pos.x, this.pos.y],
          radius: dr,
          style: style
        }),
        //
        // petit cercles
        new paper.Path.Circle({
          center: [this.pos.x, this.pos.y -r],
          radius: pcr,
          style: style
        }),
        new paper.Path.Circle({
          center: [this.pos.x, this.pos.y + r],
          radius: pcr,
          style: style
        }),
        new paper.Path.Circle({
          center: [this.pos.x + r, this.pos.y],
          radius: pcr,
          style: style
        }),
        new paper.Path.Circle({
          center: [this.pos.x -r, this.pos.y],
          radius: pcr,
          style: style
        }),
        //
        // AXES
        // vertical haut
        new paper.Path.Line({
          from: [this.pos.x, this.pos.y - r + pcr],
          to: [this.pos.x , this.pos.y - dr],
          style: style
        }),
        // vertical bas
        new paper.Path.Line({
          from: [this.pos.x, this.pos.y + r - pcr],
          to: [this.pos.x , this.pos.y + dr],
          style: style
        }),
        // horizontal gauche
        new paper.Path.Line({
          from: [this.pos.x - r + pcr, this.pos.y],
          to: [this.pos.x - dr, this.pos.y],
          style: style
        }),
        // horizontal droite
        new paper.Path.Line({
          from: [this.pos.x + r - pcr, this.pos.y],
          to: [this.pos.x + dr, this.pos.y],
          style: style
        }),
        //
        // DIAGONALES
        // bas droite
        new paper.Path.Line({
          from: [this.pos.x + m, this.pos.y + m],
          to: [this.pos.x + n, this.pos.y + n],
          style: style
        }),
        // bas gauche
        new paper.Path.Line({
          from: [this.pos.x - m, this.pos.y + m],
          to: [this.pos.x - n, this.pos.y + n],
          style: style
        }),
        // // haut droite
        // new paper.Path.Line({
        //   from: [this.pos.x + m, this.pos.y - m],
        //   to: [this.pos.x + n, this.pos.y - n],
        //   style: style
        // }),
        // // haut gauche
        // new paper.Path.Line({
        //   from: [this.pos.x - m, this.pos.y - m],
        //   to: [this.pos.x - n, this.pos.y - n],
        //   style: style
        // }),
        // fleches
        // haut
        new paper.Path({
          segments: [
            [this.pos.x - 2, this.pos.y - dr*1.5 - 2],
            [this.pos.x, this.pos.y - dr*1.5],
            [this.pos.x - 2, this.pos.y - dr*1.5 + 2]
          ],
          style: felchesstyle
        }),
        // bas
        new paper.Path({
          segments: [
            [this.pos.x + 2, this.pos.y + dr*1.5 - 2],
            [this.pos.x, this.pos.y + dr*1.5],
            [this.pos.x + 2, this.pos.y + dr*1.5 + 2]
          ],
          style: felchesstyle
        }),
        // gauche
        new paper.Path({
          segments: [
            [this.pos.x - dr*1.5 - 2, this.pos.y + 2],
            [this.pos.x - dr*1.5, this.pos.y],
            [this.pos.x - dr*1.5 + 2, this.pos.y + 2]
          ],
          style: felchesstyle
        }),
        // droite
        new paper.Path({
          segments: [
            [this.pos.x + dr*1.5 - 2, this.pos.y - 2],
            [this.pos.x + dr*1.5, this.pos.y],
            [this.pos.x + dr*1.5 + 2, this.pos.y - 2]
          ],
          style: felchesstyle
        }),
        //
        // LEGENDES
        //
        // arc bas gauche 1
        new paper.Path.Arc({
          from: [this.pos.x - pcr, this.pos.y + lar],
          through: [this.pos.x - p, this.pos.y + o],
          to: [this.pos.x - q + pcr/2, this.pos.y + q + pcr/2],
          style: legende_style
        }),
        // tiret
        new paper.Path.Line({
          from: [this.pos.x - p, this.pos.y + o],
          to: [this.pos.x - p_t, this.pos.y + o_t],
          style: legende_style
        }),
        //text
        new paper.PointText({
          point: [this.pos.x - p_t - 1, this.pos.y + o_t],
          content: "Enquête menée\nsur le terrain de vie",
          fontSize: fontsize,
          justification: 'right'
        }),
        // arc bas gauche 2
        new paper.Path.Arc({
          from: [this.pos.x - q - pcr/2, this.pos.y + q - pcr/2],
          through: [this.pos.x - o, this.pos.y + p],
          to: [this.pos.x - lar, this.pos.y + pcr],
          style: legende_style
        }),
        // tiret
        new paper.Path.Line({
          from: [this.pos.x - o, this.pos.y + p],
          to: [this.pos.x - o_t, this.pos.y + p_t],
          style: legende_style
        }),
        // texte
        new paper.PointText({
          point: [this.pos.x - o_t - 1, this.pos.y + p_t],
          content: "Construction de groupes d'intérets\navec qui composer la doléance",
          fontSize: fontsize,
          justification: 'right'
        }),
        // arc haut gauche
        new paper.Path.Arc({
          from: [this.pos.x - lar, this.pos.y - pcr],
          through: [this.pos.x - q, this.pos.y - q],
          to: [this.pos.x - pcr, this.pos.y - lar],
          style: legende_style
        }),
        // tiret
        new paper.Path.Line({
          from: [this.pos.x - q, this.pos.y - q],
          to: [this.pos.x - q_t, this.pos.y - q_t],
          style: legende_style
        }),
        // texte
        new paper.PointText({
          point: [this.pos.x - q_t - 1, this.pos.y - q_t],
          content: "Réception et traitement\nde la doléance",
          fontSize: fontsize,
          justification: 'right'
        }),
        // arc haut droite
        new paper.Path.Arc({
          from: [this.pos.x + pcr, this.pos.y - lar],
          through: [this.pos.x + q, this.pos.y - q],
          to: [this.pos.x + lar, this.pos.y - pcr],
          style: legende_style
        }),
        // tiret
        new paper.Path.Line({
          from: [this.pos.x + q, this.pos.y - q],
          to: [this.pos.x + q_t, this.pos.y - q_t],
          style: legende_style
        }),
        // texte
        new paper.PointText({
          point: [this.pos.x + q_t + 1, this.pos.y - q_t],
          content: "Mise-en-œuvre\nde la décision",
          fontSize: fontsize,
          justification: 'left'
        }),
        // arc bas droite 1
        new paper.Path.Arc({
          from: [this.pos.x + lar, this.pos.y + pcr],
          through: [this.pos.x + o, this.pos.y + p],
          to: [this.pos.x + q + pcr/2, this.pos.y + q - pcr/2],
          style: legende_style
        }),
        // tiret
        new paper.Path.Line({
          from: [this.pos.x + o, this.pos.y + p],
          to: [this.pos.x + o_t, this.pos.y + p_t],
          style: legende_style
        }),
        // texte
        new paper.PointText({
          point: [this.pos.x + o_t + 1, this.pos.y + p_t],
          content: "Réception et application\nde la décision",
          fontSize: fontsize,
          justification: 'left'
        }),
        // arc bas droite 2
        new paper.Path.Arc({
          from: [this.pos.x + q - pcr/2, this.pos.y + q + pcr/2],
          through: [this.pos.x + p, this.pos.y + o],
          to: [this.pos.x + pcr, this.pos.y + lar],
          style: legende_style
        }),
        // tiret
        new paper.Path.Line({
          from: [this.pos.x + p, this.pos.y + o],
          to: [this.pos.x + p_t, this.pos.y + o_t],
          style: legende_style
        }),
        // texte
        new paper.PointText({
          point: [this.pos.x + p_t + 1, this.pos.y + o_t],
          content: "Réussite / échec / reprise\ndu cercle politique",
          fontSize: fontsize,
          justification: 'left'
        }),
        //
        // Points Cardinaux
        //
        // haut
        new paper.Path.Circle({
          center: [this.pos.x, this.pos.y -r],
          radius: 0.5,
          style: {
            fillColor: '#000'
          }
        }),
        new paper.Path.Line({
          from: [this.pos.x, this.pos.y -r],
          to: [this.pos.x, this.pos.y - r - 8],
          style: legende_style
        }),
        new paper.PointText({
          point: [this.pos.x, this.pos.y - r - 9],
          content: "Décision",
          fontSize: fontsize,
          justification: 'center'
        }),
        // bas
        // new paper.Path.Circle({
        //   center: [this.pos.x, this.pos.y + r],
        //   radius: 0.5,
        //   style: {
        //     fillColor: '#000'
        //   }
        // }),
        // new paper.Path.Line({
        //   from: [this.pos.x, this.pos.y + r],
        //   to: [this.pos.x, this.pos.y + r + 8],
        //   style: legende_style
        // }),
        // new paper.PointText({
        //   point: [this.pos.x, this.pos.y + r + 10],
        //   content: "Début du cercle\nLe problème\n(injustice, indignation, plainte...)",
        //   fontSize: fontsize,
        //   justification: 'center'
        // }),
        // droite
        new paper.Path.Circle({
          center: [this.pos.x + r, this.pos.y],
          radius: 0.5,
          style: {
            fillColor: '#000'
          }
        }),
        new paper.Path.Line({
          from: [this.pos.x + r, this.pos.y],
          to: [this.pos.x + r + 8, this.pos.y],
          style: legende_style
        }),
        new paper.PointText({
          point: [this.pos.x + r + 9, this.pos.y - 0.5],
          content: "Adresse de la décision\nà appliquer",
          fontSize: fontsize,
          justification: 'left'
        }),
        // gauche
        new paper.Path.Circle({
          center: [this.pos.x -r, this.pos.y],
          radius: 0.5,
          style: {
            fillColor: '#000'
          }
        }),
        new paper.Path.Line({
          from: [this.pos.x - r, this.pos.y],
          to: [this.pos.x - r - 8, this.pos.y],
          style: legende_style
        }),
        new paper.PointText({
          point: [this.pos.x - r - 9, this.pos.y + 0.4],
          content: "Adresse de la doléance",
          fontSize: fontsize,
          justification: 'right'
        }),
      ];


      return new paper.Group({
        children: children,
        pivot: new paper.Point(this.pos),
        name: 'doleance_bg',
        locked: true
      });
    },
    setPaperDoleanceICON(){
      let children = [];

      let svgIcon = paper.project.importSVG(iconDoleancer);
      children.push(svgIcon);
      svgIcon.position = this.pos;

      return new paper.Group({
        children: children,
        pivot: new paper.Point(this.pos),
        name: 'doleance_icon',
        locked: true,
        style: {
          strokeColor: '#000',
          strokeWidth: 1,
          fillColor: null
        }
      });


    },
    setPaperDoleanceSteps(){
      let g = new paper.Group({
        pivot: new paper.Point(this.pos),
        name: 'doleance_steps'
      });
      let doleance = this.concernement.doleances[0];
      let all_fields = [
        [
          'leprobleme',
          'lenquete',
          {
            fieldname: 'groupesinterets',
            fields: [
                    'groupe_interets',
                    'accorder_interets',
                    'formuler',
                    ] 
          }
        ],
        [
          'entite_addresse_doleance',
          'comment_ennonce_doleance',
          'aqui_addresse_doleance',
          {
            fieldname: 'reception_traitement',
            fields: [
                    'entite_adressee',
                    'doleance_formulee',
                    'traite_doleance',
                    'entite_recoit_doleance',
                    ]
          }
        ],
        [
          'entites_decisionnaires',
          'decision_formule',
          {
            fieldname: 'mise_en_oeuvre_decision',
            fields: [
                    'entite_adresse_decision',
                    'formule_decision',
                    'entite_metenoeuvre_decisio',
                    ]
          }
        ],
        [
          'entite_adresse_application',
          'aqui_adresse_decision',
          'comment_formule_decision',
          {
            fieldname: 'receptions_et_applications',
            fields: [
                    'applique_decision',
                    'formule_decision_applic',
                    'entite_recoit_decision',
                    ]
          },
          'probleme_initial_resolu',
          'oui_nouvelle_situation',
          'non_adresse_doleance',
        ]
      ];
      
      var r = this.ray * this.scale * 0.8;  // ray
      var dr = r/2;                         // demi ray
      var pcr = 2*this.scale;               // petits cercle rayon

      // https://fr.wikipedia.org/wiki/Trigonom%C3%A9trie#/media/Fichier:Unit_circle_angles_color.svg
      // https://fr.wikipedia.org/wiki/Identit%C3%A9_trigonom%C3%A9trique_pythagoricienne#Preuve_utilisant_le_cercle_unit%C3%A9
      // radians = degrees * (pi/180)
      // degrees = radians * (180/pi)
      // Points for 45° axes
      let m = Math.sin(45*(Math.PI/180)) * r;   // x = y for rayon
      let n = Math.sin(45*(Math.PI/180)) * r/2; // x = y for demi rayon

      let o = Math.cos(22.5*(Math.PI/180)) * r; // x @ 22.5° for rayon
      let p = Math.sin(22.5*(Math.PI/180)) * r; // y @ 22.5° for rayon
      let o_d = Math.cos(22.5*(Math.PI/180)) * r/2; // x @ 22.5° for demi rayon
      let p_d = Math.sin(22.5*(Math.PI/180)) * r/2; // y @ 22.5° for demi rayon

      let fontsize = 2.1;
      
      //
      // POINTS CARDINAUX
      //
      // le problème
      //
      g.addChild(new paper.Path.Circle({
        center: [this.pos.x, this.pos.y + r],
        radius: 0.5,
        style: {
          fillColor: '#fff'
        }
      }));
      g.addChild(new paper.Path.Line({
        from: [this.pos.x, this.pos.y + r],
        to: [this.pos.x, this.pos.y + r + 8],
        strokeColor: '#fff'
      }));
      g.addChild(new paper.PointText({
          point: [this.pos.x, this.pos.y + r + 10],
          content: "Début du cercle\nLe problème (injustice, indignation, plainte...)",
          fontSize: fontsize,
          fillColor: '#000',
          justification: 'center'
      }));
      g.addChild(new paper.PointText({
        point: [this.pos.x, this.pos.y + r + 16],
        content: doleance['leprobleme'],
        fontSize: 2.3,
        fillColor: '#fff',
        justification: 'center'
      }));
      
      //
      // CAMENBERT STATIQUES
      //
      // l'enquete
      //
      // camenbert
      let cam = new paper.Path({
        strokeColor: '#fff',
        strokeWidth: 2,
        fillColor: "rgba(255, 255, 255, 0.4)",
        item_type: 'doleance_step',
        item_id: 'lenquete'
      });
      cam.add({x: this.pos.x , y: this.pos.y + dr});
      cam.lineTo({x: this.pos.x, y: this.pos.y + r});
      cam.arcTo({x: this.pos.x - p, y: this.pos.y + o}, {x: this.pos.x - m, y: this.pos.y + m});
      cam.lineTo({x: this.pos.x - n, y: this.pos.y + n});
      cam.arcTo({x: this.pos.x - p_d, y: this.pos.y + o_d}, {x: this.pos.x , y: this.pos.y + dr});
      // texte
      // enquete.addChild(new paper.PointText({
        //   point: {
          //     x:this.pos.x + Math.sin(22.5*(Math.PI/180)) * r*0.75,
          //     y:this.pos.y + Math.cos(22.5*(Math.PI/180)) * r*0.75
          //   },
          //   content: doleance['lenquete'],
          //   fontSize: fontsize,
      //   fillColor: '#fff',
      //   justification: 'center',
      //   locked: true
      // }));
      g.addChild(cam);
      
      //
      // probleme_initial_resolu
      //
      // camenbert
      let rescam = new paper.Path({
        strokeColor: '#fff',
        strokeWidth: 2,
        fillColor: "rgba(255, 255, 255, 0.4)",
        closed: true,
        item_type: 'doleance_step',
        item_id: 'probleme_initial_resolu',
      });
      rescam.add({x: this.pos.x + n, y: this.pos.y + n});
      rescam.lineTo({x: this.pos.x + m , y: this.pos.y + m});
      rescam.arcTo({x: this.pos.x + p, y: this.pos.y + o}, {x: this.pos.x, y: this.pos.y + r});
      rescam.lineTo({x: this.pos.x, y: this.pos.y + dr});
      rescam.arcTo({x: this.pos.x + p_d, y: this.pos.y + o_d}, {x: this.pos.x + n, y: this.pos.y + n});
      // texte
      // resolution.addChild(new paper.PointText({
        //   point: {
          //     x:this.pos.x - Math.sin(22.5*(Math.PI/180)) * r*0.75,
          //     y:this.pos.y + Math.cos(22.5*(Math.PI/180)) * r*0.75
          //   },
          //   content: doleance['probleme_initial_resolu'] ? doleance['oui_nouvelle_situation'] : doleance['non_adresse_doleance'],
          //   fontSize: fontsize,
          //   fillColor: '#fff',
          //   justification: 'center'
          // }));
      g.addChild(rescam)
      
      //
      // MULTIPLE FIELDS
      //
      let multiple_fields = [
        { field_name: 'groupesinterets',            arc: 45, decalage: -45 },
        { field_name: 'reception_traitement',       arc: 90, decalage: -90 },
        { field_name: 'mise_en_oeuvre_decision',    arc: 90, decalage: -180 },
        { field_name: 'receptions_et_applications', arc: 45, decalage: 90 }
      ]

      multiple_fields.forEach((mf, j) => {
        for (let i = 0, l = doleance[mf.field_name].length, a = mf.arc/l; i < l; i++) {
          // let gi = new paper.Group({
          //   item_type: 'doleance_step',
          //   item_id: 'lenquete',
          //   item_field: mf.field_name,
          //   item_index: i
          // });
          //camenbert
          let x1=  this.pos.x + Math.sin((mf.decalage- a*i)*(Math.PI/180)) * dr,
              y1=  this.pos.y + Math.cos((mf.decalage- a*i)*(Math.PI/180)) * dr;
          let x2=  this.pos.x + Math.sin((mf.decalage- a*i)*(Math.PI/180)) * r,
              y2=  this.pos.y + Math.cos((mf.decalage- a*i)*(Math.PI/180)) * r;
          let x3=  this.pos.x + Math.sin((mf.decalage- a*(i+1))*(Math.PI/180)) * r,
              y3=  this.pos.y + Math.cos((mf.decalage- a*(i+1))*(Math.PI/180)) * r;
          let x3t= this.pos.x + Math.sin((mf.decalage- a*(i+0.5))*(Math.PI/180)) * r,
              y3t= this.pos.y + Math.cos((mf.decalage- a*(i+0.5))*(Math.PI/180)) * r;
          let x4=  this.pos.x + Math.sin((mf.decalage- a*(i+1))*(Math.PI/180)) * dr,
              y4=  this.pos.y + Math.cos((mf.decalage- a*(i+1))*(Math.PI/180)) * dr;
          let x4t= this.pos.x + Math.sin((mf.decalage- a*(i+0.5))*(Math.PI/180)) * dr,
              y4t= this.pos.y + Math.cos((mf.decalage- a*(i+0.5))*(Math.PI/180)) * dr;
          let x5=  this.pos.x + Math.sin((mf.decalage- a*(i+0.5))*(Math.PI/180)) * r*0.75,
              y5=  this.pos.y + Math.cos((mf.decalage- a*(i+0.5))*(Math.PI/180)) * r*0.75;
          let p = new paper.Path({
            strokeColor: '#fff',
            strokeWidth: 2,
            fillColor: "rgba(255, 255, 255, 0.4)",
            item_type: 'doleance_step',
            item_id: `${mf.field_name}-${i}`,
            item_field: mf.field_name
          });
          p.add([x1,y1]);
          p.lineTo([x2,y2]);
          p.arcTo([x3t,y3t], [x3,y3]);
          p.lineTo([x4,y4]);
          p.arcTo([x4t,y4t], [x1,y1]);
          g.addChild(p);
          // gi.addChild(p);
          // // text
          // gi.addChild(new paper.PointText({
          //   point: {x:x5,y:y5},
          //   content: `${j}-${i}`,
          //   fontSize: fontsize,
          //   fillColor: '#fff',
          //   justification: 'center'
          // }))

          // g.addChild(gi)
        }
      });

      return g;
    },
    // PAPER EVENTS
    initPaperEvents(){

      this.paper_objects.onMouseEnter = function(event){
        if (!this.opened && this.isFocused()) { // only if no concernement is opened and is this focused
          this.setHoverElmt({
            type: 'concernement',
            id: this.id
          });
          document.body.style.cursor = "pointer";
        }
      }.bind(this);
      
      this.paper_objects.onMouseLeave = function(event){
        if (!this.opened && this.isFocused()) { // only if no concernement is opened
          this.resetHoverElmt();
          document.body.style.cursor = "auto";
        }
      }.bind(this);

      this.paper_objects.onMouseMove = function(event){
        // console.log(`onmousemove ${this.id}`);
        // TODO besoins & actions & doleances
        if (this.is_opened) {
          
          // lets define some options regarding the map_mode
          let paper_group_tohit;
          switch (this.map_mode) {
            case "terraindevie":
              paper_group_tohit = 'entites';
              break;
            case "action":
              paper_group_tohit = 'agissantes';
              break;
            case "puissancedagir":
              paper_group_tohit = 'puissanceagir_besoins';
              break;
            case "doleancer":
              paper_group_tohit = 'doleance_steps';
              break;
          }

          let result = this.paper_objects.children[paper_group_tohit].hitTest(event.point);
          // console.log('move result', result);
          if (result && result.item.item_id) {
            // console.log('move has result', result);
            let new_hover_elmt = {
              paper_id: result.item.id,
              type: result.item.item_type,
              id: result.item.item_id
            }; 
            switch (result.item.item_type) {
              case "reponse":
                new_hover_elmt.bid = result.item.item_bid;
                new_hover_elmt.cid = result.item.item_cid;
                break;
            }
            if (!this.hover_elmt || new_hover_elmt.paper_id !== this.hover_elmt.paper_id) {
              // console.log(`before setHoverElmt ${this.id}`);
              this.setHoverElmt(new_hover_elmt);
            }
            document.body.style.cursor = "pointer";
          } else {
            // console.log('move no result');
            this.resetHoverElmt();
            document.body.style.cursor = "auto";
          }
        }
      }.bind(this);
      
      this.paper_objects.onClick = function(event){
        console.log('paper concernement onClick');
        if (!this.is_opened) {
          if (!this.opened) {
            console.log(`Open me ${this.id}`);
            // open/close all concernements
            this.openCloseConcernements(this.id)
              // push route (keep the hash for map_mode)
            this.$router.push({
              name: 'concernement',
              hash: `#${this.map_mode}`,
              params: {id: this.id}
            });
            // reset the mousehover
            this.resetHoverElmt();
          }
        } else {
          // lets define some options regarding the map_mode
          // debugger;
          let op = {pg: null};
          switch (this.map_mode) {
            case "terraindevie":
              op = {
                pg: 'entites',  // paper group to hittest
              }
              break;
            case "action":
              op = {
                pg: 'agissantes', // paper group to hittest
              }
              break;
          }
          if (op.pg) {
            let result = this.paper_objects.children[op.pg].hitTest(event.point);
            // console.log('click result', result);
            if (result) {
              // we have clicked on an entite
              this.$router.push({
                name: 'concernement',
                hash: `#${this.map_mode}`,
                params: {id: this.opened.id, eid: result.item.item_id}
              });
            } else {
              // otherwise we close the entite and come back to the concernement
              this.$router.push({
                name: 'concernement',
                hash: `#${this.map_mode}`,
                params: {id: this.id}
              });
              // reset the mousehover
              this.resetHoverElmt();
            }
          }
        }
      }.bind(this);

    },
    resetHoverElmt(){
      // console.log('resetHoverElmt');
      setTimeout(()=>{
        this.setHoverElmt(null);
      }, 100);
    },
    openClose(open) {
      // console.log(`ConcernementsMapItem ${this.concernement.id} openClose: ${open}`);
      if (this.tween) {
        this.tween.stop();
      }
      if (open) {
        // paper bring to front
        this.paper_objects.bringToFront();
        // calcul opened size regarding window size
        // let ch = this.canvas.height;
        let s = this.canvas.height / (this.ray*2.8)
        // debugger;

        // opening tweening
        this.tween = new Tween.Tween({s: this.scale, x: this.pos.x, y: this.pos.y, o: 0})
          .to({
            s: s,
            x: (this.canvas.width - 450) / 2,
            y: this.canvas.height / 2,
            o: 0.8
          }, 800)
          .onUpdate((obj) => {
            // https://github.com/liabru/matter-js/issues/986#issuecomment-812488873
            // revert to the original size (by reverting the previous scale)
            Matter.Body.scale(this.body, 1 / this.scale, 1 / this.scale)
            this.paper_objects.scale(1 / this.scale);
            // then scale again to new scale
            Matter.Body.scale(this.body, obj.s, obj.s)
            this.paper_objects.scale(obj.s);

            // record new scale
            this.prev_scale = this.scale;
            this.scale = obj.s;
            this.opacity = obj.o;
            
            Matter.Body.setPosition(this.body, {x:obj.x, y:obj.y});
            this.pos = {x:obj.x, y:obj.y};
          })
          .onComplete((obj) => {
            this.constraint = Matter.Constraint.create({
              pointA: this.pos,
              bodyB: this.body,
              stiffness: 1,
              damping: 0,
              length: 0
            });
            Matter.Composite.add(this.matterEngine.world, [this.body, this.constraint]);
            this.prev_scale = this.scale;
          });
          // recreate the matter engine event to get it a the end of the events stack
          Matter.Events.off(this.matterEngine, "afterUpdate", this.onAfterEngineUpdate);
          Matter.Events.on(this.matterEngine, "afterUpdate", this.onAfterEngineUpdate);
      } else {
        // closing
        if(this.constraint){
          Matter.Composite.remove(this.matterEngine.world, this.constraint);
        }
        this.tween = new Tween.Tween({s: this.scale, o: 1})
          .to({s: 1, o: 0}, 500)
          .onUpdate((obj) => {
            // https://github.com/liabru/matter-js/issues/986#issuecomment-812488873
            // revert to the original size (by reverting the previous scale)
            Matter.Body.scale(this.body, 1 / this.scale, 1 / this.scale)
            this.paper_objects.scale(1 / this.scale);
            // then scale again to new scale
            Matter.Body.scale(this.body, obj.s, obj.s)
            this.paper_objects.scale(obj.s);
            
            // record new scale
            this.prev_scale = this.scale;
            this.scale = obj.s;
            this.opacity = obj.o;
          })
          .onComplete((obj) => {
            this.prev_scale = this.scale = 1;
          });
      }
      this.tween.easing(Tween.Easing.Quadratic.InOut).start();
    },
    // ENGINE UPDATE
    onBeforeEngineUpdate (event) {
      // update the opening/closing tweening
      if (this.tween) {
        this.tween.update();
      }

      if (this.opened) {
        if (this.opened.id !== this.id) {
          this.pushAside()
        }
      } else {
        // apply focus forces : move unfocused on the sides and focused on the center
        if (this.map_mode === 'action' 
          || this.map_mode === 'puissancedagir'
          || this.map_mode === 'doleancer'){
          this.applyFocusForces(); //
        }  
      }
      

      // reset all matter rotation forces otherwise items will spin when colide 
      Matter.Body.setAngle(this.body, 0);
      Matter.Body.setAngularSpeed(this.body, 0);
    },
    applyFocusForces(){
      if(!this.isFocused()) {
        this.pushAside()
      }else{
        this.bringToCenter()
      }
    },
    pushAside(){
      // apply a force in direction of one side or an other depending of the start position
      // the force is exponentialy proportional to the distance from the side
      let dir = this.pos.x > this.canvas.width/2 ? 1 : -1; // get the direction to the closest side
      let dist = (dir < 0 ? this.pos.x : this.canvas.width - this.pos.x); // get the distance from the side
      let ori_pos = {x:this.canvas.width/2, y:this.body.position.y};
      let x_force = Math.pow(dist/700,10) * dir;
      
      Matter.Body.applyForce(
        this.body, 
        ori_pos, 
        {
          x: x_force,
          y: 0
        }
      );
    },
    bringToCenter(){
      // bring to the centre
      let dir = this.pos.x > this.canvas.width/2 ? -1 : 1; // get the direction to the centre
      let dist = (dir < 0 ? this.pos.x - this.canvas.width/2 : this.canvas.width/2 - this.pos.x); // get the distance from the side
      let ori_pos = dir < 0 ? {x:this.canvas.width, y:this.body.position.y} : {x:0, y:this.body.position.y}
      let x_force = Math.pow(dist/800,10) * dir;
      
      this.body.frictionAir = 0.05;

      Matter.Body.applyForce(
        this.body, 
        ori_pos, 
        {
          x: x_force,
          y: 0
        }
      );
    },
    applyShuffleForces() {
      var dist, dir, x_velocity;
      dir = this.pos.x > this.canvas.width/2 ? -1 : 1; // get the direction to the centre
      dist = (dir < 0 ? this.pos.x - this.canvas.width/2 : this.canvas.width/2 - this.pos.x); // get the distance from the side
      x_velocity = Math.pow(dist/650,10) * dir;

      Matter.Body.setVelocity(this.body, {x: x_velocity, y: 0});
    },
    onAfterEngineUpdate (event) {
      // respawn element if outside screen
      // if(this.pos.x < 0
      //   || this.pos.x > this.canvas.width
      //   || this.pos.y < 0
      //   || this.pos.y > this.canvas.height){
      //     this.pos = this.getRandomPos()
      //     Matter.Body.setPosition(this.body, {x:this.pos.x, y:this.pos.y});
      //     this.setInitBodyVelocity();
      //   }
      
      this.paper_objects.position = this.pos = this.body.position;

      // this.draw()
      this.handlePaperVisibility()
    },
    // PAPER VISIBILITY
    handlePaperVisibility(){
      // contours focused
      if (!this.isFocused()){
        this.paper_objects.children['contours'].fillColor = "rgba(255,255,255,0.3)";
      }else{
        this.paper_objects.children['contours'].fillColor = "rgba(255,255,255,0.8)";
        if (this.is_hover) {
          this.paper_objects.children['contours'].strokeColor = "#01ffe2";
          this.paper_objects.children['contours'].strokeWidth = 2;
        }else{
          this.paper_objects.children['contours'].strokeColor = null;
          this.paper_objects.children['contours'].strokeWidth = 0;
        }
      }

      // contours visibility
      if (!this.is_opened 
        || (this.is_opened && this.map_mode !== "puissancedagir" && this.map_mode !== "doleancer")) {
        this.paper_objects.children['contours'].visible = true;
      } else {
        this.paper_objects.children['contours'].visible = false;
      }

      // backgrounds
      if (this.is_opened) {
        // hide all bgs
        this.paper_objects.children.boussole_bg.visible = false;
        if (this.concernement.has_puissancedagir) {
          this.paper_objects.children.puissanceagir_bg.visible = false;
        }
        if (this.concernement.has_doleance) {
          this.paper_objects.children.doleance_bg.visible = false;
        }
        // choose wich one to show, if one
        switch (this.map_mode) {
          case 'terraindevie':
            this.paper_objects.children.boussole_bg.visible = true;
            break;
          case 'puissancedagir':
            if (this.concernement.has_puissancedagir) {
              this.paper_objects.children.puissanceagir_bg.visible = true;
            }
            break;
          case 'doleancer':
            if (this.concernement.has_doleance) {
              this.paper_objects.children.doleance_bg.visible = true;
            }
            break;
        }
      }else{
        this.paper_objects.children.boussole_bg.visible = false;
        if (this.concernement.has_puissancedagir) {
          this.paper_objects.children.puissanceagir_bg.visible = false;
        }
        if (this.concernement.has_doleance) {
          this.paper_objects.children.doleance_bg.visible = false;
        }
      }

      // entites
      if (this.is_opened
        && this.map_mode !== 'puissancedagir'
        && this.map_mode !== 'doleancer' 
        && this.map_mode !== 'action' ) {
          this.paper_objects.children.entites.visible = true;
          // if (this.opened_entite_id) {
          //   // console.log('this.paper_objects.children.entites', this.paper_objects.children.entites);
          //   this.paper_objects.children.entites.children.forEach((entite) => {
          //     // console.log('entite', entite);
          //     if (entite.item_id === this.opened_entite_id) {
          //       entite.style.fillColor = '#01ffe2';
          //     } else {
          //       entite.style.fillColor = '#000';
          //     }
          //   });
          // } else {
          //   this.paper_objects.children.entites.children.forEach((entite) => {
          //     entite.style.fillColor = '#000';
          //   })
          // }
      } else {
        this.paper_objects.children.entites.visible = false;
      }


      // puissance d'agir     
      if (this.concernement.has_puissancedagir) {
        if (this.map_mode === "puissancedagir") {
          if (!this.is_opened) {
            this.paper_objects.children.puissanceagir_icon.visible = true; // if not opened and has_puissancedagir draw the puissance d'agir icone
            this.paper_objects.children.puissanceagir_besoins.visible = false;
          } else {
            this.paper_objects.children.puissanceagir_icon.visible = false;
            this.paper_objects.children.puissanceagir_besoins.visible = true;
            // this.drawBesoins();
          }
        } else {
          this.paper_objects.children.puissanceagir_icon.visible = false;
          this.paper_objects.children.puissanceagir_besoins.visible = false;
        }
      }

      // agissantes
      // console.log('this.concernement.has_agissantes', this.concernement.has_agissantes);
      if (this.concernement.has_agissantes) {
        if (this.map_mode === "action") {
          this.paper_objects.children.agissantes.visible = true;
        } else {
          this.paper_objects.children.agissantes.visible = false;
        }  
      }
      
      // doleance     
      if (this.concernement.has_doleance) {
        if (this.map_mode === "doleancer") {
          if (!this.is_opened) {
            this.paper_objects.children.doleance_icon.visible = true;
            this.paper_objects.children.doleance_steps.visible = false;
          } else {
            this.paper_objects.children.doleance_icon.visible = false;
            this.paper_objects.children.doleance_steps.visible = true;
          }
        } else {
          this.paper_objects.children.doleance_icon.visible = false;
          this.paper_objects.children.doleance_steps.visible = false;
        }
      }
    
    },
    isFocused(){
      return this.map_mode === 'terraindevie'
          || (this.map_mode === 'action' && this.concernement.has_agissantes)
          || (this.map_mode === 'puissancedagir' && this.concernement.has_puissancedagir)
          || (this.map_mode === 'doleancer' && this.concernement.has_doleance);
    },
  },
  render() {
    // console.log('render()', this.ctx);
  },
}

</script>