#ifndef LEPTO_LOG_H_
#define LEPTO_LOG_H_
//----------------------------------------------------------------------------
//
// \brief   Logging with lepto
//
//----------------------------------------------------------------------------

#if 0

#include <lepto/debug.h>
#if defined(NDEBUG)
#include <stdio.h>      // puts
#include <string.h>     // strlen
#endif

// lDebug   : Only show when debugging/verbose
// lHint    : Show (unless silent is specified)
// lWarn    : Show
// lError   : Show
#if defined(NO_LOG)
   #define lDebug CLogDummy()
   #define lWarn CLogDummy()
   #define lHint CLogDummy()
   #define lError CLogDummy()
   #define lErrorExit CLogDummy()
   #define lAssert( assertion ) if ( ! (assertion) ) \
      exception( "Assertion wrong", -1 );
   #define lAssertC( assertion, comment ) if ( ! (assertion) ) \
      exception( "Assertion wrong", -1 );
#elif defined(NANO)
   //#define lHint 0
   #define lDebug CLogNano( 0 )
   #define lHint CLogNano( 0 )
   #define lWarn CLogNano( 0 )
   #define lErrorExit CLogNano( 0 ) \
                        << eLogTypeErrorExit
   #define lAssert( assertion ) if ( ! (assertion) ) \
      lErrorExit << "Assertion wrong:" #assertion;

      // exception( "Assertion" , 0);
#elif defined(NDEBUGX)
   #define lDebug CLogDummy()
   //#define lHint CLog( "-", "-" , 0 )
   //#define lWarn CLog( "-", "-" , 0 )
   #define lHint CLogDummy()
   #define lWarn CLogDummy()
   #define lError CLogDummy()
   //#define lErrorExit CLog(__FILE__, __PRETTY_FUNCTION__ , __LINE__)
   //                     << eLogTypeErrorExit
   #define lAssert( assertion ) if ( ! (assertion) ) \
      { /* puts( "Assertion wrong:" "" #assertion "\n"); */ while(1){}; }

   #define lAssertC( assertion, comment ) if ( ! (assertion) ) \
      { /* puts( "Assertion wrong:" "" #assertion "\n" ); */ while(1){}; }


   //if ( ! (assertion) )
   //   lErrorExit << "Assertion wrong:" << "" #assertion << "; " << comment;

      // exception( "Assertion" , 0);
#elif 0
   #define lDebug CLog() << eLogTypeDebug
   #define lHint CLog()
   #define lWarn CLog() << eLogTypeWarn
   #define lError CLog() << eLogTypeError
   #define lErrorExit CLog() \
                        << eLogTypeErrorExit
   #define lHintLineInstance CLog logInstance(__FILE__, __FUNCTION__ , __LINE__)
   #define lHintLine logInstance
   #define lAssert( assertion ) if ( ! (assertion) ) \
      lErrorExit << "Assertion wrong:" << "" #assertion << "; ";
   #define lAssertC( assertion, comment ) if ( ! (assertion) ) \
      lErrorExit << "Assertion wrong:" << "" #assertion << "; " << comment;
#elif 0
   #define lDebug CLog(__FILE__, __PRETTY_FUNCTION__ , __LINE__) << eLogTypeDebug
   #define lHint CLog(__FILE__, __PRETTY_FUNCTION__ , __LINE__)
   #define lInfo CLog(__FILE__, __PRETTY_FUNCTION__ , __LINE__) << eLogTypeInfo
   #define lWarn CLog(__FILE__, __PRETTY_FUNCTION__ , __LINE__) << eLogTypeWarn
   #define lError CLog(__FILE__, __PRETTY_FUNCTION__ , __LINE__) << eLogTypeError
   #define lErrorExit CLog(__FILE__, __PRETTY_FUNCTION__ , __LINE__) \
                        << eLogTypeErrorExit
   #define lHintLineInstance CLog logInstance(__FILE__, __PRETTY_FUNCTION__ , __LINE__)
   #define lHintLine logInstance
   #define lAssert( assertion ) if ( ! (assertion) ) \
      lErrorExit << "Assertion wrong:" << "" #assertion << "; ";
   #define lAssertC( assertion, comment ) if ( ! (assertion) ) \
      lErrorExit << "Assertion wrong:" << "" #assertion << "; " << comment;
#elif 0
   #define __PARAMS __FILE__, __PRETTY_FUNCTION__ , __LINE__
   #define PARAMS
   #if defined (NDEBUG)
   #define lDebug CLogDummy()
   #else
   #define lDebug CLogNano( PARAMS ) << eLogTypeDebug
   #endif
   #define lHint CLogNano( PARAMS ) << eLogTypeInfo
   #define lInfo CLogNano( PARAMS ) << eLogTypeInfo
   #define lWarn CLogNano( PARAMS ) << eLogTypeWarn
   #define lError CLogNano( PARAMS ) << eLogTypeError
   //#define lErrorExit CLogNano( PARAMS ) << eLogTypeErrorExit
   //#define _lAssert( assertion ) if ( ! (assertion) )
   //            lErrorExit << "Assertion wrong";
   #define lAssert( assertion ) if ( ! (assertion) )while(1){;} \

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

#elif 0
    #include <stdlib.h>
    #define lHint CLog("A", "B", 1)
    #define lHintKlInstance CLog logInstance("A", "B", 1);
    #define lHintKl logInstance
    #define lErrorExit exit(22);CLog("A", "B", 1)
    shutup;
#else
#endif

class CLog;

#define MAX_NUMBER_DIGITS  0x10
#define MAX_LOG_LEN        80
#define LOG_BUF_SIZE       0x10

/*
class CLogTypeInteger
{
   private:
      int base;
      int digits;
      int value;

      // It has to be stored in the class because the string ponter is
      // kept until CLog is destructed.
      char buf[MAX_NUMBER_DIGITS];

   public:
      CLogTypeInteger();
      const char*toString();
};

char *intToStr(int value, int maxBuf, char buf);
*/
//class CLogCistern;
class CLogOutput;
//extern CLogCistern stdLogCistern;
//extern CLogCistern *stdLogCistern_p;
//#define stdLogCistern (*stdLogCistern_p)


enum ELogBase
{
   eLogBaseDec    =  10,
   eLogBaseHex    =  0x10,

   eLogBaseDefault=  eLogBaseHex,
};


enum ELogType
{
   eLogTypeOk        =  1,
   eLogTypeInfo      =  2,
   //eLogTypeHint      =  3,
   eLogTypeDebug     =  3,
   eLogTypeWarn      =  4,
   eLogTypeError     =  5,
   eLogTypeErrorExit =  6,
   eLogTypeAssert    =  7,

   eLogTypeDefault   =  eLogTypeInfo,
};

extern "C"
{
   void trouble();
   void critical();
   int heartBeatImplementation();
}

// Only Nolepto-Version
void callbackLogPuts(const char *fragment);

class CLogNano
{
   private:
      //static int m_pos;
      //static bool m_doExit;
      //ELogType m_logType=eLogTypeInfo;
      int m_pos=0;

   public:
      //const CLogNano &operator << (const char *fragment) const;
      //const CLogNano &operator << (char value) const;
      //const CLogNano &operator << (int value) const;
      //const CLogNano &operator << (long int value) const;
      //const CLogNano &operator << (unsigned long int value) const;
      typedef int CursrPos;
      enum EPrinter{
         newline
      };
      CLogNano()
      {
         //m_pos=0;
      };

      CLogNano &operator <<(const char *str)
      {
         fputs(str, stdout);
         m_pos+=strlen(str);
         return(*this);
      }
      ~CLogNano()
      {
         fputs("\n", stdout);
         //if(m_doExit)
         //{
         //   while(1){};
         //}
      }
      CLogNano &operator <<(ELogBase base)
      {
         return(*this);
      }
      CLogNano &operator <<(uint32_t val)
      {
         return(this->hex(val,8));
      }
      CLogNano &operator <<(uint16_t val)
      {
         return(this->hex(val,4));
      }
      CLogNano &hex(uint32_t val, int digits)
      {
         fputs("0x", stdout);
         for(int i1=digits-1; i1>=0; i1--)
         {
            char str[]={'0', 0};
            int nibble=( (val>>(i1*4)) & 0xF );
            if(nibble<=9)
               str[0]='0'+nibble;
            else
               str[0]='A'+(nibble-0xA);
            fputs(str, stdout);
         }
         return(*this);
      }
      CLogNano &operator <<(int val)
      {
         return( *this << (long int)val );
      }
      CLogNano &operator <<(long int val)
      {
         char buf[12]; // Amount of digits + 1
         char *s=buf + sizeof(buf) -1;
         *s=0;

         do
         {
            *(--s)='0'+(val % 10);
            val/=10;
         }while(val);


         *this << s;
         return(*this);
      }
      CLogNano &operator <<(char val)
      {
         char buf[2]={0,0};
         buf[0]=val;
         *this << buf;
         return(*this);
      }
      CLogNano &operator <<(EPrinter p)
      {
         switch(p)
         {
            case(newline):
               fputs("\n", stdout);
               break;
         }
         return(*this);
      }
      CLogNano &operator ^(int val)
      {
         return(*this);
      }
      CLogNano &operator ||(int val)
      {
         return(*this);
      }
      CLogNano &operator *()
      {
         return(*this);
      }
      CLogNano &locate(int pos)
      {
         while( m_pos < pos )
         {
            fputs(" ", stdout);
            m_pos++;
         }
         return(*this);
      }
      CLogNano &operator <<(ELogType et)
      {
         //m_logType=et;
         switch(et)
         {
            case(eLogTypeError):
               *this << "Error: ";
               break;
            case(eLogTypeWarn):
               *this << "Warning: ";
               break;
            case(eLogTypeDebug):
               *this << "Debug: ";
               break;
            case(eLogTypeInfo):
               break;
            //case(eLogTypeErrorExit):
            //   *this << "Fatal: ";
            //   m_doExit=true;
            //   break;
            default:
               while(1){};
               break;
         }

         return(*this);
      }
};


class CLogDummy
{
   public:
      CLogDummy(){return;};
      ~CLogDummy(){return;};
      const CLogDummy &operator << (const char *fragment) const {return(*this);};
      const CLogDummy &operator << (char value) const {return(*this);};
      const CLogDummy &operator << (int value) const {return(*this);};
      const CLogDummy &operator << (long int value) const {return(*this);};
      const CLogDummy &operator << (unsigned long int value) const {return(*this);};
};

#ifndef NANO
#if 0
class CLog
{
    friend class CLogOutput;

   private:
      ELogBase eLogBase;
      ELogType eLogType;

      static CLogOutput *m_pOutput;
      static char m_buf[LOG_BUF_SIZE];
      //static char oBuf[MAX_LOG_LEN + 1];
      //static char *buffer;
      int pos;
      static void (*exceptionFunction)(void);

      const char *fileName;
      const char *functionName;
      int line;
      
   public:
      // int countFragments;
      // const char *listFragments[0x100];
      CLog(const char *_fileName, const char *_functionName
           , int _line
           , ELogType _eLogType = eLogTypeHint
           //, CLogCistern *_cistern_p=stdLogCistern_p
           );
      CLog();
      ~CLog();
      static void setOutput(CLogOutput *output)
      {
         m_pOutput = output;
      }

      void putStr(const char *str);
      void putChar(const char ch);
      void prepareOutputString();
      void prepareEmptyOutputString();
      CLog &operator << (ELogBase _eLogBase);
      CLog &operator << (ELogType _eLogType);
      CLog &operator << (const char *fragment);
      CLog &operator << (char value);
      CLog &operator << (int value);
      CLog &operator << (unsigned int value);
      CLog &operator << (long int value);
      CLog &operator << (unsigned long int value);
      // CLog &operator << (int64_t value);
      // CLog &operator << (int32_t value);
      CLog &operator << (double value);
      CLog &addString(const char *fragment);
      //const char *addToOutputString(const char *str);
      //const char *getOutputString();
      const char *getStatusText();
      static void setExceptionFunction(void (*exceptionFunction)(void));
};
#endif
#endif

#endif

//---fin----------------------------------------------------------------------
#endif // ? ! _LEPTO_LOG_H_
