//
// C++ Implementation: C_Atcd
//
// Description:
//
//
// Author: Eric MAEKER <eric.maeker@free.fr> (C) 2008
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "C_Atcd.h"
#include "drtux.h"
#include <qnamespace.h>
#include <qmap.h>

//============================= Atcd_Element =========================================================================================
//------------------------------ isAllergie ------------------------------------------------------------------------------------------
/*! \brief Test l'ATCD et retourne TRUE si il s'agit d'une allergie. */
bool Atcd_Element::isAllergie()
{ if (m_Code.left(1) == "(") return TRUE; else return FALSE; }

//------------------------------ isCIM10 --------------------------------------------------
/*! \brief Test l'ATCD et retourne TRUE si il s'agit d'un codage CIM10. */
bool Atcd_Element::isCIM10()
{ if (m_Code.left(1) == "~" ) return TRUE; else return FALSE; }

//------------------------------ getPixmap --------------------------------------------------
/*! \brief Récupère le Pixmap de l'ATCD selon le Thème défini dans CApp.
*/
QPixmap Atcd_Element::getPixmap()
{ if ( isCIM10()  )
  {return Theme::getIcon( "Cim10All_Icon.png");
  }
  else if (isAllergie())
  {return Theme::getIcon( "22x22/vidal.png");
  }
  else
  {return Theme::getIcon( "22x22/file_text.png");
  }
}

//------------------------------ getLightCIM10 --------------------------------------------------
/*! \brief Les intitulés de la CIM10 sont parfois peu comptabiles avec la lecture. Cette fonction allège les intutilés pour les rendre plus compréhensibles.
*/
QString Atcd_Element::getLightCIM10()
{ QString retour = "";
  if ( isCIM10() )
  { // Enlève SAI, le texte après la virgule, le texte entre parenthèse
    retour = m_Libelle;
    retour.replace("SAI","");
    int deb = retour.find(",");
    int fin = -1;
    if (deb != -1) retour = retour.left(deb);
    int i = 0;
    while ((retour.find("(") != -1) || (i != 10))
    { ++i;
      deb = retour.find("(");
      fin = retour.find(")", deb);
      if (fin != -1)
      { //si le caractère avant la parenthèse est un espace -> l'enlever, sinon on le garde
        int i = 0;
        if (retour[fin-1] == ' ') i++;
        retour = retour.left(deb-i) + retour.right(retour.length() - fin - 1);
      }
      else break;
    }
   retour = retour.stripWhiteSpace();
 } // Fin ATCD CIM 10
 return retour;
}

//------------------------------ operator< --------------------------------------------------
/*! \brief défini la comparaison de deux éléments pour permettre le trie des antécédents.
 *  Les variables sont triées soit par ordre de rubrique, soit par ordre de libellé, soit par date. Pour trier les valeurs, utiliser Atcd_Code::setsort   et  Atcd_Code::sort() sur la variable m_Atcd_Liste de cette classe.
 *  \sa enum CApp:SortBy, CApp::m_Atcd_SortBy
*/
bool Atcd_Element::operator< (const Atcd_Element& e) const
{ bool resultat;
  switch (G_pCApp->m_Atcd_SortBy)
  { case CApp::SortByLibelle :
        { resultat = m_Libelle < e.m_Libelle;
          break;
        }
   case CApp::SortByDate :
        { resultat = m_Date < e.m_Date;
          break;
        }
   default : // SortByRubrique
        { if (m_Rubrique == e.m_Rubrique) resultat = m_Libelle < e.m_Libelle;
          else resultat = m_Rubrique < e.m_Rubrique;
          break;
        }
  } // end switch
  return resultat;
}

//------------------------------ operator== --------------------------------------------------
/*! \brief défini l'égalité entre deux éléments pour permettre la suppression des antécédents par remove().
 *  Teste d'abord l'égalité des m_Id_ATCD pour aller vite. S'il n'ont pas été définit : teste tous les items un à un.
*/
bool Atcd_Element::operator== (const Atcd_Element& e) const
{ if ((m_Id_ATCD != -1) && (e.m_Id_ATCD != -1))
     { if (m_Id_ATCD  != e.m_Id_ATCD)           return FALSE; else return TRUE;
     }
  // Si les id n'étaient pas définis lors teste tous les items
  if (m_Rubrique != e.m_Rubrique)            return FALSE;
  if (m_Libelle  != e.m_Libelle)             return FALSE;
  if (m_Date     != e.m_Date)                return FALSE;
  if (m_Etat     != e.m_Etat)                return FALSE;
  if (m_Commentaire != e.m_Commentaire)      return FALSE;
  if (m_Code     != e.m_Code)                return FALSE;
  return TRUE;
}


//================================ Atcd_Code ======================================================================

/*! \class Atcd_Code
 *  \brief Gestion des antécédents indépendemment de la vue actuelle.
 * <b>Cette classe offre tous les fonctions nécessaire à la gestion des antécédents médicaux/chirugicaux/obstétricaux et autres. Pour profiter de ses fonctionnalités, vous devez d'abord l'instancier.</b>

 * <b>Initialisation :</b> avant de travailler sur le terrain, vous devez signifier à la classe le CRubRecord à utiliser. La fonction setTerrain(CRubRecord* pCRubRecord, CMoteurBase* pCMoteurBase) est prévue pour cela. Elle analysera le fichier de terrain, extrairera les antécédents de sorte qu'ils soient exploitables par l'application et sauvegardera la clé primaire du document terrain (pour éviter de le relire si aucune modification n'a été effectuée). La fonction getPkDocTerrain() retourne le PrimKey du document terrain en cours d'utilisation. Vous devez aussi définir les liste de rubbriques pour les antécédents médicaux et chirurgicaux. Les fonctions init_Get_RubChir(QStringList *pListItem  = 0 ) et init_Get_RubMed(QStringList *pListItem   = 0 ) en sont chargées. Si aucune QStringList n'est passée en paramètre, les rubriques par défaut sont utilisées. Sinon ce sont les listes passées en paramètres. Voir aussi CApp::CApp au moment de l'instanciation initiale de la classe qui récupère les listes dans le fichier de paramètres de DrTux.

 * <b>Ajouts d'antécédents :</b> les fonctions addATCD_CIM10(), addATCD_Textuel(), addATCD_Allergie(), setGrossesse(bool etat), setAllaitement(bool etat) vous permettent de d'ajouter de nouveaux antécédents sans vous soucier des widgets d'affichage. Lorsque vous appelez addATCD_CIM10() la fenêtre d'ajout d'antécédents encodés en CIM10 apparaît automatiquement. Ceci simplifiera grandement votre code et sa lecture. La classe émet, si nécessaire, le signal ATCD_Changed() à chaque fois qu'un antécédent est modifié ou ajouté. Les classes appelantes pourront en tirer partie pour leur synchronisation.

 * <b>Les fonctions de modification :</b> changeDDR(), modifyDate(Atcd_Element* pAtcd), changeEtat(Atcd_Element* pAtcd), changeCommentaire(Atcd_Element* pAtcd), eraseAtcd(Atcd_Element* pAtcd), modifyAtcd(Atcd_Element* pAtcd), setRubrique(Atcd_Element* pAtcd, QString& rubrique), setGrossesse(bool etat),setAllaitement(bool etat), setDDRTo(QDate dt) permettent la modifications des éléments de l'antécédent (Atcd_Element) passé en paramètre. La classe émet, si nécessaire, le signal ATCD_Changed() à chaque fois qu'un antécédent est modifié ou ajouté. Les classes appelantes pourront en tirer partie pour leur synchronisation.

 * <b>Connaissance des antécédents :</b> get_ATCD_Rubname(Atcd_Element& pAtcd) retourne la rubrique de l'antécédent. getDDR() retourne la date des dernières règles enregistrée. getTermeObstetrical(QDate dt = QDate()) calcule automatiquement le terme de la grossesse à partir de la date passée en paramètre. getAtcd_byID(int idAtcd) retourne l'Atcd_Element dont l'id est celle passée en paramètre.

 * clear() efface toutes les données de la classe et remet à zéro les différents indicateurs d'état.

 * <b>Connaître l'état de modification des antécédents :</b> géré de façon automatique cet état peut être définit manuellement grâce à la fonction setModifiedState( bool state ). L'utilisation de cette fonction n'est pas souhaitable. Vous pouvez connaître l'état de modification grâce à la fonction isModified() qui retournera un booléen (TRUE = modifié, FALSE = non modifié). Ces fonctions serviront à la gestion des sauvegardes.

 * <b>La sauvegarde :</b> toOldIni() renvoie les antécédents encodés à l'ancienne mode prêts pour la sauvegarde. Il ne restera plus qu'aux classes appelantes de gérer la suite du fichier terrain (qui contient en plus les variables, le traitement en cours). Une fonction toXML() est en cours d'écriture.

 * <b>Les fonctions de tri :</b> setSort(int mode) et sort(). Le mode de tri est définissable via l'énumération CApp::SortBy. Il est possible de trier par date, rubrique, libellé.

 * <b>Les fonctions pour l'affichage :</b> getAtcdToListViewItem(CPrtQListViewItem& retour) (utilisée par Dock_Menu, le menu d'accès rapide de DrTux), getAtcdToSimpleListView(QListView& retour) (utilisée par FormRubTerrain)

 * <b>Pour des exemples de codage à l'aide de cette classe : </b> voir Dock_Menu et FormRubTerrain.

 * \sa Atcd_Element

*/


//------------------------------ Atcd_Code ------------------------------------------------------------------------
/*! \brief Constructeur obligatoire. */
Atcd_Code::Atcd_Code(QWidget *parent, const char *name)
 : QObject(parent, name)
{ m_PkDocTerrain = "";
  m_TerrainIsModified = FALSE;
    // Initialisation des listes de rubriques déportée dans CApp
//   m_Rubriques_ATCD_Med.clear();
//   m_Rubriques_ATCD_Chir.clear();
//   init_Get_RubChir();
//   init_Get_RubMed();
}


//------------------------------ Atcd_Code ------------------------------------------------------------------------
/*! \brief Destructeur. */
Atcd_Code::~Atcd_Code()
{
}

//------------------------------ clear --------------------------------------------------
/*! \brief Efface les données de la classe et envoie un signal de changement des ATCD pour que les view se mettent à jour.
*/
void Atcd_Code::clear()
{ m_Atcd_Liste.clear();
  m_Terrain = "";
  m_Grossesse = FALSE;
  m_Allaitement = FALSE;
  m_DDR = QDate();
  m_PkDocTerrain = "";
  m_TerrainIsModified = FALSE;
  //emit (ATCD_Changed() );   // emit (ATCD_Changed() à faire en fin de fonction utilisant clear() mais pas là
}


//------------------------------ isModified --------------------------------------------------
/*! \brief retourne l'état de modification de la classe antécédent. TRUE si les antécédents ont été modifiés, FALSE cas contraire.
 *  \sa m_TerrainIsModified, emitATCD_Changed.
*/
bool Atcd_Code::isModified()
{ return m_TerrainIsModified; }


//------------------------------ isModified --------------------------------------------------
/*! \brief définit l'état de modification de la classe antécédent. TRUE si les antécédents ont été modifiés, FALSE cas contraire.
 *  \sa m_TerrainIsModified, emitATCD_Changed.
*/
void Atcd_Code::setModifiedState( bool state )
{ m_TerrainIsModified = state;
}


//------------------------------ emitATCD_Changed --------------------------------------------------
/*! \brief Avant d'émettre le signal ATCD_Changed , procède à quelques vérifications de base, en particuliers définit la prorité m_TerrainIsModified à TRUE.
*/
void Atcd_Code::emitATCD_Changed()
{ m_TerrainIsModified = TRUE;
  emit (ATCD_Changed() );
 }

//------------------------------ getPkDocTerrain --------------------------------------------------
/*! \brief Retourne la clé primaire du document actuellement utilisé pour le terrain.
 *  \sa CRubRecord::m_PrimKey
*/
QString Atcd_Code::getPkDocTerrain()
{ return m_PkDocTerrain; }

//------------------------------ setSort --------------------------------------------------
/*! \brief Définition de la méthode de tri : par Rubrique, par libelle, par Date.
 *  \sa CApp::SortBy, CApp::m_Atcd_SortBy
*/
void Atcd_Code::setSort(int mode)
{ G_pCApp->m_Atcd_SortBy = mode;
}

//------------------------------ sort --------------------------------------------------
/*! \brief Lance le tri selon la méthode sauvegardée dans CApp.
*/
void Atcd_Code::sort()
{ qHeapSort(m_Atcd_Liste);
}

//------------------------------ init_Get_RubMed --------------------------------------------------
/*! \brief Construit la StringList Rubrique des ATCD médicaux. */
void Atcd_Code::init_Get_RubMed(QStringList *pListItem /* = 0 */)
{if ( pListItem && pListItem->count()) m_Rubriques_ATCD_Med = *pListItem;
 else
 { m_Rubriques_ATCD_Med.clear();
   m_Rubriques_ATCD_Med << TR("Médicaux") << TR("Facteurs de risque") << TR("Cardio-Vasculaire") << TR("Dermatologique") << TR("Endocrinologique") << TR("Gastro-entéro-hépatologique") << TR("Gynécologique") << TR("Hématologique") << TR("Maladie de système") << TR("Oncologique")  << TR("Néonatalogique") << TR("Néphrologique") << TR("Neurologique") << TR("Ophtalmologique") << TR("Pneumologique") << TR("Psychiatrique") << TR("Rhumatologique") << TR("Urologique") << TR("Médical autre");
 }
}

//------------------------------ init_Get_RubChir --------------------------------------------------
/*! \brief Construit la StringList Rubrique des ATCD médicaux. */
void Atcd_Code::init_Get_RubChir(QStringList *pListItem /* = 0 */)
{ if ( pListItem && pListItem->count()) m_Rubriques_ATCD_Chir = *pListItem;
  else
  { m_Rubriques_ATCD_Chir.clear();
    m_Rubriques_ATCD_Chir << TR("Chirurgicaux") << TR("Chirurgie digestive")  << TR("Chirurgie gynécologique") << TR("Chirurgie orthopédique et traumatologique") << TR("Chirurgie thoracique et cardio-vasculaire") << TR("Chirurgie urologique") << TR("Chirurgie vasculaire");
  }
}

//------------------------------ getRubriqueName_Medical --------------------------------------------------
QString Atcd_Code::getRubriqueName_Medical(int id)
{ if (id<0)  return TR("Médicaux et Chirurgicaux");
  //if (id<=0) return TR("Médicaux");
  if (id < (int) m_Rubriques_ATCD_Med.count()) return m_Rubriques_ATCD_Med[ id ];
  else return "";
}

//------------------------------ getRubriqueName_Chirurgical --------------------------------------------------
QString Atcd_Code::getRubriqueName_Chirurgical(int id)
{ if (id<0)  return TR("Médicaux et Chirurgicaux");
  //if (id==0) return TR("Chirurgicaux");
  if (id < (int)m_Rubriques_ATCD_Chir.count()) return m_Rubriques_ATCD_Chir[ id ];
  else return "";
}

//------------------------------ getIdRubrique --------------------------------------------------
/*! \brief Teste l'ATCD et renvoie l'Id correspondant à la QStringList en rapport (médical ou chirurgical).
 *  \param isMed : ATCD de type médical (aller rechercher la rubrique dans la liste médicale.
 *  \param isChir : ATCD de type chirurgical (aller rechercher la rubrique dans la liste chirurgicale.
 *  \param isAllergie : ATCD de type allergique.
 *  \param id : id de la QStringList. retourne -1 si la rubrique n'a pas été trouvée
 *  \todo A TESTER
*/
bool Atcd_Code::getIdRubrique(Atcd_Element& pAtcd, bool& isMed, bool& isChir, bool& isAllergie, int& id, QString  *pRubname /* = 0 */)
{ isMed        = FALSE;
  isChir       = FALSE;
  isAllergie   = FALSE;
  bool trouve  = FALSE;
  id = -1;                // Permettra de tester si la rubrique a été trouvée ou pas

  // Teste compatiblité ancienne version de rubriques Méd/Chir
  if (pAtcd.m_Code.find('(')!=-1)
  {               id = m_Rubriques_ATCD_Chir.findIndex (pAtcd.m_Rubrique );
   if (id == -1)  id = m_Rubriques_ATCD_Med.findIndex  (pAtcd.m_Rubrique );
   isAllergie        = TRUE;
   trouve            = TRUE;
  }
  else if (pAtcd.m_Rubrique == TR("Méd"))
  { id     = 0;
    isMed  = TRUE;
    trouve = TRUE;
  }
  else if (pAtcd.m_Rubrique == TR("Chir"))
  { id     = 0;
    isChir = TRUE;
    trouve = TRUE;
  }

  else if (pAtcd.m_Rubrique == "")
  { id     = -1;
    trouve = TRUE;
  }
  else
   { // Recherche parmis les ATCD Chirurgicaux / Médicaux
     QString testChir = pAtcd.m_Rubrique.left(4);
     if (testChir != "Chir")
     { for (int i = 0; i < (int)m_Rubriques_ATCD_Med.count();++i)
        { if (pAtcd.m_Rubrique == m_Rubriques_ATCD_Med[i])
          { id     = i;
            isMed  = TRUE;
            trouve = TRUE;
            break;
          } // fin If
        } // Fin For
      } // Fin if isChir

      // Si pas trouvé ==> recherche parmis les ATCD chirurgicaux
      if (!trouve)
      {        for (int i = 0; i < (int)m_Rubriques_ATCD_Chir.count();++i)
        { if (pAtcd.m_Rubrique == m_Rubriques_ATCD_Chir[i])
           { id     = i;
             isChir = TRUE;
             trouve = TRUE;
             break;
           }
        } // Fin For
       } // Fin if trouvé
   }
if (pRubname)
   {                         *pRubname = "";
    if (isMed)               *pRubname = getRubriqueName_Medical(id);
    else if (isChir)         *pRubname = getRubriqueName_Chirurgical(id);
    else if (isAllergie)     *pRubname = TR("Allergies");
    if (pRubname->stripWhiteSpace().length() == 0) *pRubname = TR("Médicaux et Chirurgicaux");
   }
 return trouve;
}
//------------------------------ setTerrain --------------------------------------------------
/*! \brief Cette fonction défini pour la classe le fichier de terrain à analyser et construit la liste des ATCD.
 * Attention, si des données sont déjà présentes dans la classe elles seront effacées. Veillez donc à gérer la sauvegarde si nécessaire avant l'appel de cette fonction.
 *  \param CRubRecord = pointeur vers l'enregistrement de terrain à utiliser
 *  \param CMoteurBase : pointeur vers le moteur de la base de données
*/
void Atcd_Code::setTerrain(CRubRecord* pCRubRecord, CMoteurBase* pCMoteurBase)
{ if (!pCRubRecord)                             return;
  if (!pCMoteurBase)                            return;
  QString data = "";
  if (pCRubRecord->m_PrimKey == m_PkDocTerrain) return;
  pCMoteurBase->GetDataFromRubList(data, pCRubRecord);
  m_PkDocTerrain = pCRubRecord->m_PrimKey;
  setTerrain(data, pCMoteurBase);
}

//------------------------------ setTerrain --------------------------------------------------
/*! \brief Cette fonction renseigne et initialise la classe avec les donnees SQL de terrain à analyser et construit la liste des ATCD.
 *  \param CRubRecord = pointeur vers l'enregistrement de terrain à utiliser
 *  \param it : pointeur vers le moteur de la base de données
*/
int Atcd_Code::setTerrain(RUBREC_LIST::iterator it, CMoteurBase* pCMoteurBase)
{
 //........................... si rubrique qui etait avant celle a afficher, a ete modifiée ................................................
 //                            replacer son contenu dans la liste des rubriques avant d'afficher la nouvelle
 // if (m_IsModifiable && m_IsModified && m_LastRub != -1)
 //   {FormToData(stringDST);
 //    m_pCMoteurBase->ReplaceDataInRubList(stringDST, m_pRubList, m_LastRub );
 //   }
  if ((*it).m_PrimKey == m_PkDocTerrain) return 0;
  clear();
 //........................... retirer les donnees de la base SQL ..............................
 //
 QByteArray  data;
 int           ret = pCMoteurBase->GetDataFromRubList(data, it);
 QString stringDST = "";
 char         *ptr = data.data();
 long          len = data.size();
 if (ptr && len>0)
    {if (CGestIni::IsUtf8( ptr ))
        {stringDST = QString::fromUtf8 ( ptr );
         ptr = (char*)(const char*) stringDST;
        }
     setTerrain(ptr, pCMoteurBase);
    }
 else
    {setTerrain("", pCMoteurBase);
    }
  emit ATCD_Changed();
  return ret;
}

//------------------------------ setTerrain --------------------------------------------------
/*! \brief Préférez utiliser la fonction setTerrain(CRubRecord* pCRubRecord, CMoteurBase* pCMoteurBase) plutôt que cette fonction, car elle gère pas la synchronisation. Cette fonction défini pour la classe le fichier de terrain à analyser et construit la liste des ATCD.
 * Attention, si des données sont déjà présentes dans la classe elles seront effacées. Veillez donc à gérer la sauvegarde si nécessaire avant l'appel de cette fonction.
 *  \param strTerrain = texte de l'enregistrement de terrain à utiliser
 *  \param CMoteurBase : pointeur vers le moteur de la base de données
*/
void Atcd_Code::setTerrain(const char* strTerrain, CMoteurBase* pCMoteurBase)
{// Récupère la liste des ATCD
 //clear();
 int id        = 0;
 m_Grossesse   = FALSE;
 m_Allaitement = FALSE;
 m_Terrain     = strTerrain;
 m_Atcd_Liste.clear();

 char *pt = (char*) (const char*) strTerrain;

 //........... effacer les anciennes tables de variables ................
 //
 QString libelle, dt_str, rubrique, comm, etat, code;
 QString      section          = "";
 QString     var_name          = "";
 int            etat_int       = 0;
 Atcd_Element*            Atcd = 0;
 QDate        dt;

 while((pt = CGestIni::Param_GotoNextSection(pt, 0, &section)) && *pt)
 { if (section==TR("Antécédents"))
     { while (*pt && *pt != '[')
       {var_name = "";
        libelle  = ""; rubrique=""; etat=""; code=""; comm=""; dt_str="";
        pt = CGestIni::Param_ExtraireNextValeurs(pt, libelle, &rubrique, &etat, &code, &comm, &dt_str);
        // Nettoie les items de l'antécédent
        libelle.replace("\\,",",");        libelle.replace("\\;",";");        libelle.replace("\\[","[");
        libelle.replace("\\]","]");        comm.replace("\\,",",");           comm.replace("\\;",";");
        comm.replace("\\[","[");           comm.replace("\\]","]");
        if (dt_str.length())
           dt = QDate::fromString(dt_str.right(4)+"-"+dt_str.mid(3,2)+"-"+dt_str.left(2), Qt::ISODate);
        else dt = QDate();
        // Crée l'ATCD et ajoute le à la liste
        if (etat == TR("Passé")) etat_int = 0;
        else etat_int = 1;

        Atcd = new Atcd_Element(rubrique, libelle, dt , code, etat_int, comm) ;
        //m_Rubriques_ATCD_Med;         /*!< contient la liste des rubriques disponibles. */
        //m_Rubriques_ATCD_Chir;        /*!< contient la liste des rubriques disponibles. */
        //QStringList::Iterator it = m_Rubriques_ATCD_Med.find(rubrique)
        Atcd->setId(id);
        m_Atcd_Liste.append ( *Atcd );
        ++id;
       }  //  Fin while
       section="";
     }  // Fin if section == "Antécédents"

   // OBSTETRIQUE
   if (section == TR("Obstétrique"))
     { while (*pt && *pt != '[')
       { pt = CGestIni::Param_ExtraireNextValeurs(pt, libelle, &dt_str); // 18-03-2004
         if (libelle == TR("Grossesse"))
         { if (dt_str.length() && dt_str != TR("non"))
				{ m_Grossesse = TRUE;
				  m_DDR = QDate( atoi(dt_str.right(4)), atoi(dt_str.mid(3,2)), atoi(dt_str.left(2)) );
				}
           else m_Grossesse = FALSE;
         }
         if (dt_str.length() && libelle == TR("Allaitement") && dt_str==TR("oui"))  m_Allaitement = TRUE;
         else                                                                       m_Allaitement = FALSE;
         section="";
       } // Fin while
      } // Fin if section
 } // Fin while GotoNextSection

//  ATCD_LISTE::iterator it;
//  for (it=m_Atcd_Liste.begin(); it != m_Atcd_Liste.end();++it)
//  { qWarning( QString::number( (*it).m_Etat ) + "    " + (*it).m_Libelle ); }

 // Trie la liste des ATCD selon le nom de la rubrique
 qHeapSort( m_Atcd_Liste );

}

//------------------------------ toOldIni --------------------------------------------------
/*! \brief Prépare le fichier de sauvegarde des ATCD dans l'ancien format dit "format INI".
 *
 * A savoir le terrain dans les versions 1 à 2.10 de MedinTux est sauvegardé en version INI. C'est grâce à CGestIni qu'il est parsé. Le fichier de terrain comprend plusieurs paramètres sauvegardés les uns derrière les autres :
 * - les antécédents
 * - les variables
 * - le traitement en cours.
 *
 * Voici comment sont sauvegardés les antécédents :
 * [Antécédents]\n
 *     Libelle = rubrique, etat, code, commentaire, date(dd-MM-yyyy)\n
 *  ATTENTION : les libellés CIM10 peuvent contenir des crochets "[]" qui perturbent la sauvegarde et la lecture des ATCD. Ils seront remplacés par des accolades "{}".
 *
*/
QString Atcd_Code::toOldIni()
{ ATCD_LISTE::iterator it;
  QString retour = "";
  QString tmp = "";

  for (it=m_Atcd_Liste.begin(); it!=m_Atcd_Liste.end();++it)
  { if ((*it).m_Etat == 0) tmp = TR("Passé");
    else tmp = TR("Actif");
    if ((*it).m_Libelle.find("[") )
    { (*it).m_Libelle.replace("[", "{");
      (*it).m_Libelle.replace("]", "}");
    }
//     if ((*it).m_Libelle.find(",") )
//     { (*it).m_Libelle.replace(",", ";");
//     }
    retour += "   " +(*it).m_Libelle +" = ";
    retour += (*it).m_Rubrique + ", ";
    retour += tmp + ", ";
    retour += (*it).m_Code + ", ";
    retour += (*it).m_Commentaire + ", ";
    retour += (*it).m_Date.toString("dd-MM-yyyy") + "\r\n";
  } // fin for
  retour.prepend("["+TR("Antécédents")+"]\r\n");
  retour += "["+TR("Obstétrique")+"]\r\n";
  if (!m_Grossesse) retour += "   " + TR("Grossesse") + "  = " + TR("non") + "\r\n";
  else retour += "   " + TR("Grossesse") + "  = " + m_DDR.toString("dd-MM-yyyy") + "\r\n";
  if (m_Allaitement) retour += "   " + TR("Allaitement") + "  = " + TR("oui") + "\r\n";
  else retour += "   " + TR("Allaitement") + "  = " + TR("non") + "\r\n";

  return retour;
}


//------------------------------ getDDR --------------------------------------------------
/*! \brief retourne la date des dernières règles si elle est renseignée.
*/
QDate Atcd_Code::getDDR()
{ return m_DDR; }

/*! \brief Calcul le terme de la grossesse à la date souhaitée.
 *  \param QDate dt        Date pour le calcul (si =0 calcule à partir de la date sytème).
 *  \return Le terme au format string du style : " XX SA XX Jours "
 *  Testée fonctionnelle
*/

//------------------------------ getTermeObstetrical --------------------------------------------------
/*! \brief Retourne une QString contenant le terme obstétrical en SA et jours, ou le message d'erreur "Non calculable".
*/
QString Atcd_Code::getTermeObstetrical(QDate dt /*=QDate()*/)
{ // Quelques contrôles
  if (!m_Grossesse) return QString::null;
  if (!m_DDR.isValid() ) return QString::null;
  if (dt.isNull()) {dt = QDate::currentDate(); }
  else { if (!dt.isValid() ) return QString::null; }

  // Calcul du terme
  int nbDays = m_DDR.daysTo(dt);
  int nbDaysLeft = nbDays % 7;
  int nbWeeks = (nbDays - nbDaysLeft ) / 7;
  QString ret = "";

  if (dt < m_DDR)
  { ret = TR("Non calculable"); }
  else if (nbWeeks > 45)
  { ret = TR("Non calculable"); }
  else
  { ret = QString(TR("%1 SA %2 Jours")).arg(nbWeeks).arg(nbDaysLeft); }
  return ret;
}

//------------------------------ getAtcdToListViewItem --------------------------------------------------
/*! \brief Construit un ListViewItem hiérarchique à une colonne avec les ATCD prêt à être affiché.
 *  \param CPrtQListViewItem : L'item qui recevra l'arborescence des antécédents.
 *  \sa CPrtQListViewItem, Dock_Menu
*/
void Atcd_Code::getAtcdToListViewItem(CPrtQListViewItem& retour)
{ if (m_Atcd_Liste.count() == 0) return;
  setSort(CApp::SortByRubrique);
  sort();

  QMap<QString, CPrtQListViewItem* > MAP_pLVITEM;                 // on se cree une map pour matcher non de la rubrique et CPrtQListViewItem allant avec
//  bool isMed_Act, isChir_Act, isAllergie_Act;
  QString tmp      = "";
//  int id_Act       = -1;

  CPrtQListViewItem*  last_rub_Item = 0;                          // pointeur sur la rubrique pere precedente
  CPrtQListViewItem*   cur_rub_Item = 0;                          // pointeur sur la rubrique pere courante
  CPrtQListViewItem*      atcd_Item = 0;
  QString                   rubname = "";
  ATCD_LISTE::iterator           it = m_Atcd_Liste.at(0);
  for (it = m_Atcd_Liste.at(0); it != m_Atcd_Liste.end(); ++it)
      { //.................... nom de la rubrique (pere) de cet antecedent ....................................
        rubname = get_ATCD_Rubname((*it));                                                         // generer le nom de la rubrique de cet antecedent
        QMap<QString, CPrtQListViewItem*>::Iterator mit = MAP_pLVITEM.find ( rubname );            // rechercher dans la map si il n'y a pas deja un item pere a cet antecedent
        if ( mit == MAP_pLVITEM.end() )                                                            // si pas trouve
           { last_rub_Item = new CPrtQListViewItem( &retour, last_rub_Item, rubname);              // on cree la rubrique pere
             if (last_rub_Item)
                {last_rub_Item->setOpen( TRUE );                                                   // on l'ouvre
                 MAP_pLVITEM.insert ( rubname, last_rub_Item, FALSE );                             // on l'insere dans la map
                }
             cur_rub_Item = last_rub_Item;                                                         // c'est la nouvelle   qui sera le pere de l'antecedent
           }
        else cur_rub_Item = *mit;                                                                  // c'est celle trouvee dans la map qui sera le pere de l'antecedent
        //..................... inserer l'antecedent ...........................................................
                                         tmp  = (*it).m_Libelle;
        if ( (*it).isCIM10() )           tmp  = (*it).getLightCIM10();
        if ( (*it).m_Date.isValid() )    tmp += " ("+(*it).m_Date.toString("yyyy")+")";
        atcd_Item = new CPrtQListViewItem ( cur_rub_Item, atcd_Item, tmp);
        if (atcd_Item) atcd_Item->set_ID_Rublist( (*it).getId() );
  } // Fin FOR
  // Grossesse et Allaitement
  if (m_Grossesse)   { new CPrtQListViewItem ( &retour,0, TR("Grossesse en cours"));   }
  if (m_Allaitement) { new CPrtQListViewItem ( &retour,0, TR("Allaitement en cours")); }
}

//------------------------------ get_ATCD_Rubname --------------------------------------------------
/*! \brief Teste l'ATCD et renvoie le nom de la rubrique auquel il appartient.
 *  \param  Atcd_Element& pAtcd : reference sur l'antecedent
*/
QString Atcd_Code::get_ATCD_Rubname( Atcd_Element& pAtcd )
{ // Teste compatiblité ancienne version de rubriques Méd/Chir
  if (pAtcd.m_Code[0] == '(')
     { return  TR("Allergies");
     }
  else if (pAtcd.m_Rubrique == TR("Méd"))
     { return TR("Médicaux");
     }
  else if (pAtcd.m_Rubrique == TR("Chir"))
     { return TR("Chirurgicaux");
     }
  else if (pAtcd.m_Rubrique.stripWhiteSpace().length() == 0)
     { return TR("Médicaux et Chirurgicaux");
     }
  return pAtcd.m_Rubrique;
}

//------------------------------ getAtcdToSimpleListView --------------------------------------------------
/*! \brief Construit un ListViewItem hiérarchique à une colonne avec les ATCD prêt à être affiché.
 *  \param CPrtQListViewItem : L'item qui recevra l'arborescence des antécédents.
 *  \sa RubTerrain, CMDI_Terrain
*/
void Atcd_Code::getAtcdToSimpleListView(QListView& retour)
{ if (m_Atcd_Liste.count() == 0) return;
  QString tmp = "";
  QString etat = "";
  CPrtQListViewItem* atcd_Item = 0;
  setSort(CApp::SortByRubrique);
  sort();
  retour.clear();

  // Récupère l'id_rubrique du premier ATCD
  ATCD_LISTE::iterator it;
  for (it = m_Atcd_Liste.begin(); it != m_Atcd_Liste.end(); ++it)
  { if ((*it).m_Etat == 0) etat= TR("Passé"); else etat=TR("Actif");
    atcd_Item = new CPrtQListViewItem ( &retour,
                                    atcd_Item,
                                 (*it).m_Libelle);        // Libelle
   atcd_Item->set_ID_Rublist( (*it).getId() );
   atcd_Item->setText( 1, (*it).m_Rubrique);
   atcd_Item->setText( 2, etat);
   atcd_Item->setText( 3, (*it).m_Code);        // Rubrique
   atcd_Item->setText( 4, (*it).m_Commentaire);        // Rubrique
   atcd_Item->setText( 5, (*it).m_Date.toString("dd-MM-yyyy"));        // Rubrique
   atcd_Item->setPixmap(0, (*it).getPixmap() );
  } // Fin FOR
}


//------------------------------ addATCD_CIM10 --------------------------------------------------
/*! \brief Ajoute à la liste actuelle des ATCD codés en CIM10.
 *  Fait apparaître le Widget d'ajout qui se trouve dans DrTux.
 *  \sa DrTux::CodageCim10All()
*/
void Atcd_Code::addATCD_CIM10()
{QString       strlistCode="";
 QString result = G_pCApp->m_pDrTux->CodageCim10All(DrTux::ATCDString, strlistCode);
 if (result.length()<=0) return;
 // Récupère le libellé et le code sélectionné
 QStringList atcdCIM10 = QStringList::split( "@@", result);
 uint i = 0;
 for (i = 0; i< atcdCIM10.count();++i)
 { int p = atcdCIM10[i].find("::");
   QString libelle = atcdCIM10[i].left(p);
   QString code = atcdCIM10[i].mid(p+2);
   code = "~" + code.left( code.length()-2) + "~";
   QDate dt = QDate();
   int id_ATCD = m_Atcd_Liste.count()+1;
   Atcd_Element pAtcd = Atcd_Element( "", libelle, dt, code, 0, "");
   pAtcd.setId( id_ATCD );
   m_Atcd_Liste.append (pAtcd);
 }
// setSort(CApp::SortByRubrique);
 emitATCD_Changed();
}


//------------------------------ addATCD_Textuel --------------------------------------------------
/*! \brief Ajoute à la liste actuelle des ATCD un ATCD en mode textuel.
 *  Fait apparaître le Widget d'ajout DlgAtcd_txt.
*/
void Atcd_Code::addATCD_Textuel()
{// Appel le Widget de saisie ATCD en texte libre
 DlgAtcd_txt* pDlgAtcd_txt = new DlgAtcd_txt();
 if (!pDlgAtcd_txt) return;
 pDlgAtcd_txt->setRubriques( m_Rubriques_ATCD_Med, m_Rubriques_ATCD_Chir);
 pDlgAtcd_txt->exec();
 if (pDlgAtcd_txt->result() == QDialog::Accepted)
 { // Récupère les données du widget
   QString libelle, commentaire, date, rubrique;
   QDate dt ;
   pDlgAtcd_txt->getInfos(libelle, rubrique, date, commentaire);
   if (date != "") dt = QDate::fromString(date, Qt::ISODate);
   else dt = QDate();
   int id_ATCD = m_Atcd_Liste.count()+1;
   Atcd_Element pAtcd = Atcd_Element(rubrique, libelle, dt, "", 0, commentaire);
   pAtcd.setId( id_ATCD );
   m_Atcd_Liste.append (pAtcd);
   emitATCD_Changed();
 }
 if (pDlgAtcd_txt) delete pDlgAtcd_txt;
}


//------------------------------ addATCD_Allergie --------------------------------------------------
/*! \brief Ajoute à la liste actuelle des ATCD un ATCD allergique.
 *  Fait apparaître le Widget d'ajout DlgAllergie.
*/
void Atcd_Code::addATCD_Allergie()
{// Appel le Widget de saisie ATCD allergique
 DlgAllergie *dlg =      new DlgAllergie();
 if (dlg ==0)            return;
 if (dlg->exec() == QDialog::Rejected)            {delete dlg; return;}  // si annuler cassos
 if (dlg->listView_Choix->childCount ()<=0)       {delete dlg; return;}  // si liste de choix vide  cassos

 // Iterer la liste de choix
 QListViewItemIterator it( dlg->listView_Choix);
 while ( it.current() )
 { QListViewItem *item = it.current();
   ++it;
   QDate dt = QDate();
   // Inserer l'allergie dans la liste des ATCD
   int id_ATCD = m_Atcd_Liste.count()+1;
   Atcd_Element pAtcd = Atcd_Element("", item->text(0), dt,"("+item->text(1)+")",1,"");
   pAtcd.setId( id_ATCD );
   m_Atcd_Liste.append (pAtcd);
 }
 emitATCD_Changed();
 delete dlg;
}



//------------------------------ getAtcd_byID --------------------------------------------------
/*! \brief Renvoie l'antécédent dont l'id est celle passée en paramètre.
*/
Atcd_Element* Atcd_Code::getAtcd_byID(int idAtcd)
{if (idAtcd == -1) return 0;
 ATCD_LISTE::iterator it;
 for (it=m_Atcd_Liste.begin(); it != m_Atcd_Liste.end();++it)
 { if ((*it).getId() == idAtcd) break; }
 return &(*it);
}

//------------------------------ viewATCD --------------------------------------------------
/*! \brief Affiche les renseignements d'un ATCD sans possiblité de modification.
 *  Fait apparaître le Widget de visualisation des ATCD.
*/
void Atcd_Code::viewATCD(int id_ATCD)
{// Trouve l'ATCD selon l'id passée en paramètre
 ATCD_LISTE::iterator it;
 for (it=m_Atcd_Liste.begin(); it != m_Atcd_Liste.end();++it)
 { if ((*it).getId() == id_ATCD) break; }

 // Appel le Widget de saisie ATCD en texte libre
 DlgAtcd_txt* pDlgAtcd_txt = new DlgAtcd_txt();
 if (!pDlgAtcd_txt) return;
 pDlgAtcd_txt->setRubriques( m_Rubriques_ATCD_Med, m_Rubriques_ATCD_Chir);
 pDlgAtcd_txt->setATCD_toView( this, &(*it) );
 pDlgAtcd_txt->exec();
 if (pDlgAtcd_txt) delete pDlgAtcd_txt;
}

//------------------------------ setRubrique --------------------------------------------------
/*! \brief Modifie la rubrique de l'antécédent passé en paramètre par la rubrique passée en paramètre.
*/
void Atcd_Code::setRubrique(Atcd_Element* pAtcd, QString& rubrique)
{ if (!pAtcd) return;
 pAtcd->m_Rubrique = rubrique;
 emitATCD_Changed();
}

//------------------------------ setGrossesse --------------------------------------------------
/*! \brief Modifie l'état de la grossesse.
*/
void Atcd_Code::setGrossesse(bool etat)
{m_Grossesse = etat;
 emitATCD_Changed();
}

//------------------------------ setAllaitement --------------------------------------------------
/*! \brief Modifie l'état de l'allaitement.
*/
void Atcd_Code::setAllaitement(bool etat)
{m_Allaitement = etat;
 emitATCD_Changed();
}

//------------------------------ setDDRTo --------------------------------------------------
/*! \brief Modifie l'état de la grossesse.
*/
void Atcd_Code::setDDRTo(QDate dt)
{m_DDR = dt;
 emitATCD_Changed();
}


//------------------------------ modifyDate --------------------------------------------------
/*! \brief Affiche le widget calendar pour modifier la date de l'antécédent passé en paramètre.
*/
void Atcd_Code::modifyDate(Atcd_Element* pAtcd)
{ if (!pAtcd) return;
  Dlg_Calendar* dlg  = new Dlg_Calendar(0, "Calendar_Dial", FALSE);
 if (dlg==0) return;
 dlg->setCaption(TR("Date de début"));
 dlg->move ( QCursor::pos().x(), QCursor::pos().y() );
 QDate dt = pAtcd->m_Date;
 if ( ! dt.isValid() ) dt = QDate::currentDate();

 dlg->setDate(dt);
 dlg->setComboAnOnDate_Offset(dt, 25,0);
 dlg->SelectDateAll();

 if (dlg->exec()== QDialog::Accepted )
    { pAtcd->m_Date = dlg->getDate();
      emitATCD_Changed();
    }
 if (dlg) delete dlg;
}


//------------------------------ modifyAtcd --------------------------------------------------
/*! \brief Affiche le widget de modification de l'antécédent selon son type et gère sa modification.
 *  \todo gestion des Atcd Texte Libre
*/
void Atcd_Code::modifyAtcd(Atcd_Element* pAtcd)
{ if (!pAtcd) return;
  // ATCD CIM10
  if (pAtcd->isCIM10())
  { QString strlistCode="";
    QString result = G_pCApp->m_pDrTux->CodageCim10All(DrTux::ATCDString, strlistCode);
    if (result.length()<=0) return;
    // Récupère le libellé et le code sélectionné
    int p = result.find("::");
    QString libelle = result.left(p);
    QString code = result.mid(p+2);
    // Enlève de la liste l'Atcd à modifier
    m_Atcd_Liste.remove(*pAtcd);
    // Change libelle et code
    pAtcd->m_Libelle = libelle;
    pAtcd->m_Code = "~"+code.left( code.length()-2)+"~";
    // Remet l'Atcd modifié dans la liste
    m_Atcd_Liste.append (*pAtcd);
    setSort(CApp::SortByRubrique);
    emitATCD_Changed();
  } // Fin modifyCIM10
  // ATCD ALLERGIQUE
  else if (pAtcd->isAllergie() )
  { // Appel le Widget de saisie ATCD allergique
    DlgAllergie *dlg =      new DlgAllergie();
    if (dlg ==0)            return;
    if (dlg->exec() == QDialog::Rejected)            {delete dlg; return;}  // si annuler cassos
    if (dlg->listView_Choix->childCount ()<=0)       {delete dlg; return;}  // si liste de choix vide  cassos
    // Récupère le premier item de la liste de choix (car ici on modifie un ATCD)
    QListViewItem* item = dlg->listView_Choix->firstChild();
    if (!item) return;
    QString libelle = item->text(0);
    QString code = "("+item->text(1)+")";
    // Enlève de la liste l'Atcd à modifier
    m_Atcd_Liste.remove(*pAtcd);
    // Change libelle et code
    pAtcd->m_Libelle = libelle;
    pAtcd->m_Code = code;
    // Remet l'Atcd modifié dans la liste
    m_Atcd_Liste.append (*pAtcd);
    setSort(CApp::SortByRubrique);
    emitATCD_Changed();
    delete dlg;
  }
  // ATCD TEXTE LIBRE
  else
  { // Appel le Widget de saisie ATCD en texte libre
    DlgAtcd_txt* pDlgAtcd_txt = new DlgAtcd_txt();
    if (!pDlgAtcd_txt) return;
    pDlgAtcd_txt->setRubriques( m_Rubriques_ATCD_Med, m_Rubriques_ATCD_Chir);
    pDlgAtcd_txt->setATCD_toView( this, pAtcd);
    pDlgAtcd_txt->setToUpdate(TRUE);
    pDlgAtcd_txt->exec();
    if (pDlgAtcd_txt->result() == QDialog::Accepted)
    { // Récupère les données du widget
      QString libelle, commentaire, date, rubrique;
      QDate dt ;
      pDlgAtcd_txt->getInfos(libelle, rubrique, date, commentaire);
      if (date != "") dt = QDate::fromString(date, Qt::ISODate);
      else dt = QDate();
      int id_ATCD = pAtcd->getId();
      m_Atcd_Liste.remove (*pAtcd);
      pAtcd = new Atcd_Element(rubrique, libelle, dt, "", 0, commentaire);
      pAtcd->setId( id_ATCD );
      m_Atcd_Liste.append (*pAtcd);
    }
    if (pDlgAtcd_txt) delete pDlgAtcd_txt;
    emitATCD_Changed();
  }
}

//------------------------------ changeDDR --------------------------------------------------
/*! \brief Affiche le widget calendar pour modifier la date des dernières règles.
*/
void Atcd_Code::changeDDR()
{ Dlg_Calendar* dlg  = new Dlg_Calendar(0, "Calendar_Dial", FALSE);
 if (dlg==0) return;
 dlg->setCaption(TR("Date des dernières règles"));
 dlg->move ( QCursor::pos().x(), QCursor::pos().y() );
 if (m_DDR.isValid() )
    { dlg->setDate(m_DDR);
      dlg->SelectDateAll();
    }
 if (dlg->exec()== QDialog::Accepted )
    { m_DDR       = dlg->getDate();
      m_Grossesse = TRUE;
      emit ATCD_Changed();
    }
 if (dlg) delete dlg;
}

//------------------------------ changeEtat --------------------------------------------------
/*! \brief Change l'état de l'antécédent, passé en paramètre, de Actif<->Guéri.
*/
void Atcd_Code::changeEtat(Atcd_Element* pAtcd)
{ if (!pAtcd) return;
  switch (pAtcd->m_Etat)
  { case 0 : pAtcd->m_Etat = 1;  break;
    case 1 : pAtcd->m_Etat = 0;  break;
  }
 emitATCD_Changed();
}


//------------------------------ changeCommentaire --------------------------------------------------
/*! \brief Appel un widget pour changer le commentaire de l'antécédent.
*/
void Atcd_Code::changeCommentaire(Atcd_Element* pAtcd)
{ if (CGenTools::DialogGetString(0, TR("Saisir un commentaire (mode texte libre)") , pAtcd->m_Commentaire) == QDialog::Accepted)
  {  emitATCD_Changed();
  }
}

//------------------------------ eraseAtcd --------------------------------------------------
/*! \brief Change l'état de l'antécédent, passé en paramètre, de Actif<->Guéri.
*/
void Atcd_Code::eraseAtcd(Atcd_Element* pAtcd)
{ if (!pAtcd) return;
  // Trouve l'Atcd dans la liste
  m_Atcd_Liste.remove( *pAtcd );
 emitATCD_Changed();
}


