#ifndef CALIBRATION_APP_HPP
#define CALIBRATION_APP_HPP
//----------------------------------------------------------------------------
///
/// \brief   Simple ui for performing an touch screen calibration
///
///          User has to press on crosses
///
/// \date   20240827
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


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


//---Own------------------------------

#include <biwak/gdisplay.h>
#include <biwak/touch_tsc2007.h>


//---Declaration--------------------------------------------------------------


/**
 * @brief   Simple UI for performing an touch screen calibration
 *
 *          The user is asked to press crosses on the display. After 3 or 4
 *          crosses, the application is finished. The main application can read
 *          the values and store it in retain field.
 *
 *          The main application can integrate this UI by creating an instance
 *          and keep it running by calling eventLoop() periodically.
 *          When finished() returns true, the main application can use the
 *          calibration values.
 */
class CCalibrationApp
{
   private:
      CGraphicDisplay* m_display;
       CTouchTsc2007* m_touch;
      struct SCoord{int x; int y;};
      static constexpr int m_crossBorder=25;
      static constexpr int m_touchPressLevel=400;
      static constexpr int m_touchReleaseLevel=10;
      const SCoord coords[4]={
          // Starting in the left upper corner, clockwise
          { m_crossBorder, m_crossBorder },
          { m_display->width() - m_crossBorder, m_crossBorder },
          { m_display->width() - m_crossBorder, m_display->height() - m_crossBorder },
          { m_crossBorder, m_display->height() - m_crossBorder },
      };
      SCoord m_values[4];
      int m_touchX, m_touchY, m_touchZ1, m_touchZ2;
      int m_crossIndex=0;

      enum class EState{
         Start,
         WaitInitialRelease,
         StartCross,
         WaitPressed,
         WaitReleased,
         SwitchNextCross,
         Finished,
         Stopped,
      } m_state=EState::Start;

   public:
      CCalibrationApp( CGraphicDisplay* display, CTouchTsc2007* touch )
         :m_display( display )
         ,m_touch( touch )
      {
      }
      void clearScreen()
      {
         m_display->clear( black );
         m_display->setFont(getFont8());
      }
      void drawText(const char* text)
      {
         m_display->setFg( blue );
         m_display->drawText( (m_display->width()/2)-(strlen(text)*4), m_display->height()/2-4, text);
      }
      void drawStartScreen()
      {
         clearScreen();
         drawText("PRESS THE CROSSES");
      }
      void drawFinished()
      {
         clearScreen();
         drawText("FINISHED");
      }
      void cross( int x, int y, TRgb color )
      {
         //m_display->drawRect(x-10, y-10, x+10, y+10, color);
         m_display->drawLine(x-10, y-10, x+10, y+10, color);
         m_display->drawLine(x-10, y+10, x+10, y-10, color);
      }
      void eventLoop()
      {
         bool intInput=m_touch->readInput();
         
         switch(m_state)
         {
            case EState::Start:
               drawStartScreen();
               m_state=EState::WaitInitialRelease;
               break;
            case EState::WaitInitialRelease:
               m_touch->readTouch(m_touchX, m_touchY, m_touchZ1, m_touchZ2);
               lInfo("Z1: %d Z2: %d; %d", m_touchZ1, m_touchZ2, intInput );
               //if( m_touchZ1 < m_touchReleaseLevel )
               if( intInput )
               {
                   m_state=EState::StartCross;
               }
               break;
            case EState::StartCross:
               cross( coords[ m_crossIndex ].x, coords[ m_crossIndex ].y, white);
               m_state=EState::WaitPressed;
               break;
            case EState::WaitPressed:
               m_touch->readTouch(m_touchX, m_touchY, m_touchZ1, m_touchZ2);
               lInfo("Z1: %d Z2: %d", m_touchZ1, m_touchZ2);
               if( intInput == 0 )
               {
                  m_values [ m_crossIndex ].x=m_touchX;
                  m_values [ m_crossIndex ].y=m_touchY;
                  m_state=EState::WaitReleased;
               }
               break;
            case EState::WaitReleased:
               cross( coords[ m_crossIndex ].x, coords[ m_crossIndex ].y, green);
               lInfo("Z1: %d Z2: %d X: %d Y: %d", m_touchZ1, m_touchZ2, m_touchX, m_touchY);
               //if( m_touchZ1 < m_touchReleaseLevel )
               if( intInput )
               {
                  m_state=EState::SwitchNextCross;
               }
               else
               {
                  m_touch->readTouch(m_touchX, m_touchY, m_touchZ1, m_touchZ2);
                  if( m_touchZ1 > m_touchPressLevel )
                  {
                     m_values [ m_crossIndex ].x=m_touchX;
                     m_values [ m_crossIndex ].y=m_touchY;
                  }
               }
               break;
            case EState::SwitchNextCross:
               cross( coords[ m_crossIndex ].x, coords[ m_crossIndex ].y, black);
               m_crossIndex++;
               if( m_crossIndex < arraySize(coords) )
               {
                  m_state=EState::StartCross;
               }
               else
               {
                  m_state=EState::Finished;
               }
               break;
            case EState::Finished:
               drawFinished();
               for(int i1=0; i1 < arraySize(coords); i1++)
               {
                  lInfo("[%d]: X: %d Y: %d", i1, m_values [ i1 ].x, m_values [ i1 ].y);
               }
               biwakEventLoop();
               m_state=EState::Stopped;
               break;
            case EState::Stopped:
               break;
            default:
               lFatal("Unknown State: %d", m_state);
               break;
         }
      }
      int getCalibrationXLeft()
      {
         return( ( m_values[0].x + m_values[3].x ) / 2 );
      }
      int getCalibrationXRight()
      {
         return( ( m_values[1].x + m_values[2].x ) / 2 );
      }
      int getCalibrationYTop()
      {
         return( ( m_values[0].y + m_values[1].y ) / 2 );
      }
      int getCalibrationYBottom()
      {
         return( ( m_values[2].y + m_values[3].y ) / 2 );
      }
      bool finished()
      {
         return( m_state == EState::Stopped );
      }
};


//---fin----------------------------------------------------------------------
#endif // ? ! CALIBRATION_APP_HPP
