/***************************************************************************
                          mymoneyutils.cpp  -  description
                             -------------------
    begin                : Tue Jan 29 2002
    copyright            : (C) 2000-2002 by Michael Edwardes
    email                : mte@users.sourceforge.net
                           Javier Campos Morales <javi_c@users.sourceforge.net>
                           Felix Rodriguez <frodriguez@users.sourceforge.net>
                           John C <thetacoturtle@users.sourceforge.net>
                           Thomas Baumgart <ipwizard@users.sourceforge.net>
                           Kevin Tambascio <ktambascio@users.sourceforge.net>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>

#include "mymoneyutils.h"
#include "mymoneyaccount.h"

#include <cstdio>
#include <cstdarg>
#include <cstdlib>

#include <tqregexp.h>

#ifdef _CHECK_MEMORY

#undef new
#undef _CheckMemory_Leak
#undef _CheckMemory_FreeAll

_CheckMemory chkmem;
bool enable=false;

_CheckMemoryEntry::_CheckMemoryEntry(void *p, int line, size_t size, const char *file)
  : m_p(p), m_line(line), m_size(size), m_file(file)
{
}

_CheckMemoryEntry::_CheckMemoryEntry()
  : m_p(0), m_line(0), m_size(0)
{
}


/////////////////////////////////////////////////////////////////////////////////////////
_CheckMemory::_CheckMemory()
{
  outfunc = (_CheckMemoryOutFunc *)NULL;
}

_CheckMemory::_CheckMemory(_CheckMemoryOutFunc *out)
{
  outfunc = out;
}

_CheckMemory::~_CheckMemory()
{
}

_CheckMemoryOutFunc *_CheckMemory::SetOutFunc(_CheckMemoryOutFunc *out)
{
  _CheckMemoryOutFunc *old;
  old = outfunc;
  outfunc = out;
  return old;
}

void _CheckMemory::Output(const char *fmt,...)
{
  va_list args;
  char buf[128];
  va_start(args,fmt);
  if(outfunc) {
    vsprintf(buf,fmt,args);
    outfunc(buf);
  }
  else {
    vfprintf(stderr,fmt,args);
    putc('\n', stderr);
  }
  va_end(args);
}

int _CheckMemory::TableCount(void)
{
  return table.size();
}

bool _CheckMemory::CheckMemoryLeak(bool freeall)
{
  bool d = false;
  size_t total = 0;
  int freec = 0;
  CheckMemoryTable::ConstIterator it;

  for(it = table.begin(); it != table.end(); ++it) {
    if((*it).pointer() != 0) {
      total += (*it).size();
      freec++;
      if(d == false) {
        Output("CheckMemory++: CheckMemoryLeak: Memory leak detected!");
        Output("Position  |Size(bytes)  |Allocated at");
        d=true;
      }
      if(d==true)
        Output("%p |%-13d|%s:%d",(*it).pointer(),(int)(*it).size(),(*it).file(),(*it).line());
    }
  }
  if(d == true)
    Output("You have forgotten to free %d object(s), %d bytes of memory.",freec, (int)total);
  else
    Output("CheckMemory++: CheckMemoryLeak: No memory leak detected.");
  if(freeall == true)
    FreeAll();
  return true;
}

void _CheckMemory::FreeAll()
{
  size_t total=0;
  int freec=0;
  CheckMemoryTable::Iterator it;

  for(it = table.begin(); it != table.end(); it = table.begin()) {
    if((*it).pointer() != 0) {
      total += (*it).size();
      freec++;
      Output("CheckMemory++: FreeAll: freed %d bytes of memory at %p.",(int)(*it).size(),(*it).pointer());
      free((*it).pointer());
    }
    table.remove(it);
  }
  Output("CheckMemory++: FreeAll: Totally freed %d objects, %d bytes of memory.",freec,(int)total);
}

void _CheckMemory_Init(_CheckMemoryOutFunc *out)
{
  if(enable!=true) {
    chkmem.Restart();
    chkmem.SetOutFunc(out);
    enable=true;
  }
}

void _CheckMemory_End()
{
  if(enable!=false) {
    chkmem.Restart();
    chkmem.SetOutFunc(NULL);
    enable=false;
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
void *operator new(size_t s,const char *file,int line) throw()
{
  void *p = malloc(s);

  if(p == NULL) throw;
  if(enable==true) {
    _CheckMemoryEntry entry(p, line, s, file);
    chkmem.table[p] = entry;
  }
  return p;
}

void * operator new [] (size_t s,const char *file,int line) throw()
{
  void *p = malloc(s);

  if(p == NULL) throw;
  if(enable==true) {
    _CheckMemoryEntry entry(p, line, s, file);
    chkmem.table[p] = entry;
  }
  return p;
}

void operator delete(void *p) throw()
{
  if(enable==true) {
    CheckMemoryTable::Iterator it;
    it = chkmem.table.find(p);
    if(it != chkmem.table.end()) {
      chkmem.table.remove(it);
    }
  }
  free(p);
}

void operator delete [] (void *p) throw()
{
  if(enable==true) {
    CheckMemoryTable::Iterator it;
    it = chkmem.table.find(p);
    if(it != chkmem.table.end()) {
      chkmem.table.remove(it);
    }
  }
  free(p);
}

#endif // _CHECK_MEMORY

TQString MyMoneyUtils::getFileExtension(TQString strFileName)
{
  TQString strTemp;
  if(!strFileName.isEmpty())
  {
    //find last . delminator
    int nLoc = strFileName.findRev('.');
    if(nLoc != -1)
    {
      strTemp = strFileName.right(strFileName.length() - (nLoc + 1));
      return strTemp.upper();
    }
  }
  return strTemp;
}

int MyMoneyTracer::m_indentLevel = 0;
int MyMoneyTracer::m_onoff = 0;

MyMoneyTracer::MyMoneyTracer(const char* name)
{
  if(m_onoff) {
    TQRegExp exp("(.*)::(.*)");
    if(exp.search(name) != -1) {
      m_className = exp.cap(1);
      m_memberName = exp.cap(2);
    } else {
      m_className = TQString(name);
      m_memberName = TQString();
    }
    TQString indent;
    indent.fill(' ', m_indentLevel);
    std::cerr << indent.latin1() << "ENTER: " << m_className.latin1() << "::" << m_memberName.latin1() << std::endl;
  }
  m_indentLevel += 2;
}

MyMoneyTracer::MyMoneyTracer(const TQString& className, const TQString& memberName) :
  m_className(className),
  m_memberName(memberName)
{
  if(m_onoff) {
    TQString indent;
    indent.fill(' ', m_indentLevel);
    std::cerr << indent.latin1() << "ENTER: " << m_className.latin1() << "::" << m_memberName.latin1() << std::endl;
  }
  m_indentLevel += 2;
}

MyMoneyTracer::~MyMoneyTracer()
{
  m_indentLevel -= 2;
  if(m_onoff) {
    TQString indent;
    indent.fill(' ', m_indentLevel);
    std::cerr << indent.latin1() << "LEAVE: " << m_className.latin1() << "::" << m_memberName.latin1() << std::endl;
  }
}

void MyMoneyTracer::printf(const char *format, ...) const
{
  if(m_onoff) {
    va_list args;
    va_start(args, format);
    TQString indent;
    indent.fill(' ', m_indentLevel);
    std::cerr << indent.latin1();

    vfprintf(stderr,format,args);
    putc('\n', stderr);
    va_end(args);
  }
}

void MyMoneyTracer::onOff(int onOff)
{
  m_onoff = onOff;
}

void MyMoneyTracer::on(void)
{
  m_onoff = 1;
}

void MyMoneyTracer::off(void)
{
  m_onoff = 0;
}

TQString dateToString(const TQDate& date)
{
  if(!date.isNull() && date.isValid())
    return date.toString(TQt::ISODate);

  return TQString::null;
}

TQDate stringToDate(const TQString& str)
{
  if(str.length()) {
    TQDate date = TQDate::fromString(str, TQt::ISODate);
    if(!date.isNull() && date.isValid())
      return date;
  }
  return TQDate();
}

TQString TQStringEmpty(const TQString& val)
{
  if(!val.isEmpty())
    return TQString(val);

  return TQString::null;
}

unsigned long extractId(const TQString& txt)
{
  int pos;
  unsigned long rc = 0;

  pos = txt.find(TQRegExp("\\d+"), 0);
  if(pos != -1) {
    rc = txt.mid(pos).toLong();
  }
  return rc;
}
