#ifndef INCSTR_H
#include <incstr.h>
#endif

#include <applicat.h>
#include <mailbox.h>
#include <utility.h>

#define DEF_MSGS_CAPACITY 8
#define MAX_TXT_LEN 256

TMessage::TMessage(const char* to, const char* sub, 
                   const char* text, const char* from)
{ 
  TString rec(to);
  if (rec.not_empty() && (rec.len() != 6 || rec.strip(" -") != to))
    rec = cmd2name(to); 
  _to = rec;  
  _subject = sub;
  _text = text;

  rec = from;
  if (rec.not_empty())
  {
    if (rec.len() != 6 || rec.strip(" -") != from)
      rec = cmd2name(from); 
  }
  else
    rec = main_app().name();

  _from = rec;
  _flags = 0x00;
}

void TMessage::send()
{
  TMailbox mail;
  mail.send(*this);
}


void TMailbox::reread()
{
  char buf[MAX_TXT_LEN];

  ifstream mbox(_path);

  // skip read messages
  mbox.seekg(_lastpos);
  while (mbox.getline(buf, MAX_TXT_LEN -1) != NULL)
  {
    // process new message
    TMessage* tmnew = new TMessage (NULL, NULL, NULL, buf);
    // lines are <from> <subject> <body>
    mbox.getline(buf, MAX_TXT_LEN -1);
    tmnew->subject(buf);
    mbox.getline(buf, MAX_TXT_LEN -1);
    tmnew->body(buf);
    _msgs.add(tmnew);
    // tmnew->number(_msgs.items());
    n_new++;
  }
  _lastpos = mbox.tellg();
}

TMessage* TMailbox::next_unread()
{
  // returns next unread message;
  if (_cnt == _msgs.items())
    return NULL;
  while(this->get(_cnt)->isread())
  {
    _cnt++;
    if (_cnt == _msgs.items())
      return NULL;
  }
  n_new --;
  return this->get(_lastread = _cnt);
}

TMessage* TMailbox::next_read()
{
  // next read/unread message
  if (_cnt == _msgs.items()) 
    return NULL; 
  if (!(this->get(_cnt)->isread()))
    n_new--;
  return this->get(_cnt++);
}

// @doc EXTERNAL

// @mfunc Ritorna il prossimo messaggio
TMessage* TMailbox::next(
  bool read)  // @parm Indica se il messaggio deve essere tra quelli
  //       letti (default FALSE)

  // @comm Se <p read> e' TRUE ritorna il prossimo messaggio non letto
{
  TMessage* m = read ? next_read() : next_unread(); 
  if (m) 
    m->setread();
  return m;
}

// @doc EXTERNAL

// @mfunc Ritorna il prossimo messaggio con lo stesso oggetto
TMessage* TMailbox::next_s(
  const char* s,    // @parm Oggetto del messaggio da ritornare
  bool read)  // @parm Indica se il messaggio deve essere tra quelli
  //       letti (default FALSE)

  // @comm Ricerca tra i messaggi quello che possiede l'oggetto passato in <p s>.
  //       Se <p read> ritorna il primo messaggio non letto.
{
  for (;;)
  {
    if (_cnt == _msgs.items()) 
      return NULL; 
    if (strcmp(this->get(_cnt)->subject(), s) == 0)
    {
      if (read) break;
      else
      {
        if (!(this->get(_cnt)->isread())) break;
      }
    } 
    _cnt++;
  }
  this->get(_cnt)->setread();
  if (!read) n_new--;
  return this->get(_cnt);
}

// @doc EXTERNAL

// @mfunc Ritorna il prossimo messaggio con lo stesso mandante
TMessage* TMailbox::next_f(
  char* f,    // @parm Oggetto del messaggio da ritornare
  bool read)  // @parm Indica se il messaggio deve essere tra quelli
  //       letti (default FALSE)

  // @comm Ricerca tra i messaggi quello che possiede il mandate passato in <p f>.
  //       Se <p read> ritorna il primo messaggio non letto.
{
  for (;;)
  {
    if (_cnt == _msgs.items()) 
      return NULL; 
    if (strcmp(this->get(_cnt)->from(), f) == 0)
    {
      if (read) break;
      else { if (!(this->get(_cnt)->isread())) break; }
    } 
    _cnt++;
  }
  this->get(_cnt)->setread();
  if (!read) n_new--;
  return this->get(_cnt);
}

void TMailbox::send(TMessage& m)
{
  CHECK(m.from().not_empty() && m.to().not_empty() &&
        (m.subject().not_empty() || m.body().not_empty()),
        "Can't send partially empty message");

  //    strcpy(to_path, getenv("TMPDIR") == NULL ? MAILDIR : getenv("TMPDIR"));
  TFilename to_path; to_path.tempdir();
  to_path.add(m.to());
  to_path.ext("mbx");

  ofstream fto(to_path, ios::app);
  CHECK(fto.good(),"send: trouble opening mailbox file");
  fto << m.from() << '\n' << m.subject() << '\n' << m.body() << '\n';
  fto.close();
}

void TMailbox::sendcmd(int argc, char* argv[], char* to)
{
  NFCHECK("MAILBOX::COMMANDLINE INTERFACE NOT IMPLEMENTED");
  for (int i = 0; i < argc; i++)
  {
    // parse argv[i]
    // create new message
    // send it out
  }
}

char* TMailbox::readcmd(char*)
{
  // filters all messages to recipient and adds to to_path
  NFCHECK("MAILBOX::COMMANDLINE INTERFACE NOT IMPLEMENTED");
  // TMessage* m;
  return "NOT YET IMPLEMENTED";
}

TMailbox::TMailbox(const char* appname) : _msgs(DEF_MSGS_CAPACITY)
{
  if (appname == NULL)
    appname = main_app().name();  // myself; must be global

  _path.tempdir();
  _path << SLASH << appname << ".mbx";

  _lastread =0;  _lastpos = 0l;
  n_new = 0;
  this->reread();
  restart();
}

TMailbox::~TMailbox()
{
  TMessage* m;
  // scan all remaining messages and erase mailbox
  reread();
  if (fexist(_path))
    remove(_path);
  // send unread messages to myself
  while((m = next()) != NULL)
  {
    m->to(main_app().name());
    send(*m);
  }
}