/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set et sw=2 ts=2: */
/***************************************************************************
 *            sessionserialiser.cc
 *
 *  Thu May 20 11:26:18 CEST 2010
 *  Copyright 2010 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 "sessionserialiser.h"

#include "journal.h"

#include "sessionparser.h"
#include "database.h"

#include "xml_encode_decode.h"
//#include "base64.h"

#include <stdio.h>
#include <string.h>

std::string getSessionFilename(const std::string &path,
                               const std::string &sessionid)
{
  return path + "/pracro_session." + sessionid;
}


static std::string itostr(int i)
{
  char sid[32];
  snprintf(sid, sizeof(sid), "%d", i);
  return sid;
}

SessionSerialiser::SessionSerialiser(std::string path)
{
  this->path = path;
}

#define XENC(s) xml_encode(s)
#define XDEC(s) xml_decode(s)

//#define BENC(s) base64encode(s)
//#define BDEC(s) base64decode(s)

Session *SessionSerialiser::loadStr(const std::string &xml,
                                    const std::string &sessionid)
{
  //  SessionAutolock lock(*session);
  SessionParser parser;
  parser.parse(xml.data(), xml.length());

  Session *session = new Session(sessionid, parser.patientid, "");
  Journal *j = session->journal();
  j->setUser(XDEC(parser.userid));
  j->setPatientID(XDEC(parser.patientid));
  std::vector<SessionParser::Entry>::iterator i = parser.entries.begin();
  while(i != parser.entries.end()) {
    j->addEntry(XDEC(i->resume), xml_decode(i->macro), i->index);
    i++;
  }

  session->database()->restore(XDEC(parser.database));

  return session;
}

std::string SessionSerialiser::saveStr(Session *session)
{
  //  SessionAutolock lock(*session);

  std::string xml;

  xml += "<?xml version='1.0' encoding='UTF-8'?>\n";
  xml += "<session timestamp=\""+itostr(time(NULL))+"\" "
    "id=\""+session->id()+"\">\n";

  Journal *journal = session->journal();

  xml += "  <journal patientid=\"" + XENC(journal->patientID()) +
    "\" userid=\"" + XENC(journal->user()) + "\">\n";

  std::map< int, Journal::ResumeEntry >::iterator i =
    journal->entrylist.begin();
  while(i != journal->entrylist.end()) {

    xml += "    <entry index=\""+itostr(i->first) + "\""
      " macro=\"" + i->second.macro + "\">\n";
    xml += "      <resume>" + XENC(i->second.resume) + "</resume>\n";
    xml += "    </entry>\n";

    i++;
  }

  xml += "  </journal>\n";

  std::string dbtype = "pgsql";
  xml += "  <database type=\""+dbtype+"\">"+
    XENC(session->database()->serialise())+
    "</database>\n";

  xml += "</session>\n";

  return xml;
}

Session *SessionSerialiser::load(const std::string &sessionid)
{
  // read xml from file
  std::string filename = getSessionFilename(path, sessionid);

  FILE *fp =  fopen(filename.c_str(), "r");
  std::string xml;
  while(!feof(fp)) {
    char str[64];
    memset(str, 0, sizeof(str));
    fread(str, sizeof(str) - 1, 1, fp);
    xml += str;
  }
  fclose(fp);

  Session *session = loadStr(xml, sessionid);

  // delete file
  unlink(filename.c_str());
  
  return session;
}

void SessionSerialiser::save(Session *session)
{
  std::string filename = getSessionFilename(path, session->id());

  std::string xml = saveStr(session);

  // write xml to file
  FILE *fp =  fopen(filename.c_str(), "w");
  fwrite(xml.data(), xml.size(), 1, fp);
  fclose(fp);
}

#ifdef TEST_SESSIONSERIALISER
//deps: session.cc journal.cc debug.cc configuration.cc mutex.cc journal_commit.cc sessionparser.cc saxparser.cc
//cflags: -I.. $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS)
//libs: $(PTHREAD_LIBS) $(EXPAT_LIBS)
#include "test.h"

#define SID "42"
#define SPATH "/tmp"

TEST_BEGIN;

std::string xml;

{
  Session session(SID);
  Journal *j = session.journal();
  j->addEntry("some text", "macro1", 0);
  j->addEntry("some more text", "macro2", 2);
  j->addEntry("yet some more text", "macro3", 1);
  SessionSerialiser s(SPATH, &session);
  xml = s.saveStr();
  s.loadStr(xml);
  std::string xml2 = s.saveStr();
  TEST_EQUAL_STR(xml, xml2, "Compare");
}

{
  Session session(SID);
  Journal *j = session.journal();
  j->addEntry("some text", "macro1", 0);
  j->addEntry("some more text", "macro2", 2);
  j->addEntry("yet some more text", "macro3", 1);
  SessionSerialiser s(SPATH, &session);
  xml = s.saveStr();
}

{
  Session session(SID);
  SessionSerialiser s(SPATH, &session);
  s.loadStr(xml);
  std::string xml2 = s.saveStr();
  TEST_EQUAL_STR(xml, xml2, "Compare");
}

{
  Session session(SID);
  Journal *j = session.journal();
  j->addEntry("some text", "macro1", 0);
  j->addEntry("some more text", "macro2", 2);
  j->addEntry("yet some more text", "macro3", 1);
  SessionSerialiser s(SPATH, &session);
  s.save();
}

{
  Session session(SID);
  SessionSerialiser s(SPATH, &session);
  s.load();
  std::string xml2 = s.saveStr();
  TEST_EQUAL_STR(xml, xml2, "Compare");
}


TEST_END;

#endif/*TEST_SESSIONSERIALISER*/