/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set et sw=2 ts=2: */
/***************************************************************************
 *            praxisd.cc
 *
 *  Tue Apr 19 09:00:29 CEST 2011
 *  Copyright 2011 Bent Bisballe Nyeng
 *  deva@aasimon.org
 ****************************************************************************/
/*
 *  This file is part of Pracro.
 *
 *  Pracro is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Pracro is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Pracro; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
#include "praxisd.h"
#include "saxparser.h"
static std::string strtime(bool with_sec = true)
{
  std::string ret;
  time_t epoch = time(NULL);
  struct tm t;
  localtime_r(&epoch, &t);
  char buf[32];
  snprintf(buf, sizeof(buf), "%04d-%02d-%02d",
           t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
  ret = buf;
  if(with_sec) {
    snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
             t.tm_hour, t.tm_min, t.tm_sec);
    ret += " ";
    ret += buf;
  }
  return ret;
}
static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
  std::string *str = (std::string*)userp;
  str->append((char*)buffer, size * nmemb);
  return size * nmemb;
}
Praxisd::Praxisd(std::string h, int port)
{
  ch = curl_easy_init();
  host = h;
  curl_easy_setopt(ch, CURLOPT_PORT, port);
  curl_easy_setopt(ch, CURLOPT_FAILONERROR, 1L);
  curl_easy_setopt(ch, CURLOPT_TIMEOUT, 150L);
  curl_easy_setopt(ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  curl_easy_setopt(ch, CURLOPT_CONNECTTIMEOUT, 15L);
  curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L);
  curl_easy_setopt(ch, CURLOPT_USERAGENT, "libpraxisd");
  curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, write_data);
  curl_easy_setopt(ch, CURLOPT_FILETIME, 1L);
  curl_easy_setopt(ch, CURLOPT_HEADER, 0L);
}
Praxisd::~Praxisd()
{
  curl_easy_cleanup(ch);
}
// Get Journal By CPR
std::string Praxisd::journal_get_by_cpr(std::string cpr)
{
  std::string journal;
  std::string uri = host + "/praxisd/1.0/journal/get_by_cpr?cpr=" + cpr;
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &journal);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch %d\n", errornum);
  }
  time_t time;
  errornum = curl_easy_getinfo(ch, CURLINFO_FILETIME, &time);
  return journal;
}
time_t Praxisd::journal_last_changed(std::string cpr)
{
  std::string journal;
  std::string uri = host + "/praxisd/1.0/journal/get_by_cpr?cpr=" + cpr;
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &journal);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch %d\n", errornum);
  }
  time_t time;
  errornum = curl_easy_getinfo(ch, CURLINFO_FILETIME, &time);
  return time;
}
void Praxisd::journal_add(std::string cpr, std::string entry)
{
  std::string xml;
  xml += "\n";
  xml += "  "+entry+"\n";
  xml += "\n";
  curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, (long)xml.length());
  curl_easy_setopt(ch, CURLOPT_POSTFIELDS, xml.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 1L);
  struct curl_slist *slist = NULL;
 // Unset 'Expect' header, set by CURLOPT_POSTFIELDS
  slist = curl_slist_append(slist, "Expect:");
  slist = curl_slist_append(slist, "Content-Type: text/xml");
  slist = curl_slist_append(slist, "Connection: keep-alive");
  curl_easy_setopt(ch, CURLOPT_HTTPHEADER, slist);
  std::string uri = host + "/praxisd/1.0/journal/add";
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  std::string reply;
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &reply);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch: %d %s\n", errornum, reply.c_str());
  }
}
void Praxisd::add_sogeord(std::string cpr, std::string sogeord,
                          std::string sogetxt)
{
  std::string datestr = strtime(false);
  std::string xml;
  xml += "\n";
  xml += "  \n";
  xml += "    "+
    sogetxt+"\n";
  xml += "  \n";
  xml += "\n";
  curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, (long)xml.length());
  curl_easy_setopt(ch, CURLOPT_POSTFIELDS, xml.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 1L);
  struct curl_slist *slist = NULL;
 // Unset 'Expect' header, set by CURLOPT_POSTFIELDS
  slist = curl_slist_append(slist, "Expect:");
  slist = curl_slist_append(slist, "Content-Type: text/xml");
  slist = curl_slist_append(slist, "Connection: keep-alive");
  curl_easy_setopt(ch, CURLOPT_HTTPHEADER, slist);
  std::string uri = host + "/praxisd/1.0/patient/add_sogeord";
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  std::string reply;
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &reply);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch: %d %s\n", errornum, reply.c_str());
  }
}
#define DOTAG(x) if(name == #x) str = &p.x; 
class PatientParser : public SAXParser {
public:
  PatientParser(Praxisd::patient_t &_p) : p(_p) { str = NULL; }
  void characterData(std::string &data)
  {
    if(str) *str += data;
  }
  void startTag(std::string name, attributes_t &attr)
  {
    DOTAG(fornavne);
    DOTAG(efternavn);
    DOTAG(stilling);
    DOTAG(gade);
    DOTAG(by);
    DOTAG(telefonnumre);
    DOTAG(sikringsgr);
    DOTAG(amtsnr);
    DOTAG(sygekontor);
    DOTAG(henvnr);
    DOTAG(frilinie1);
    DOTAG(frilinie2);
    DOTAG(frilinie3);
    DOTAG(frilinie4);
    DOTAG(frilinie5);
    DOTAG(ydernr);
    DOTAG(created);
    DOTAG(donottouch);
    DOTAG(visus);
    DOTAG(labkort);
    DOTAG(medkort);
    DOTAG(jlock);
    DOTAG(unknown1);
    DOTAG(henvdato);
    DOTAG(aarhund);
    DOTAG(fakturadato);
    DOTAG(fakturabelob);
    DOTAG(betaldato);
    DOTAG(betalbelob);
    DOTAG(jdato);
    DOTAG(unknown250);
    DOTAG(unknown251);
    DOTAG(jtime);
    if(name == "sogeords") {} // do nothing
    if(name == "sogeord") {
      Praxisd::sogeord_t s;
      if(attr.find("sogenr") != attr.end()) s.sogenr = attr["sogenr"];
      if(attr.find("sogedato") != attr.end()) s.sogedato = attr["sogedato"];
      p.sogeord.push_back(s);
      str = &p.sogeord[p.sogeord.size() - 1].sogetxt;
    }
  }
  void endTag(std::string)
  {
    str = NULL;
  }
  
private:
  std::string *str;
  Praxisd::patient_t &p;
};
Praxisd::patient_t Praxisd::patient_get_by_cpr(std::string cpr)
{
  patient_t p;
  std::string xml;
  std::string uri = host + "/praxisd/1.0/patient/get_by_cpr?cpr=" + cpr;
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &xml);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch %d\n", errornum);
  }
  //  printf("Get Patient: %d %s\n", xml.length(), xml.c_str()); fflush(stdout);
  PatientParser parser(p);
  parser.parse(xml.data(), xml.length());
  return p;
}
std::string Praxisd::get_sogenr(std::string sogenr)
{
  std::string xml;
  std::string uri = host + "/praxisd/1.0/diverse/get_all_by_sogenr?sogenr=" +
    sogenr;
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &xml);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch %d\n", errornum);
  }
  return xml;
}
#define DODIVTAG(x) if(name == #x) str = &div[div.size() - 1].x; 
class AdresseParser : public SAXParser {
public:
  AdresseParser(std::vector &al) : div(al) { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_adresse") {
      Praxisd::adresse_t a;
      if(attr.find("sogenr") != attr.end()) a.sogenr = attr["sogenr"];
      div.push_back(a);
    }
    DODIVTAG(edi_adresse);
    DODIVTAG(navn);
    DODIVTAG(att);
    DODIVTAG(gade);
    DODIVTAG(by);
    DODIVTAG(tlf);
    DODIVTAG(fax);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector Praxisd::diverse_get_adresse(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("A"+sogenr);
  AdresseParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class BehandlingParser : public SAXParser {
public:
  BehandlingParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_behandling") {
      Praxisd::behandling_t a;
      if(attr.find("sogenr") != attr.end()) a.sogenr = attr["sogenr"];
      div.push_back(a);
    }
    DODIVTAG(kode);
    DODIVTAG(behandling);
    DODIVTAG(bemaerkning);
    DODIVTAG(udregning);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_behandling(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("B"+sogenr);
  BehandlingParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class CaveParser : public SAXParser {
public:
  CaveParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_cave") {
      Praxisd::cave_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(cave);
    DODIVTAG(bemaerkning1);
    DODIVTAG(bemaerkning2);
    DODIVTAG(bemaerkning3);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector Praxisd::diverse_get_cave(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("C"+sogenr);
  CaveParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class DiagnoseParser : public SAXParser {
public:
  DiagnoseParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_diagnose") {
      Praxisd::diagnose_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(kode);
    DODIVTAG(diagnose);
    DODIVTAG(bemaerkning);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_diagnose(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("D"+sogenr);
  DiagnoseParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class FraseParser : public SAXParser {
public:
  FraseParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_frase") {
      Praxisd::frase_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(frase1);
    DODIVTAG(frase2);
    DODIVTAG(frase3);
    DODIVTAG(frase4);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector Praxisd::diverse_get_frase(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("F"+sogenr);
  FraseParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class GrafikParser : public SAXParser {
public:
  GrafikParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_grafik") {
      Praxisd::grafik_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(navn);
    DODIVTAG(bemaerkning);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector Praxisd::diverse_get_grafik(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("G"+sogenr);
  GrafikParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class IndholdstofParser : public SAXParser {
public:
  IndholdstofParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_indholdstof") {
      Praxisd::indholdstof_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(indholdstof);
    DODIVTAG(form1);
    DODIVTAG(form2);
    DODIVTAG(form3);
    DODIVTAG(form4);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_indholdstof(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("I"+sogenr);
  IndholdstofParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class KlageParser : public SAXParser {
public:
  KlageParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_klage") {
      Praxisd::klage_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(kode);
    DODIVTAG(klage);
    DODIVTAG(bemaerkning);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_klage(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("K"+sogenr);
  KlageParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class OversigtParser : public SAXParser {
public:
  OversigtParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_oversigt") {
      Praxisd::oversigt_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(navn);
    DODIVTAG(bemaerkning);
  }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_oversigt(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("O"+sogenr);
  OversigtParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class PostnummerParser : public SAXParser {
public:
  PostnummerParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_postnummer") {
      Praxisd::postnummer_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(postnummer);
    DODIVTAG(by_gade);
    DODIVTAG(kbh);
    DODIVTAG(amtsnr);
    DODIVTAG(kommunenr);
    DODIVTAG(regionnavn);
    DODIVTAG(kommunenavn); 
 }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_postnummer(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("P"+sogenr);
  PostnummerParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class TypeParser : public SAXParser {
public:
  TypeParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_type") {
      Praxisd::type_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(type);
    DODIVTAG(bemaerkning1); 
    DODIVTAG(bemaerkning2); 
    DODIVTAG(bemaerkning3); 
 }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_type(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("T"+sogenr);
  TypeParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class UndersoegelseParser : public SAXParser {
public:
  UndersoegelseParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_undersoegelse") {
      Praxisd::undersoegelse_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(kode);
    DODIVTAG(undersoegelse); 
    DODIVTAG(udregning); 
 }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_undersoegelse(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("U"+sogenr);
  UndersoegelseParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class YdelseParser : public SAXParser {
public:
  YdelseParser(std::vector &d) : div(d)
  { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "div_ydelse") {
      Praxisd::ydelse_t d;
      if(attr.find("sogenr") != attr.end()) d.sogenr = attr["sogenr"];
      div.push_back(d);
    }
    DODIVTAG(nr);
    DODIVTAG(gr1); 
    DODIVTAG(gr2); 
    DODIVTAG(privat); 
    DODIVTAG(journal1); 
    DODIVTAG(journal2); 
    DODIVTAG(moms); 
 }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector
Praxisd::diverse_get_ydelse(std::string sogenr)
{
  std::vector lst;
  std::string xml = get_sogenr("Y"+sogenr);
  YdelseParser parser(lst);
  parser.parse(xml.data(), xml.length());
  return lst;
}
class AftaleParser : public SAXParser {
public:
  AftaleParser(std::vector &a) : div(a) { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "aftale") {
      Praxisd::aftale_t a;
      if(attr.find("date") != attr.end()) a.date = attr["date"];
      if(attr.find("calendar") != attr.end()) a.date = attr["calendar"];
      div.push_back(a);
    }
    DODIVTAG(cpr);
    DODIVTAG(cref);
    DODIVTAG(cmrk); 
    DODIVTAG(ctxt); 
    DODIVTAG(cres); 
 }
  
private:
  std::string *str;
  std::vector ÷
};
static std::string i2s(int i) {
  char buf[32];
  snprintf(buf, sizeof(buf), "%d", i);
  return buf;
}
std::vector
Praxisd::aftale_get_all_by_date_and_calendar(int cal, int year, int month,
                                             int day)
{
  std::vector aft;
  std::string xml;
  std::string uri = host + "/praxisd/1.0/aftale/get_all_by_date_and_calendar?"
    "calendar=" + i2s(cal) + "&year=" + i2s(year) + "&month=" + i2s(month) +
    "&day=" + i2s(day);
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &xml);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch %d\n", errornum);
  }
  AftaleParser parser(aft);
  parser.parse(xml.data(), xml.length());
  return aft;
}
std::vector Praxisd::aftale_get_all_by_cpr(std::string cpr)
{
  std::vector aft;
  std::string xml;
  std::string uri = host + "/praxisd/1.0/aftale/get_all_by_cpr?cpr=" + cpr;
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &xml);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch %d\n", errornum);
  }
  AftaleParser parser(aft);
  parser.parse(xml.data(), xml.length());
  return aft;
}
bool Praxisd::authenticate(std::string user, std::string pass)
{
  std::string uri = host + "/praxisd/1.0/authenticate?user=" + user + "&pass=" +
    pass;
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, NULL);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    return false;
  }
  long code = 0;
  errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code); 
  if(code == 401) return false;
  if(code == 200) return true;
  return false; // Don't interpret an error as successful login.
}
class DokMenuParser : public SAXParser {
public:
  DokMenuParser(std::vector &a) : div(a) { str = NULL; }
  void characterData(std::string &data) { if(str) *str += data; }
  void endTag(std::string) { str = NULL; }
  void startTag(std::string name, attributes_t &attr)
  {
    if(name == "dokmenu") {
      Praxisd::dokmenu_t a;
      if(attr.find("date") != attr.end()) a.date = attr["date"];
      if(attr.find("calendar") != attr.end()) a.date = attr["calendar"];
      div.push_back(a);
    }
    DODIVTAG(group);
    DODIVTAG(subject);
    DODIVTAG(filename);
    if(name == "filename") {
      div[div.size() - 1].filesize = atoi(attr["filesize"].c_str());
      div[div.size() - 1].date = attr["date"];
    }
 }
  
private:
  std::string *str;
  std::vector ÷
};
std::vector Praxisd::dokmenu_get_all_by_cpr(std::string cpr)
{
  std::vector dokmenu;
  std::string xml;
  std::string uri = host + "/praxisd/1.0/dokmenu/get_all_by_cpr?cpr=" + cpr;
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &xml);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch %d\n", errornum);
  }
  DokMenuParser parser(dokmenu);
  parser.parse(xml.data(), xml.length());
  return dokmenu;
}
// Get Dokmenu by Name and CPR
std::string Praxisd::dokmenu_get_by_cpr_and_name(std::string cpr,
                                                 std::string name)
{
  std::string data;
  std::string uri = host + "/praxisd/1.0/dokmenu/get_by_cpr_and_name?cpr=" +
    cpr + "&name=" + name;
  curl_easy_setopt(ch, CURLOPT_URL, uri.c_str());
  curl_easy_setopt(ch, CURLOPT_POST, 0L);
  curl_easy_setopt(ch, CURLOPT_WRITEDATA, &data);
  CURLcode errornum = curl_easy_perform(ch);
  if(errornum != CURLE_OK) {
    printf("Ouch %d\n", errornum);
  }
  return data;
}
#ifdef TEST_PRAXISD
//deps: saxparser.cc debug.cc log.cc
//cflags: $(CURL_CFLAGS) $(EXPAT_CFLAGS) -I..
//libs: $(CURL_LIBS) $(EXPAT_LIBS)
#include "test.h"
#define NL "\r\n"
#define CPR "1505050505"
TEST_BEGIN;
Praxisd p("http://localhost", 10000);
std::string j = p.journal_get_by_cpr(CPR);
TEST_NOTEQUAL(j, "", "Did we get a journal?");
std::string more = "less is more... much much more.";
p.journal_add(CPR, more);
time_t changed = p.journal_last_changed(CPR);
TEST_EQUAL_INT(changed, time(NULL), "Changed just now?");
Praxisd::patient_t patient = p.patient_get_by_cpr(CPR);
TEST_EQUAL_STR(patient.fornavne, "Kristian", "Who are you?");
/*
std::string exp = j + more + NL;
std::string j2 = p.journal_get_by_cpr(CPR);
TEST_EQUAL_INT(exp.length(), j2.length(), "Compare lengths");
TEST_EQUAL_STR(exp, j2, "Did we correctly append to the journal?");
*/
//p.add_sogeord(CPR, "CA0003", "Nolder");
{
  std::vector cave = p.diverse_get_cave("A0001");
  TEST_EQUAL_INT(cave.size(), 1, "Precicely one result.");
  TEST_EQUAL_STR(cave[0].cave, "AZOPT", "The correct one?");
}
{
  std::vector cave = p.diverse_get_cave("");
  TEST_EQUAL_INT(cave.size(), 25, "Get them all.");
}
{
  std::vector dm = p.dokmenu_get_all_by_cpr(CPR);
  TEST_NOTEQUAL_INT(dm.size(), 0, "Empty result?");
  std::string file = p.dokmenu_get_by_cpr_and_name(CPR, dm[0].filename);
  TEST_EQUAL_INT(file.size(), dm[0].filesize, "Size matters?");
}
TEST_END;
#endif/*TEST_PRAXISD*/