//DRS_Error.cpp

#include <windows.h>

#include <cstdio>
#include <vector>

#include "drs/drs_error.h"

/////////////////////////////////////////////////////////////////////////////////////
//DRS_Errors
/////////////////////////////////////////////////////////////////////////////////////
DRS_ErrorMissingConfig * DRS_ErrorMissingConfig::clone
  ()
  const
{
  return new DRS_ErrorMissingConfig(*this);
}

void DRS_ErrorMissingConfig::report
  (DRS_Error::Reporter &reporter)
  const
{
  reporter.report(this);
}

/////////////////////////////////////////////////////////////////////////////////////
//DRS_ErrorFormat
/////////////////////////////////////////////////////////////////////////////////////
na_string DRS_ErrorFormat::Param( const AT_Error *const err, char const * prefix)
{
  na_string s;

  if( !!err->getObjectName() && strlen(err->getObjectName()))
  {
    if( prefix)
      s = prefix;
    else
      s = "\n";

    s += (char const *) err->getObjectName();

  }

  return s;
}

na_string DRS_ErrorFormat::ObjectStamp( const AT_Error *const err)
{
  na_string s;

  #ifndef NDEBUG

    if( !!err->getObjectType() && strlen(err->getObjectType()))
      {
      s += "\n   [Object: ";
      s +=(const char *)err->getObjectType();
      s += "]";
      }

  #endif

  return s;
}

na_string DRS_ErrorFormat::FileStamp( const AT_Error *const err)
{

  na_string s;

  #ifndef NDEBUG
  s = "\n   [File ";

  s +=  (const char *) err->getModule();
  s += " at line ";
  s += ultoa(err->getLineNum(), (char*) num_buf, 10);
  s += "]";

  #endif

  return s;
}

na_string DRS_ErrorFormat::ErrorNum( const AT_System_Error *const err)
{
  na_string s;

    s = ultoa(err->getErrorNum(), (char*) num_buf, 10);

  return s;
}

void DRS_ErrorFormat::PushErr(const AT_Error *const err)
{
  na_string s;

    s = "Unknown application error.";
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_ErrorFormat::PushErr(const AT_General_Error *const err)
{
  na_string s;

    s = "General error.";
    s += ObjectStamp(err);
    s += FileStamp(err);
    s += " ";
    s += err->getObjectType();
    s += " ";
    s += err->getObjectName();

  vStrings.push_back( s );
}

void DRS_ErrorFormat::PushErr(const AT_System_Error *const err)
{
  na_string s;

    s = "System error: ";
    s += ErrorNum(err);
    s += "\nMessage: ";
    LPVOID lpMsgBuf;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                  NULL,
                  err->getErrorNum(),
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                  (LPTSTR) &lpMsgBuf,
                  0,
                  NULL);
    s += (char *)lpMsgBuf;
    LocalFree(lpMsgBuf);
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );

}

/////////////////////////////////////////////////////////////////////////////////////
//DRS_ConfigFormat
/////////////////////////////////////////////////////////////////////////////////////
void DRS_ConfigFormat::PushErr(const DRS_ErrorMissingConfig *const err)
{
  na_string s;

    s = "Application configuration error:\n[";
    s += (const char *) err->Section();
    s += "] ";
    s += (const char *) err->Key();
    s += "\nFile ";
    if( char const * p = strrchr( (char const *) err->File(), '\\') )
      s += (++p);
    else
      s += (const char *) err->File();
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

/////////////////////////////////////////////////////////////////////////////////////
//DRS_GenFormat
/////////////////////////////////////////////////////////////////////////////////////
void DRS_GenFormat::PushErr( const AT_Bounds_Error *const err)
{
  na_string s;

    s = Param( err, "" );
    s += " ";
    if( (long) err->getBadValue() == -1L)
      s += "-1";
    else
      s += itoa(err->getBadValue(), (char*) num_buf, 10);
    s += " is out of bounds.";
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_GenFormat::PushErr(const AT_Logic_Error *const err)
{
  na_string s;

    s = "Logic error:";
    s += Param(err);
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_GenFormat::PushErr(const AT_Corrupt_Error *const err)
{
  na_string s;

    s = "Corruption error:";
    s += Param(err);
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_GenFormat::PushErr(const AT_File_Open_Error *const err)
{
  na_string s;

    s = "Cannot open file";
    s += Param( err, " ");
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_GenFormat::PushErr(const AT_File_Type_Error *const err)
{
  na_string s;

    s = "Bad file type ";
    /*
    s += err->getActual();
    s += "\n";
    s += "Expected ";
    s += err->getExpected();
    */
    s += Param(err);
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_GenFormat::PushErr(const AT_File_Read_Error *const err)
{
  na_string s;

    s = "Cannot read file";
    s += Param( err, " ");
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_GenFormat::PushErr(const AT_File_Write_Error *const err)
{
  na_string s;

    s = "Cannot write to file";
    s += Param( err, " ");
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_GenFormat::PushErr(const AT_Constructor_Error *const err)
{
  na_string s;

    s = "Cannot construct";
    s += Param( err, " ");
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );

}

void DRS_GenFormat::PushErr(const AT_Function_Error *const err)
{
  na_string s;

    s = "Unimplemented function:";
    s += Param(err);
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );

}

void DRS_GenFormat::PushErr(const AT_Unexpected_Error *const err)
{
  na_string s;

    s = "Unexpected error:";
    s += Param(err);
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );

}

/////////////////////////////////////////////////////////////////////////////////////
//DRS_IdxFormat
/////////////////////////////////////////////////////////////////////////////////////
void DRS_IdxFormat::PushErr( const AT_Index_List::noIndex *const err)
{
  na_string s;

    s = "Index not available.";
    //s += Param(err);
    s += ObjectStamp(err);
    s += FileStamp(err);
  vStrings.push_back( s );
}

void DRS_IdxFormat::PushErr( const AT_Index_List::openError *const err)
{

  na_string s;

   #ifndef NDEBUG
       s = "Cannot open index ";
       s += itoa(err->getIndexNum(), (char*) num_buf, 10);
       s += ".";
    #else
       s = "Cannot open index.";
     #endif
    //s += Param(err);
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

void DRS_IdxFormat::PushErr(const AT_Parse::Error *const err)
{
  na_string s;

   #ifndef NDEBUG
       s = "Search criterion error: Position: ";
       s += itoa(err->getPos(), (char*) num_buf, 10);
       s += " Length: ";
       s += itoa(err->getLen(), (char*) num_buf, 10);       
       s += ".";
    #else
       s = "Search criterion error: ";
     #endif
    //s += Param(err);
    s += ObjectStamp(err);
    s += FileStamp(err);

  vStrings.push_back( s );
}

/////////////////////////////////////////////////////////////////////////////////////
//DRS_Error::Reporter
/////////////////////////////////////////////////////////////////////////////////////
void DRS_Error::Reporter::report(const AT_Error *const err)
{
  DRS_ErrorFormat::PushErr(err);
}

void DRS_Error::Reporter::report(const AT_System_Error *const err)
{
  DRS_ErrorFormat::PushErr(err);
}

void DRS_Error::Reporter::report(const DRS_ErrorMissingConfig *const err)
{
  PushErr(err);
}

/////////////////////////////////////////////////////////////////////////////////
//AT_GeralError::Reporter implementation
/////////////////////////////////////////////////////////////////////////////////

void AT_GenErrorReporter::report(const AT_Error *const err)
{
  DRS_ErrorFormat::PushErr(err);
}

// PS added
void AT_GenErrorReporter::report(const AT_General_Error *const err)
{
  DRS_ErrorFormat::PushErr(err);
}

void AT_GenErrorReporter::report( const AT_Bounds_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_Logic_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_Corrupt_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_System_Error *const err)
{
  DRS_ErrorFormat::PushErr(err);
}

void AT_GenErrorReporter::report(const AT_File_Open_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_File_Type_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_File_Read_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_File_Write_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_Constructor_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_Function_Error *const err)
{
  PushErr(err);
}

void AT_GenErrorReporter::report(const AT_Unexpected_Error *const err)
{
  PushErr(err);
}

/////////////////////////////////////////////////////////////////////////////////
//AT_IdxErrorReporter
/////////////////////////////////////////////////////////////////////////////////
void AT_IdxErrorReporter::report( const AT_Index_List::noIndex *const err)
{
  PushErr(err);
}

void AT_IdxErrorReporter::report( const AT_Index_List::openError *const err)
{
  PushErr(err);
}

void AT_IdxErrorReporter::report( const AT_Parse::Error *const err)
{
  PushErr(err);
}

void AT_IdxErrorReporter::report(const AT_System_Error *const err)
{
  DRS_ErrorFormat::PushErr(err);
}

void AT_IdxErrorReporter::report(const AT_Error *const err)
{
  DRS_ErrorFormat::PushErr(err);
}
