// Ce fichier contient deux petit fichier cc (.h et .cc) définissant
// la classe Unit

////////////////////////////////////////////////////////////////////////
// 
// classe Unit  (Declarations)
//
// 
// 
// La classe Unit servira de classe de base pour les Unit standards
// (disponibles en stock) "UnitS" , pour les Unit achetés ou potentiellement
// achetables ("UnitB") ou peut-etre les Unit louées "UnitR" si Benoit
// insiste :-).
// 
// 
// Information CVS :
// 
// $Id: cc_petit.cc,v 1.1.1.1 2000/09/19 10:50:09 diam Exp $
// $Name:  $
// 
////////////////////////////////////////////////////////////////////////

/* 
 Essai de commentaire type C
 La classe Unit servira de classe de base pour les Unit standards
 (disponibles en stock) "UnitS" , pour les Unit achetés ou potentiellement
 achetables ("UnitB") ou peut-etre les Unit louées "UnitR" si Benoit
 insiste :-).
*/ 

#define POPO  /* autre commaire type C */
#ifndef UNIT_H
#define UNIT_H

#include "external.h"

#include "declarations.h"

#include "util.h"
#include "trans.h"
#include "state.h"
#include "resourcetype.h"
#include "constraint.h"


class Unit {

// "friend" en premier
   
friend 
  ostream& operator<< (ostream& os, Unit const & t) ; 

public:
    
    // l'entier identifiant une Unit
    int uid;
    
    // nom de l'objet : contiendra par exemple "r2_uid3_buy"
    string name;

    // Pour accéder au info de la ressource a partir d'une unité
    ResourceType* p_rt;

    // vrai si cette unité est figée pour la relaxation
    bool is_frozen;
    bool is_frozen_SAVED;

    // date d'achat (sans signification pour une Unit Standard ou de 
    // location). 
    // 
    //   vaut -1 egalement pour une unite standard (car déja dispo en stock)
    //   Vaut -1 pour une unite achetable, mais pas encore achetee,
    //           (Dans ce dernier cas, j'aurais prefere (EndTime + 1) , mais 
    //           cela necessiterait d'avoir acces au attribut de l'objet de 
    //           la classe Bench.)
    int buyingDate;
    
    // pour identifier le type d'objet reellement associé à cet état
    // typedef enum kindType {
    //    std  =  0,
    //    buy  =  1,
    // } kindType ;
    typedef enum {
       std  =  0,
       buy  =  1
    } kindType ;
    kindType kind ;


    ////////////////////////////////////////////////////////////////////
    // constructeurs complet
    Unit (
       kindType       kind, 
       int            uid, 
       ResourceType*  p_rt, 
       int            buyingDate = -1
    );
    
    ////////////////////////////////////////////////////////////////////
    // Destructeur complet
    ~Unit();
    
    ////////////////////////////////////////////////////////////////////
    // representation chaine du "typë de l'unité (std, buy, ...)
    string get_kind() const;

    ////////////////////////////////////////////////////////////////////
    // Calcul du cout réel en fonction de la liste des transitions
    // franchies (exploration du path pccPath)
    int get_realCost() const;

    ////////////////////////////////////////////////////////////////////
    // Calcul du cout total modifié en fonction de la liste des 
    // transitions franchies et du cout perturbé affecté à chaque 
    // transition (obtenu par la lecture du tableau 
    // na_dist[node relatif au endState de la resourceType associée]
    double get_pathCost() const;

    ////////////////////////////////////////////////////////////////////
    // gestion de l'attribut buyingDate
    inline int get_buyingDate() {
        return buyingDate;
    };
    inline int set_buyingDate(int date) {
        return buyingDate=date;
    };
    
    ////////////////////////////////////////////////////////////////////
    // pour savoir si une unité était dans stock initiale.
    // (par opposition à achetable)
    // 
    // ATTENTION 
    // 
    //    La version inline utilisant un attribut de p_rt ne compile pas
    //    à cause de la définition provisoire de la ResourceType :
    //        invalid use of undefined type `struct ResourceType'
    //    
    //    inline bool is_standardKind() {
    //        return (uid <= p_rt->stock);
    //    };
    
    inline bool is_stdKind() {
        return (kind == std);
    };
    inline bool is_buyKind() {
        return (kind == buy);
    };
    
    
    ////////////////////////////////////////////////////////////////////
    // Calcul du chemin minimum de l'unité dans le graphe correspondant
    // au type de ressource de cette unité, et compte tenu du tableau 
    // des points des arêtes passé en parametre.
    // 
    // - retourne le cout réel de cette unité,
    // - met à jour toutes les listes relatives à ce pcc (par appel à
    //   update_pccInfos),
    
    void update_shortestPath();
    
    ////////////////////////////////////////////////////////////////////////
    // Mise à jour les attributs secondaires relatifs au PCC à partir
    // de l'attribut principal  pccPath :
    // 
    // 1 - Les listes relatives aux états traversés :
    // 
    //     - pccPath
    //     - lp_pccStates
    //     - lp_pccMaintStates
    //     - lp_pccOrders
    // 
    // 2 - Les listes relatives CUS (Sequence d'utilisations continues) :
    // 
    //     - llp_cusOrderss : liste de liste des ordres appartenant à
    //       une meme CUS (peut contenir des CUS ne concernant qu'un
    //       seul ordre qui n'apparait donc pas dans les listes
    //       suivantes. 
    //     - l_cusPaths : liste de toutes les CUS (formé des transitions
    //       d'ordre à ordre : donc une CUS le longueur 1 concerne deux
    //       ordres. 
    //     - l_longCusPaths : liste des CUS dont la durèe d'utilisation
    //       excéde la longueurs maximal d'utilisation.
    //         
    void update_pccInfos(Path const & onePccPath);
    // idem, mais utilise le pccPath courant de l'unitée
    void update_pccInfos();
    
    // Affiche les transitions traversées par le plus court chemin, et 
    // leur cout
    void print_pathInfos(ostream& os = cout);
    
    ////////////////////////////////////////////////////////////////////////
    // Initialise les tableaux utilisés par l'algo Dijkstra en fonction
    // du graphe de vie de la ressource de cette unité
    // A ne lancer qu'une seule fois APRES la construction du graphe
    // (c'est pour cette raison que cette méthode ne peut pas être incorporée
    // au constructeur).

    void initGraphArray();
    
    // les 6 listes liées au chemin minimum de l'unité : 
    
    // liste des transitions utilisées
    Path                    pccPath;
    // Version prévue pour la restauration sans avoir à refaire les PCC
    Path                    pccPath_SAVED;
    // Meilleure solutions trouvée (en fonction de la bestBorneSup)
    Path                    pccPath_BEST;

    // Liste des états du PCC (SANS les 3 pseudo-états)
    list<State*>       lp_pccStates;

    // Liste des états de maintenance du PCC
    list<State*>       lp_pccMaintStates;

    // Liste des ordres affectés par le PCC
    list<Order*>       lp_pccOrders;

    // Liste des Sequences Continue d'Utilisation du PCC 
    // (ne contient QUE des transitions d'ordre à ordre)
    list<Path>                  l_cusPaths;
    // Sous liste des CUS dont la durée d'utilisation excède utime
    list<Path>                  l_longCusPaths;
    // Liste des Sequences Continue d'Utilisation du PCC (les états d'ordre)
    list<list <Order*> >   llp_cusOrderss;

    // Calcul de l'excédent d'utilisation (xTime) par rapport à utime
    // du type de ressource de cette unité en fonction de la
    // Séquence d'Utilisation Complète CUS passée en parametre
    // (que ce soit par cusPath ou par lp_cusOrders)
    // 
    // En l'abscence de dépassement, on retourne une valeur >= 0
    // 
    int get_xtime (Path & cusPath)                       const;
    int get_xtime (list<Order*> & lp_cusOrders)     const ;
    
    // Variante qui calcul du **cumul** des l'excédent d'utilisation (xTime) 
    // pour toutes les CUS du PCC (Plus Court Chemin) courant.
    // 
    int get_xtime () const ;  // prend le PCC courant de cette unité

    ////////////////////////////////////////////////////////////////////
    // Ces tableaux seront utilisés par l'algo Dijkstra
    // il seront initialisé une seul fois apres la création des graphes 
    // de ressource.
    
// //     // tableau du cumul des distances calculées par Dijkstra
// //     leda_node_array<double>     na_dist;
// //     
// //     // tableau des prédécesseurs dans le plus court chemin
// //     leda_node_array<leda_edge>  na_pred;
// // 
// //     // tableau des poids initial pour chaque edge du graphe.
// //     leda_edge_array<double>     ea_initialCosts;
// // 
// //     // tableau des poids variables pour chaque edge du graphe.
// //     leda_edge_array<double>     ea_costs;
// // 
// //     ////////////////////////////////////////////////////////////////////
// //     // liste des contraintes c5 de cette unité (utime limité)
// //     leda_list<ConstraintC5*>      lp_constraintC5s;
    
    ////////////////////////////////////////////////////////////////////
    // 
    
    // Méthodes de comparaison d'unités
    // 
    
    // Permet de comparer des liste de pointeurs d'unités en fonction
    // du cout reel de leur chemin
    // 
    // PRECONDITION : le PCC (variable pccPath) doit être à jour
    // 
    static int compareOnReverse_realCost (
                Unit* const & p_u1, 
                Unit* const & p_u2
    );
    
};

////////////////////////////////////////////////////////////////////////
// Idée à évaluer l'intérêt : créer des classes dérivées suivantes :
//     - UnitS (unités Standards)
//     - UnitB (unités achetées)
// celle-ci devront implémenter des méthodes vituelles de la classe 
// de base Unit
////////////////////////////////////////////////////////////////////////


#endif



////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// 
// classe Unit  (Implementation)
//
// 
// 
// Information CVS :
// 
// $Id: cc_petit.cc,v 1.1.1.1 2000/09/19 10:50:09 diam Exp $
// $Name:  $
// 
////////////////////////////////////////////////////////////////////////


#include "unit.h"

// Le constructeur avec parametres :
Unit::Unit (
    kindType         local_kind, 
    int              local_uid, 
    ResourceType*    local_p_rt, 
    int              local_buyingDate
) {

    // Affectation du type d'état (attribut kind)
    switch (local_kind) {
    
        case std :
        
        case buy :
           kind = local_kind;
           break;
           
        default: 
           cerr << "erreur : type d'etat non autorisé : " 
                << local_kind 
                << endl;
           exit(1);
           
    }; //endswitch   
     
    uid =             local_uid;
    p_rt =            local_p_rt;
    is_frozen =       false;
    is_frozen_SAVED = false;
    buyingDate =      local_buyingDate;
    
    // Construction la la chaine de caractere nom (exprérimental)
    ostrstream  myStream;
    myStream << "r" 
             << p_rt->rid 
             << "_uid" 
             << uid 
             << "_" 
             << get_kind()
             << ends ;
    name = myStream.str();

};
////////////////////////////////////////////////////////////////////////
// Le destructeur
Unit::~Unit () {
};

////////////////////////////////////////////////////////////////////////
ostream& operator<< (ostream& os, Unit const & u) {

    os << "=> " 
       << setiosflags(ios::left) << setw(13)
       << u.name 
       << " (" 
       << &u 
       << ") ";
    os << " buyingDate =  " << u.buyingDate  
       << endl ;
       
    return os;
}; 

////////////////////////////////////////////////////////////////////////
string Unit::get_kind() const {

    switch (kind) {
     
        case std  : return string("std");
        case buy  : return string("buy");
        
        default: 
           cerr << "erreur : type d'etat inconnu : " << kind << endl;
           exit(1);
           
    }; //endswitch
};

// // ////////////////////////////////////////////////////////////////////////
// // // 
// // int Unit::get_realCost() const {
// // 
// //     int totalCost = 0;
// //     Trans* p_tr;
// //     
// //     forall(p_tr, pccPath) {
// //        totalCost += p_tr->realCost;
// //     };
// //     return totalCost;
// // };
// // ////////////////////////////////////////////////////////////////////////
// // // 
// // double Unit::get_pathCost() const {
// //     
// //     // // Ceci est la seule utilisation de na_dist !
// //     // // INCONVENIENT : IL FAUT FAUT QUE LE DERNIER PCC CORRESPONDE AU LAMBDA
// //     // return na_dist[p_rt->p_endState->v];
// // 
// //     // On peut se passer de na_dist 
// //     // AVANTAGE : UTILISATION APRES RESTORATION DES ATTRIBUT DU PCC
// //     // (sans avoir à refaire les PCC)
// //     double totalCost = 0;
// //     Trans* p_trans;
// //     
// //     forall(p_trans, pccPath) {
// //        totalCost += ea_costs[p_trans->e];
// //     };
// //     return totalCost;
// // };
// // 
// // ////////////////////////////////////////////////////////////////////////
// // // Initialise les tableaux utilisés par l'algo Dijkstra en fonction
// // // du graphe de vie de la ressource de cette unité
// // // 
// // void Unit::initGraphArray() {
// // 
// //     // déclaration d'un alias pour alléger l'ecriture
// //     GRAPH<State*,Trans*> & gr = *p_rt->p_graph;
// // 
// //     // init du tableau des distances du chemin
// //     na_dist.init(gr);
// //        
// //     // init du tableau des prédécesseurs dans le plus court chemin
// //     na_pred.init(gr);
// //        
// //     // init du tableau des lambda de chaque transition
// //     // ea_lambda.init(gr);
// // 
// //     // // init du tableau des lambda de la contrainte 
// //     // // C5 PAS UTILISE POUR L'INSTANT
// //     // ea_c5costs.init(gr);
// // 
// //     // init des tableau de coût,
// //     ea_initialCosts.init(gr);
// //     ea_costs.init(gr);
// // 
// // }
// // 
// // ////////////////////////////////////////////////////////////////////////
// // // Calcul du chemin minimum de l'unité dans le graphe correspondant
// // // 
// // void Unit::update_shortestPath() {
// // 
// //     // déclaration d'un alias pour alléger l'ecriture
// //     GRAPH<State*,Trans*> & gr = *p_rt->p_graph;
// //             
// //     leda_node destNode =   p_rt->p_endState->v;
// //     leda_node sourceNode = nil;
// //     
// //     switch (kind) {
// //         case std : 
// //            sourceNode = p_rt->p_startState->v;
// //            break;
// //         case buy : 
// //            sourceNode = p_rt->p_vendorState->v;
// //            break;
// //     }; //endswitch
// //     
// // 
// //     // L'algo DIJKSTRA de la librairie LEDA nécessite des arcs positifs
// //     // On utilise donc l'algo BELLMAN, moins efficace, mais qui peut 
// //     // travailler avec des poids négatifs
// //     // 
// //     // Entrées :
// //     //     gr : graph au sens leda
// //     //     ea_costs : tableau des coût pour chaque arc du graphe
// //     // 
// //     // Sorties (par référence) :
// //     //     na_dist : tableau des distances (CUMUL OU NON ???)
// //     //           par rapport au noeud source (NON UTILISE !!)
// //     //     na_pred : donne l'arc prédécesseur pour chaque noeud du graphe
// //     // 
// //     
// //     // DIJKSTRA(gr, sourceNode, ea_costs, na_dist, na_pred);
// //     BELLMAN_FORD(gr, sourceNode, ea_costs, na_dist, na_pred);
// //     
// //     // Construction du plus court chemin
// //     Path localPccPath;
// // 
// //     leda_node v = destNode;
// //     leda_edge e;
// //     while (v != sourceNode) {
// //               
// //        // on mémorise le edge et la transition correspondante
// //        e = na_pred[v];
// //        localPccPath.push_front(gr[e]);
// //        
// //        // On continue avec le noeud plus proche
// //        v = gr.source(e);
// //     }
// //     
// //     // Mise à jour des attribut relatif à ce chemin
// //     update_pccInfos(localPccPath);
// //     
// // }
// // 
// // ////////////////////////////////////////////////////////////////////////
// // // Mise à jour les attributs secondaires relatifs au PCC à partir
// // // de l'attribut principal  pccPath :
// // // 
// // // 1 - Les listes relatives aux états traversés :
// // // 
// // //     - pccPath
// // //     - lp_pccStates
// // //     - lp_pccMaintStates
// // //     - lp_pccOrders
// // // 
// // // 2 - Les listes relatives CUS (Sequence d'utilisations continues) :
// // // 
// // //     - llp_cusOrderss : liste de liste des ordres appartenant à
// // //       une meme CUS (peut contenir des CUS ne concernant qu'un
// // //       seul ordre qui n'apparait donc pas dans les listes
// // //       suivantes. 
// // //     - l_cusPaths : liste de toutes les CUS (formé des transitions
// // //       d'ordre à ordre : donc une CUS le longueur 1 concerne deux
// // //       ordres. 
// // //     - l_longCusPaths : liste des CUS dont la durèe d'utilisation
// // //       excéde la longueurs maximal d'utilisation.
// // //         
// // void Unit::update_pccInfos(Path const & onePccPath) {
// //     pccPath = onePccPath;
// //     update_pccInfos();
// // }
// // void Unit::update_pccInfos() {
// //     
// //     ////////////////////////////////////////////////////////////////////
// //     // 1 - listes concernant les états et les trans traversées
// //     ////////////////////////////////////////////////////////////////////
// //     
// //     lp_pccStates.clear();
// //     lp_pccOrders.clear();
// //     lp_pccMaintStates.clear();
// // 
// //     Trans*                  p_trans;
// //     State*                  p_state;
// //     forall(p_trans, pccPath) {
// //               
// //        // On remplit les différentes liste utiles
// //        p_state = p_trans->p_targetState;
// //        switch (p_state->kind) {
// //        
// //            case State::maintKind :
// //                // on mémorise l'état utile correspondante 
// //                lp_pccMaintStates.push_back(p_state);
// //                lp_pccStates.push_back(p_state);
// // 
// //                break;
// //               
// //            case State::orderKind :
// //               
// //                // on mémorise l'état utile correspondante 
// //                lp_pccOrders.push_back(p_state->p_order);
// //                lp_pccStates.push_back(p_state);
// // 
// //                break;
// //               
// //            default: 
// //               // Etat de type endKind : rien à faire
// //               ;
// //               
// //        }; //endswitch    
// // 
// //     }
// // 
// //     ////////////////////////////////////////////////////////////////////
// //     // 1 - liste concernant les CUS (utilisations continues)
// //     ////////////////////////////////////////////////////////////////////
// //     
// //     // Effacement des listes à mettre à jour
// //     l_cusPaths.clear();
// //     l_longCusPaths.clear();
// //     llp_cusOrderss.clear();
// //     
// //     // Construction des listes des CUS (l_cusPaths et llp_cusOrderss)
// //     // 
// //     // Trans*                  p_trans;  // Deja déclaré ci-dessus
// //     Path                    cusPath;
// //     leda_list <Order*>      lp_cusOrders;
// //     forall(p_trans, pccPath) {
// //         if (p_trans->is_otherToOrderKind()) {
// //         
// //             // Nouvelle séquence d'ordre
// //             cusPath.clear();
// //             lp_cusOrders.clear();
// //             lp_cusOrders.push_back(p_trans->p_sourceState->p_order);
// // 
// //         } else if (p_trans->is_orderToOrderKind()) {
// //         
// //             cusPath.push_back(p_trans);
// //             lp_cusOrders.push_back(p_trans->p_targetState->p_order);
// //         
// //         } else if (p_trans->is_orderToOtherKind()) {
// //         
// //             // Fin de séquence d'utilisation :
// //             
// //             // On mémorise ce lp_cusOrders dans la liste des lp_cusOrders
// //             llp_cusOrderss.push_back(lp_cusOrders);
// //             
// //             // On mémorise ce cusPath dans la liste des cusPath
// //             if (cusPath.length() > 0) {
// //                 l_cusPaths.push_back(cusPath);
// // 
// //                 // Si ce CUS dépasse utime, on l'enregistre.
// //                 if (get_xtime (cusPath) > 0 ) {
// //                     l_longCusPaths.push_back(cusPath);                    
// //                 };
// //                 
// //             };
// //             
// //         } // endif (p_trans->is_...)
// //     } // endwhile    
// // }
// // 
// // ////////////////////////////////////////////////////////////////////////
// // int Unit::get_xtime() const {
// //     Path    cusPath;
// //     int     xtime = 0;
// //     
// //     forall (cusPath, l_longCusPaths) {
// //         xtime += get_xtime(cusPath);
// //     }
// //     return xtime;
// // }
// // 
// // ////////////////////////////////////////////////////////////////////////
// // int Unit::get_xtime(Path & cusPath) const {
// // 
// //     Trans*  p_trans;
// //     int     xtime  = - p_rt->utime 
// //                      + cusPath.front()->p_sourceState->p_order->d;
// //                      
// //     forall(p_trans, cusPath) {
// //         xtime += p_trans->p_targetState->p_order->d;
// //     }
// //     return xtime;
// // }
// // 
// // int Unit::get_xtime(leda_list<Order*> & lp_cusOrders) const {
// // 
// //     Order*  p_order;
// //     int     xtime = -p_rt->utime;
// //     
// //     forall(p_order, lp_cusOrders) {
// //         xtime += p_order->d;
// //     }
// //     return xtime;
// // }
// // 
// // ////////////////////////////////////////////////////////////////////////
// // // Visu du chemin minimum de l'unité dans le graphe correspondant
// // // 
// // void Unit::print_pathInfos(ostream& os = cout) {
// //     Trans * p_trans;
// //     
// //     os << setiosflags(ios::left) << setw(17) 
// //          << this->name; 
// //     if (is_frozen) {
// //         os << "(figée)   ";
// //     } else {
// //         os << "          ";
// //     }
// //     
// //     os << pccPath.length() - 1 
// //          << " états utiles traversés :" 
// //          << endl; 
// //          
// //     forall(p_trans, pccPath) {
// // 
// //         // Affichage du nom de la transition
// //         os << "  " 
// //              << setiosflags(ios::left) << setw(17) 
// //              << p_trans->name ;  
// //              
// //         // Affichage du coût variable (pondéré par les lambda)
// //         os << "  cost = ";
// //         os << setiosflags(ios::right)
// //              << setw(8) 
// //              << ea_costs[p_trans->e]
// //              << " " ;
// // 
// //         // Affichage du coût réel d'origine
// //         os << " realCost = ";
// //         os << setiosflags(ios::right)
// //              << setw(8) 
// //              << p_trans->realCost 
// //              << " " ;
// //         os << endl;
// //     }
// //         
// //     // os << endl;  
// // 
// //          
// //     os << "  Total              pathCost :   " 
// //          << setw(7)   << get_pathCost();
// //          
// //     os << "  realCost :  " 
// //          << setw(7)   << get_realCost() 
// //          << endl ;
// //          
// //     // Affichage des viols éventuels :
// //     Path   cusPath;
// //     if (l_longCusPaths.length() == 0) {
// //         os << "Pas de viols C5 pour cette unité.\n";
// //     } else {
// //         forall (cusPath, l_longCusPaths) {
// //             os << "viol de utime : " ;
// // 
// //             forall (p_trans, cusPath) {
// //                 os << p_trans->name << " ";
// //             }
// //             os << " xtime="
// //                  << get_xtime(cusPath)
// //                  << endl; 
// //         }
// //     }
// //              
// //     os << endl;  
// // }
// // 
// // ////////////////////////////////////////////////////////////////////////
// // // Méthodes de comparaison d'ordres
// // // 
// // 
// // // Amelioration possible si problème d'efficacité
// // // 
// // int Unit::compareOnReverse_realCost (
// //             Unit* const & p_u1, 
// //             Unit* const & p_u2
// // ) {
// //     int rc1, rc2;
// //     rc1 = p_u1->get_realCost();
// //     rc2 = p_u2->get_realCost();
// //     if (rc1 < rc2) return -1;
// //     if (rc1 > rc2) return  1;
// //     return 0;
// // };



