//*************************************************************************
//
//  Pack Pi Decimals (Tool) - C++ language
//
//  PackPiDecimals.cpp
//
//  Developed by Armando Giuseppe BONATTO MINELLA.
//
//*************************************************************************
#include <QtCore>
#include <iostream>
//*************************************************************************
#define SOURCE_HEAD_SIZE             18ull
#define SOURCE_TAIL_SIZE              4ull
#define SOURCE_FILESIZE_MIN 85899345942ull // SOURCE_HEAD_SIZE + (TARGET_BYTES * 2) + SOURCE_TAIL_SIZE
#define TARGET_BYTES        42949672960ull
//*************************************************************************
typedef enum : std::int32_t
{
  Executable     = 0,
  SourceFilename = 1,
  TargetFilename = 2
} Arguments_t;
//*************************************************************************
std::int32_t main (std::int32_t   argc   ,
                   char         * argv [] )
{
  if (!((argc                                                         >  Arguments_t::TargetFilename)          &&
        QFile::exists (QString (argv [Arguments_t::SourceFilename]))                                           &&
        (QFile (QString (argv [Arguments_t::SourceFilename])).size () >= ((std::int64_t) SOURCE_FILESIZE_MIN))   ))
  {
    std::cout << ""                                                                                                                << std::endl
              << "WARNING: invalid command line arguments"                                                                         << std::endl
              << ""                                                                                                                << std::endl
              << "Usage: PackPiDecimals <Source filename> <Target filename>"                                                       << std::endl
              << "       +--> Source filename"                                                                                     << std::endl
              << "            +--> Minimum size of " << QString::asprintf ("%'llu",SOURCE_FILESIZE_MIN).toStdString () << " bytes" << std::endl
              << ""                                                                                                                << std::endl;
  }
  else
  {
    QString sourceFilename                  = QString (argv [Arguments_t::SourceFilename]);
    QString targetFilename                  = QString (argv [Arguments_t::TargetFilename]);
    QFile   sourceFile     (sourceFilename)                                               ;
    //-------------------------------------
    if (sourceFile.open (QIODeviceBase::ReadOnly))
    {
      if (sourceFile.seek (SOURCE_HEAD_SIZE))
      {
        QFile targetFile (targetFilename);
        //-------------------------------------
        if (targetFile.open (QIODevice::WriteOnly |
                             QIODevice::Truncate   ))
        {
          std::uint8_t nibbles [2]     ;
          std::uint8_t byte        = 0u;
          //-------------------------------------
          for (std::uint64_t index = 0ull;(index < TARGET_BYTES);index += 1ull)
          {
            sourceFile.read (((char *) nibbles)       ,
                             (sizeof (std::uint8_t) *
                              2ll                    ) );
            if ((((nibbles [0] >= 0x30u) &&          // "0"
                  (nibbles [0] <= 0x39u)   ) ||      // "9"
                 ((nibbles [0] >= 0x61u) &&          // "a"
                  (nibbles [0] <= 0x66u)   )   ) &&  // "f"
                (((nibbles [1] >= 0x30u) &&
                  (nibbles [1] <= 0x39u)   ) ||
                 ((nibbles [1] >= 0x61u) &&
                  (nibbles [1] <= 0x66u)   )   )   )
            {
              if ((nibbles [0] >= 0x30u) &&
                  (nibbles [0] <= 0x39u)   )
              {
                nibbles [0] -= 0x30u;
              }
              else
              {
                nibbles [0] -= 0x57u;
              }
              if ((nibbles [1] >= 0x30u) &&
                  (nibbles [1] <= 0x39u)   )
              {
                nibbles [1] -= 0x30u;
              }
              else
              {
                nibbles [1] -= 0x57u;
              }
              byte = ((nibbles [0] << 4) +
                      nibbles [1]         );
              targetFile.write (((char *) (& (byte))),
                                sizeof (std::uint8_t) );
            }
            else
            {
              std::cout << "ERROR: invalid data in source file ('" << sourceFilename.toStdString () << "')" << std::endl;
              targetFile.close ();
              sourceFile.close ();
              return (EXIT_FAILURE);
            }
          }
          targetFile.close ();
        }
        else
        {
          std::cout << "ERROR: cannot create target file ('" << targetFilename.toStdString () << "')" << std::endl;
          sourceFile.close ();
          return (EXIT_FAILURE);
        }
      }
      else
      {
        std::cout << "ERROR: cannot seek source file ('" << sourceFilename.toStdString () << "')" << std::endl;
        sourceFile.close ();
        return (EXIT_FAILURE);
      }
      sourceFile.close ();
    }
    else
    {
      std::cout << "ERROR: cannot open source file ('" << sourceFilename.toStdString () << "')" << std::endl;
      return (EXIT_FAILURE);
    }
    std::cout << std::endl;
  }
  return (EXIT_SUCCESS);
}
//*************************************************************************

