actors types {
  acteurCamera , utilisateurCarte, acteurTrigger, acteurManipulateurMusee
}
modules types { PsEntiteVisiteur2 }

scenario psy
(
  acteurCamera * camera,
  acteurManipulateurMusee * manipulateur,
  acteurManipulateurMusee * utilisateur
)
{
  include {
    #include "acteurCamera.h"
    #include "acteurTrigger.h"
    #include "variableTableId.h"
    #include "utilisateurCarte.h"
    #include "acteurManipulateurMusee.h"
  };
  declaration {
    variableTableId _table;
    ensembleActeur _visiteurs;
    ensembleActeur _vert1;
    ensembleActeur _vert2;
    ensembleActeur _boucleVisite1;
    ensembleActeur _fond1;
    ensembleActeur _fond2;
    ensembleActeur _tamponV1;
    ensembleActeur _tamponV2;
    ensembleActeur _tamponF1;
    ensembleActeur _tampon2F1;
    ensembleActeur _tamponF2;
    ensembleActeur _tampon2F2;
    ensembleActeur _vertTous;
  };
  c++ { camera -> setPosition(0,100,0,-90,0,0); };
  use creationHumanos(&_fond1,&_table,"F1",2,"-8","11",0);
  use creationHumanos(&_fond2,&_table,"F2",2,"-2","14",0);

  use creationHumanos(&_vert1,&_table,"V",2,"23","8",0);
  use creationHumanos(&_vert1,&_table,"W",2,"21","4",0);
  use creationHumanos(&_vert2,&_table,"X",2,"23","0",0);
  use creationHumanos(&_vert2,&_table,"Y",2,"21","-2",0);

  c++ {
    _vertTous = _vert1 || _vert2;
    _tamponV1 = _vert1; _tamponV2 = _vert2;
    _tamponF1 = _fond1; _tampon2F1 = _fond1;
    _tamponF2 = _fond2; _tampon2F2 = _fond2;
  };

  use ordre(
    &_vert1,
    &_vert2,
    &_visiteurs,
    &_fond1,
    &_fond2,
    manipulateur,
    utilisateur,
    &_boucleVisite1,
    &_tamponV1, &_tamponV2,
    &_tamponF1, &_tampon2F1,
    &_tamponF2, &_tampon2F2,
    &_vertTous
  );

}

scenario ordre(
  ensembleActeur * vert1,
  ensembleActeur * vert2,
  ensembleActeur * visiteurs,
  ensembleActeur * fond1,
  ensembleActeur * fond2,
  acteurManipulateurMusee * manipulateur,
  acteurManipulateurMusee * utilisateur,
  ensembleActeur * boucleVisite1,
  ensembleActeur * tamponV1,
  ensembleActeur * tamponV2,
  ensembleActeur * tamponF1,
  ensembleActeur * tampon2F1,
  ensembleActeur * tamponF2,
  ensembleActeur * tampon2F2,
  ensembleActeur * vertTous
)
{
  instance robot of manipulationRobot(manipulateur);
  instance visite1 of visiteSurveillee(
    visiteurs,3,74,-4,boucleVisite1,boucleVisite1
  );
  instance surveillance1 of attendManipulateur(utilisateur,20,0,60);
  instance surveillance2 of attendManipulateur(utilisateur,0,-15,70);
  instance surveillance3 of attendManipulateur(utilisateur,0,-15,10);
  instance surveillance4 of attendManipulateur(utilisateur,60,0,50);
  instance debutVert1 of geneurZone(23,6,vert1,4,tamponV1,false,2);
  instance debutVert2 of geneurZone(23,-4,vert2,4,tamponV2,false,2);
  instance geneVert1a of geneurZone(80,4,tamponV1,4,boucleVisite1,true,3);
  instance geneVert2a of geneurZone(80,-4,tamponV2,4,boucleVisite1,true,3);
  instance geneVert1b of geneurZone(23,4,vertTous,4,vert1,false,4);
  instance geneVert2b of geneurZone(23,-4,vertTous,4,vert2,false,4);
  instance debutFond1 of geneurZone(-4,11,fond1,2,tamponF1,false,2);
  instance debutFond2 of geneurZone(0,14,fond2,2,tamponF2,false,2);
  instance geneFond1a of geneurZone(24,6,tamponF1,2,tamponF1,false,3);
  instance geneFond1b of geneurZone(20,6,tamponF1,2,tamponF1,false,3);
  instance geneFond2 of geneurZone(12,12,tamponF2,2,tamponF2,false,3);
  instance geneFond1Retour of geneurZone(3,15,tampon2F1,2,tampon2F1,false,4);
  instance geneFond2Retour of geneurZone(1,16,tampon2F2,2,tampon2F2,false,4);
  schedule {
    start of robot equals start of visite1;

    start of debutVert1 equals start of visite1;
    start of debutVert2 equals start of visite1;

    start of surveillance1 equals start of visite1;
    surveillance1 meets geneVert1a;
    surveillance1 meets geneVert2a;

    surveillance1 meets surveillance2;
    surveillance2 meets geneFond1a;
    geneFond1a meets geneFond1b;
    surveillance2 meets geneFond2;

    surveillance2 meets surveillance3;
    surveillance3 meets geneFond1Retour;
    surveillance3 meets geneFond2Retour;

    surveillance3 meets surveillance4;
    surveillance4 meets geneVert1b;
    surveillance4 meets geneVert2b;
  };
}

scenario manipulationRobot(
  acteurManipulateurMusee * manipulateur
)
{
  include { #include "acteurManipulateurMusee.h" };

  on butAtteind(acteurManipulateurMuseeGenere * emetteur,float x, float z)
  from actor manipulateur type acteurManipulateurMusee
  { _surBut = true; };

  declaration { bool _surBut; };

  c++ {
    manipulateur -> bougeVers(20,-7);
    _surBut = false;
  };
  waitfor (_surBut);
  c++ {
    manipulateur -> bougeVers(-0.5,-16);
    _surBut = false;
  };
  waitfor (_surBut);
  c++ {
    manipulateur -> bougeVers(0,-19);
    _surBut = false;
  };
  waitfor (_surBut);
  c++ {
    manipulateur -> switchManipulation("cible");
    manipulateur -> bougeVers(20,-7);
    _surBut = false;
  };
  waitfor (_surBut);
  wait(1),
  c++ {
    _surBut = false;
    manipulateur -> bougeVers(70,-1);
  };
  waitfor (_surBut);
  c++ {
    manipulateur -> switchManipulation("cible");
    manipulateur -> bougeVers(60,0);
  };
}

scenario creationHumanos(
  ensembleActeur * visiteurs,
  variableTableId * table,
  const char * lettre,
  int nombre,
  std::string positionX,
  std::string positionZ,
  int oeuvreCourante
)
{
  include {
    #include "utilisateurCarte.h"
    #include "variableTableId.h"
    #include "ensembleActeur.h"
  };
  declaration {
    std::string _nom;
    std::string _geometrie;
    utilisateurCarte * _nouveau;
    int _i;
  };

  c++ {
    _nom ="visiteur_"+std::string(lettre);
    _geometrie = "modifVisu/humanoEric.iv";
    _i = 0;
  };
  repeat {
    use creationUnHumano(
      &_nouveau,
      table,
      _nom,
      positionX, positionZ,
      _geometrie,
      oeuvreCourante
    );
    c++ {
      acteurComRes * ancetre = dynamic_cast<acteurComRes *>(_nouveau);
      visiteurs->insert(ancetre);
      _i++;
      _nom +=std::string(lettre);
    };
  } until (_i>=nombre);
}

scenario visiteSurveillee(
  ensembleActeur * ptrEnsVisiteurs, //l'ensemble des gens qui font la visite
  int nombreOeuvres,
  float xDepart, float zDepart,
  ensembleActeur * ptrEnsEntrees,
  ensembleActeur * ptrEnsSorties
)
{
  include {
    #include "utilisateurCarte.h"
    #include "ensembleActeur.h"
    #include "math.h"
  };
  declaration {
    bool _evt;
    ensembleActeur _arrives;
    ensembleActeur _recommence;   //qui vont au debut de la visite
    ensembleActeur _ensVisiteurs; //qui suivent la visite actuellement
    bool _debutOk;
  };
// demarrage --------------------------------------------------------
  c++ {
    _evt = false;
    _ensVisiteurs = *ptrEnsVisiteurs;
  };
  reserve (
    from _ensVisiteurs to _ensVisiteurs
    count(_ensVisiteurs.size()) priority(1)
  )
  {
    success { _debutOk = true; }
    failure {
      cout<<"ATTENTION !!!!! Pb reservation initiale"<<endl;
      _debutOk = false;
    }
  };
  if (_debutOk)
  {
    // evt de communication avec scenario voleur ---------------------
    on confiscation(acteurComRes * acteurConfisque)
    {
      _ensVisiteurs = _ensVisiteurs - acteurConfisque;
      _recommence = _recommence - acteurConfisque;
      ptrEnsVisiteurs->erase(acteurConfisque);
    };

    //passage d'oeuvre en oeuvre et maj des sorties -------------------
    on debutRegarde(utilisateurCarteGenere * emetteur)
    from type utilisateurCarte
    {
      _evt = true;
      acteurComRes * ancetre = dynamic_cast<acteurComRes *>(emetteur);
      _arrives = _arrives || ancetre;
    };

    eachtime(_evt)
    {
      forall visiteur type ptrUtilisateurCarte in _arrives
      {
        acteurComRes * ancetre = dynamic_cast<acteurComRes *>(visiteur);
        if (_ensVisiteurs.find(ancetre) != _ensVisiteurs.end())
        {
          if ((visiteur -> getNbOeuvres()) >= nombreOeuvres)
          {
            visiteur -> razNbOeuvres();
            ptrEnsSorties->insert(ancetre);
            _ensVisiteurs.erase(ancetre);
          }
        }
      };
      free(*ptrEnsSorties);
      c++ {
        _arrives = ensembleActeur();
        _evt = false;
      };
    };

    //------------ verifier les entrees -------------------------------
    declaration {
      ensembleActeur _ensEntrees;
      bool _resEnCours;
    };
    c++ { _resEnCours = true; };
    eachtime(ptrEnsEntrees->size() > 0)
    {
      c++ { _ensEntrees = *ptrEnsEntrees; };
      reserve (
        from _ensEntrees to _ensEntrees count(_ensEntrees.size()) priority(1)
      )
      {
        success { _resEnCours = true; }
        failure {
          _resEnCours = false;
          cout<<"ERREUR !!!!! Pb reservation en cours de scenario"<<endl;
        }
      };
      if (_resEnCours)
      {
        forall visiteur type ptrUtilisateurCarte in _ensEntrees
        {
          acteurComRes * ancetre = dynamic_cast<acteurComRes *>(visiteur);
          visiteur -> razNbOeuvres();
          visiteur -> vaJusque(xDepart,zDepart);
          _recommence = _recommence || ancetre;
          ptrEnsEntrees->erase(ancetre);
          ptrEnsVisiteurs->insert(ancetre);
        };
      }
      else { _resEnCours = true; };
    };
    //----------- amener jusqu'au point de depart
    on positionAtteinte(utilisateurCarteGenere * emetteur,float x,float z)
    from type utilisateurCarte
    {
      acteurComRes * ancetre = dynamic_cast<acteurComRes *>(emetteur);
      ensembleActeur  diff = _recommence - ancetre;
      if (diff != _recommence)
      {
        if ( pow((xDepart - x),2) + pow((zDepart - z),2) <= 2*2)
        {
          _recommence = diff;
          _ensVisiteurs.insert(ancetre);
          emetteur -> stop();
        }
        else { emetteur -> vaJusque(xDepart,zDepart); }
      }
    };
    //-------- bouchon --------------------------------------------
    waitfor(false);
  }; //fin du if(_debutOk}
}

scenario geneurZone(
  float xBut, float zBut,
  ensembleActeur * ptrEnsVisiteurs,
  int nombreDemande,
  ensembleActeur * ptrEnsRetour,
  bool retourner,
  int priorite
)
{
  include {
    #include "ensembleActeur.h"
    #include "utilisateurCarte.h"
  };

  declaration {
    ensembleActeur _visiteurs;
    ensembleActeur _reserves;
    int _nombre;
    bool _enCours;
  };

  //--------- reservation des humanos
  c++ {
    _nombre = ptrEnsVisiteurs->size();
    if (_nombre > nombreDemande) { _nombre = nombreDemande; }
    _visiteurs = *ptrEnsVisiteurs;
    _enCours = true;
  };
  reserve(
    from _visiteurs to _reserves count (_nombre) priority (priorite)
  )
  {
    success {}
    failure {
      PsnControleur::erreur("Echec de reservation dans geneur zone");
    }
  };
  forall visiteur in _reserves
  { ptrEnsVisiteurs -> erase(dynamic_cast<acteurComRes *>(visiteur)); };

  //-------- deplacement jusque tout le monde arrive ou fini
  on confiscation(acteurComRes * visiteur)
  {
    _reserves.erase(dynamic_cast<acteurComRes *>(visiteur));
    _nombre--;
  };
  aslongas (_nombre>0 && _enCours)
  {
    use deplaceurEnsemble(&_reserves,xBut,zBut);
    c++ { _enCours = false; };
  };

  //----------- terminer en relachant
  forall visiteur type ptrUtilisateurCarte in _reserves
  {
    if (retourner) { visiteur -> stop(); }
    ptrEnsRetour->insert(dynamic_cast<acteurComRes *>(visiteur));
  };
  free (_reserves);
}

scenario deplaceurEnsemble
(
  ensembleActeur * entree,
  float xBut, float zBut
)
{
  include {
    #include "ensembleActeur.h"
    #include "utilisateurCarte.h"
  };
  declaration {
    int _nombre;
    int _cpt;
    ensembleActeur _entree;
  };

//----------  init
  c++ {
    _nombre = entree->size();
    _cpt = 0;
    _entree = *entree;
  };
// --------- deplacement
  forall humano type ptrUtilisateurCarte in _entree
  {
     humano -> vaJusque(xBut,zBut);
  };
// ---------- comptage des arrivees et relance eventuelle
  on positionAtteinte(utilisateurCarteGenere * emetteur,float x,float z)
  from type utilisateurCarte
  {
    acteurComRes * ancetre = dynamic_cast<acteurComRes *>(emetteur);
    if (_entree.find(ancetre) != _entree.end())
    {
      if ( (pow((xBut - x),2) + pow((zBut - z),2)) > (2*2))
      {
        emetteur -> vaJusque(xBut,zBut);
      }
      else { _cpt++; }
    }
  };
// ---------- attente de fini
  waitfor(_cpt == _nombre);
}

scenario attendManipulateur(
  acteurManipulateurMusee * manipulateur,
  float xCentre, float zCentre, float rayon
)
{
  include { #include "acteurManipulateurMusee.h" };
  declaration { bool _entree; };
//-------- init
  c++ {
    _entree = false;
    manipulateur -> surveillePosition(xCentre,zCentre,rayon);
  };
//------- attente
  on entreEnZone( acteurManipulateurMuseeGenere * emetteur, float x, float z)
  from actor manipulateur type acteurManipulateurMusee
  { _entree = true; };
 
  waitfor(_entree);
//-------- on desactive la surveillance en finissant
  destructor { manipulateur -> arreteSurveille(); };
}