//----------------------------------------------------------------------------
//
// \brief   Main
//
//----------------------------------------------------------------------------


//---Includes-----------------------------------------------------------------


//---Objects/Variables--------------------------------------------------------


#include <arena/arena.h>
#include <arena_app.h>
#include <minutnik.hpp>
#include <lepto/logoutput_console.h>

#define USE_TERMINAL
//#define BOOTLOADER
#undef BOOTLOADER
 
#ifdef USE_TERMINAL
#include <fosh/fosh.hpp>
#include <fosh/command.h>
#endif

// #include <HALWrapper/stm32_hal.h>    // REMAP
#include <biwak/output_blink_modes.h>
#include <ocelli/clock.hpp>
#include <ocelli/ocelli.hpp>
#include <ocelli/screen.hpp>
#include <ocelli/button.hpp>
#include <ocelli/screen_navi.hpp>
#include <ocelli/icon.hpp>
#include <ocelli/theme.hpp>
#include <screen_minutnik.h>
#include <fosh/commands/signal.hpp>
#include <biwak/biwak.h>
#include <lepto/time.h>                // USEC_PER_SEC


#ifdef USE_TERMINAL
const CCommand *createInstance_stop(CPlatform *platform);
const CCommand *createInstance_freeze(CPlatform *platform);
const CCommand *createInstance_hwinfo(CPlatform *platform);
const CCommand *createInstance_info(  );
const CCommand *createInstance_gd( CGraphicDisplayIli9341 &display );
const CCommand *createInstance_i2c( CI2c &i2c );
const CCommand *createInstance_date( CRtc &rtc );
const CCommand *createInstance_hwclock( CI2cSlave &slave, CRtc &rtc );
#endif

//---Implementation-----------------------------------------------------------


class CHwinfo:public CCommand
{
      CMinutnik *m_minutnik;

   public:
      CHwinfo(CMinutnik *minutnik)
            :CCommand("hwinfo", "Show production data")
            ,m_minutnik(minutnik)
      {
         return;
      }
      virtual int exec(int argc, const char * argv[]) const override;

};

int CHwinfo::exec(int argc, const char * argv[]) const
{
   m_minutnik->printHWInfo();
   return(0);
};

const CCommand *createInstance_hwinfo(CMinutnik *minutnik)
{
   return(new CHwinfo(minutnik));
}

#if ! defined (NDEBUG)
   extern int handlerFreezerKeeper;
#endif

CMinutnik *pMinutnik=nullptr;

#if 0


void readFlashData(int addr, void *dest, size_t size)
{
   pCanDis->m_flash.readData(addr, dest, size);
}

void writeFlashData(int addr, void *src, size_t size)
{
   pCanDis->m_flash.writeData(addr, src, size);
}

void eraseFlash()
{
   pCanDis->m_flash.eraseChip();
   pCanDis->m_flash.waitForReady();
}
#endif

#if 0
void cross(CGraphicDisplay &display, int x, int y, TRgb color)
{
   display.drawLine(x-10, y-10, x+10, y+10, color);
   display.drawLine(x-10, y+10, x+10, y-10, color);
}


void calibrate(CTouchTsc2007 &touch, CGraphicDisplay &display)
{
   struct SCoord{int x; int y;};
   const SCoord coords[3]={
       {25,25},
       {display.width()-10,10},
       {display.width()-10,display.height()-10}
   };
   SCoord values[3];
   int dummyX, dummyY, dummyZ1, dummyZ2;
   
   display.clear( black );
   display.setFont(getFont8());
   const char *text="PRESS THE CROSSES";
   display.drawText((display.width()/2)-(strlen(text)*4), display.height()/2-4, text);
   pCanDis->m_pwmBacklight.setPwmValue(1000);
   lInfo("Press");
   for(int i1=0; i1<3; i1++)
   {
         pCanDis->eventLoop();
         biwakEventLoop();
         
         bool pressed=false;
         cross(display, coords[i1].x, coords[i1].y, white);
         while( !pressed )
         {
            pCanDis->eventLoop();
            biwakEventLoop();
            touch.readTouch(dummyX, dummyY, dummyZ1, dummyZ2);
            lInfo("Z1/Z2: %d/%d", dummyZ1, dummyZ2);
            usleep(10);
            if( dummyZ1 > 500 )
            {
               pressed=true;
            }
         }
         cross(display, coords[i1].x, coords[i1].y, green);
         while( pressed )
         {
            pCanDis->eventLoop();
            biwakEventLoop();
            touch.readTouch(dummyX, dummyY, dummyZ1, dummyZ2);
            if( dummyZ1 < 10 )
            {
               pressed=false;
            }
            usleep(10);
         }
         cross(display, coords[i1].x, coords[i1].y, black);
         usleep(USEC_PER_SEC);
         lInfo( "%d: %d / %d", i1, values[i1].x, values[i1].y );
         values[i1].x*=0x100;
         values[i1].y*=0x100;
   }
   int xVpp=( values[0].x-values[1].x ) / (display.width()-20);
   int xOffset=values[1].x-(10*xVpp);
   int yVpp=( values[1].y-values[2].y ) / (display.height()-20);
   int yOffset=values[2].x-(10*yVpp);
   lInfo( "xVpp: %d / xOffset: %d", xVpp, xOffset);
   lInfo( "yVpp: %d / yOffset: %d", yVpp, yOffset);
   
   //touch.calibrate(xOffset, xVpp, display.width(), yOffset, yVpp, display.height());
}
#endif

int main(void)
{
   biwakInit();
   arenaInit();
   
   pMinutnik=new CMinutnik;
   
   fputs( "\n\n" , stdout );
   
   biwakPrintBaseInfo();
   biwakPrintClockInfo();
   biwakPrintMemoryInfo();
   biwakPrintDateInfo();
   
   pMinutnik->m_pwmBuzzer.setPwmValue(500);
   pMinutnik->m_outputSpiCS.setValue(false);

   #ifdef USE_TERMINAL
      CFosh term;
      CI2cSlave i2cRtc(pMinutnik->m_i2c1, 0x6F);
      //term.addCommand( createInstance_date( pCanIO->m_rtc1) );
      //term.addCommand( createInstance_stop( pCanDis ) );
      //term.addCommand( createInstance_freeze( pCanDis ) );
      //term.addCommand( createInstance_sf( spiFlash ) );
      //term.addCommand( createInstance_info() );
      term.addCommand( createInstance_hwinfo( pMinutnik ) );
      //term.addCommand( createInstance_gd( pCanDis->m_gdisplayIli93411 ) );
      //term.addCommand( createInstance_i2c( pCanDis->m_i2c1 ) );
      term.addCommand( createInstance_date( pMinutnik->m_rtc1 ) );
      term.addCommand( createInstance_hwclock( i2cRtc, pMinutnik->m_rtc1 ) );
      //term.addCommand( createInstance_eeprom( pCanDis->m_eeprom ) );
      term.addCommand( new CCommandSignal( "config", "show/set confiduration\n"
                                           "       config                       : show current confugration\n"
                                           "       config reset                 : set default configuration\n"
                                           "       config <slot> <time> <text>  : configure single slot"
                                           , pMinutnik, &CMinutnik::commandConfig ) );
      term.addCommand( new CCommandSignal( "eraseflash", "Erase media flash"
                                         , pMinutnik, &CMinutnik::eraseFlash ) );
      term.addCommand( new CCommandSignal( "forceCalib", "force touch calibration"
                                         , pMinutnik, &CMinutnik::forceTouchCalibration ) );
   #endif
      
   //calibrate(pCanDis->getTouch(), *pCanDis->getDisplay());
      
   pMinutnik->prepareApplication();
   //pCanDis->appInfo();
   
   pMinutnik->m_gdisplayIli93411.setDrawBackground(true);
   
   printf( " \n" );
   printf( "start: %d\n", lrElapsedMSeconds(0) );
   
   while( 1 )
   {
      pMinutnik->eventLoop();
      //pCanDis->m_pCan1->buffer.clear();
      biwakEventLoop();
      #ifdef USE_TERMINAL
         term.eventLoop();
      #endif
 
      // screenCanmon.eventLoop();
      // screenMinutnik.eventLoop();

      //handlePendingSignals();
#if 0
      if( lrElapsedMSeconds(&clockTimer, MSECS_PER_SEC/4) )
      {
         static char text[20];
         int hour, minute, second;
         static int phour, pminute, psecond=-1;
         pCanDis->m_rtc1.getTime(hour, minute, second);
         {
            if( ( phour != hour) || ( pminute != minute) || ( psecond != second ) )
            {
               snprintf(text, 20, "%02d:%02d:%02d", hour, minute, second);
               pCanDis->m_gdisplayIli93411.setFont(getFont32());
               pCanDis->m_gdisplayIli93411.drawText(4,100, text);
            }
         }
      }
#endif
      if( ! ( pMinutnik->isBootloaderActive()
               || pMinutnik->isAlarmActive() ) )
      {
         // 1/24 minutnik-clock still ugly
         // 1/48 would work for phonyBl but quite slow flashing
         // 1/96 is ok for alarm audio
         usleep( USEC_PER_SEC / 48 ); 
      }

      //counter++;
   }

   return(0);
}


//---fin----------------------------------------------------------------------
