//----------------------------------------------------------------------------
///
/// \file   board.cpp
///
/// \brief  class describing the periphery of an MCU board
///
/// \date   20180129
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


//---Documentation------------------------------------------------------------


//---Defines------------------------------------------------------------------


#define  MAKRO_IDENT    35


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


//---General--------------------------

#include <QMap>
#include <QFile>
#include <QTextStream>
#include <QSharedPointer>

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

#include "writerArena.h"
#include "board.h"
#include "app.h"

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


int CWriterArena::writeHeader(const QString &fileName)
{
   QMap <QString, int> typeCounter;
   QString line;
   QFile file(fileName);
   if (!file.open(QFile::WriteOnly | QFile::Truncate))
      qFatal("Could not open header file for writing");
   QTextStream out(&file);

   for(const auto &periphery: board().listConst())
   {
      if(periphery->doInstantiate())
      {
         QString type=periphery->getPeripheryType();
         typeCounter[type]++;
      }
   }

   out << QString("#ifndef _ARENA_CONFIG_%1_H_\n").arg(app().getName().toUpper());
   out << "//-----------------------------------------------------------------------------\n";
   out << "//\n";
   out << "// \\brief   Autogenerated arena board description\n";
   out << "//\n";
   out << "//          Dont edit this file. It will get overwritten!\n";
   out << "//\n";
   out << "//          Board: " << board().getName() << "\n";
   out << "//          App:   " << app().getName() << "\n";
   out << "//\n";
   out << "//-----------------------------------------------------------------------------\n";

   out << "\n\n";

   line=QString("#define ARENA_APP_NAME%1").arg(" ", -40);
   line.truncate(MAKRO_IDENT);
   line+=QString("%1\n").arg(app().getName());
   out << line;
   line=QString("#define ARENA_APP_%1\n").arg(app().getName());
   out << line;
   line=QString("#define ARENA_APP_ID%1").arg(" ", -40);
   line.truncate(MAKRO_IDENT);
   line+=QString("%1\n").arg(app().getId());
   out << line;
   
   // Static macros definig the features of used arena version. Its not about
   // features that can be configured, its just what the version of arena
   // supports.
   line=QString("#define ARENA_FEATURE_PLACEHOLDER_MACROS 1\n");
   line=QString("#define ARENA_FEATURE_PLACEHOLDER        1\n");
   out << line;

   line=QString("#define ARENA_BOARD_NAME%1").arg(" ", -40);
   line.truncate(MAKRO_IDENT);
   line+=QString("%1\n").arg(board().getName());
   out << line;

   //line=QString("#define ARENA_BOARD_%1\n").arg(board().getName());
   //out << line;

   line=QString("#define ARENA_BOARD_ID%1").arg(" ", -40);
   line.truncate(MAKRO_IDENT);
   line+=QString("%1\n").arg(board().getId());
   out << line;

   line=QString("#define ARENA_IRQS%1").arg(" ", -40);
   line.truncate(MAKRO_IDENT);
   for (auto iterator : pinmux().getIrqHandlers())
      line+=QString("%1 ").arg( iterator );
   line+=QString("\n");
   out << line;

   out << "\n\n";

   for( const auto &type: typeCounter.keys() )
   {
      line=QString("#define ARENA_USE_%1%2").arg(type).arg(" ", -40);
      line.truncate(MAKRO_IDENT);
      line+=QString("%1\n").arg(typeCounter[type]);
      out << line;
      int counter=0;

      for ( const auto &periphery: board().listConst())
      {
         CReferencePtr pReference=periphery->getReferenceLink();
         if( periphery->doInstantiate() && ( periphery->getPeripheryType()==type ) )
         {
            out << formatHeaderBlob(*periphery, pReference.data(), type, counter);
            counter++;
         }
      }
      out << "\n";
   }

   if(!app().getDebugUart().isEmpty())
   {
      line=QString("#define ARENA_DEBUG_UART%3").arg(" ", -40);
      line.truncate(MAKRO_IDENT);
      line+=QString("eUartIndex%1\n").arg(app().getDebugUart());
      out << line;
   }
   if(app().getHeartbeat())
   {
      out << "#define ARENA_USE_LED_HEARTBEAT\n";
   }

   out << "\n";
   out << "\n//---fin-----------------------------------------------------------------------\n";
   out << QString("#endif // ? ! _ARENA_CONFIG_%1_H_\n").arg(app().getName().toUpper());
   file.close();

   return(0);
}


QString CWriterArena::macroLine(const QString &name, const QString &value)
{
   QString line=QString("#define %1%2").arg(name).arg(" ", -40);
   line.truncate(MAKRO_IDENT);
   line+=value;
   line+="\n";
   return(line);
}

QString CWriterArena::peripheralPins(const CPeriphery &periphery)
{
   QString macro;
   QString pin=periphery.getAttribute( "pin" );

   macro+=QString("%1").arg(pin);

   for(const auto &consumes: periphery.getConsumesListConst() )
   {
      if(!macro.isEmpty())
         macro+=QString(", \\\n%1").arg(' ', MAKRO_IDENT);

      macro+=QString("%1").arg(getWiring(consumes));
   }

   if(macro.isEmpty())
      macro+="None";
   return( macro );
}

QString CWriterArena::formatHeaderBlob(const CPeriphery &periphery
                                  , const CReference *pReference
                                  , const QString &type, int counter)
{
   QString line;
   QString name, pname;

   line+=macroLine(QString("ARENA_%1_%2").arg(type).arg(counter)
                   , "XXX" /*m_pinmux.getPeripheralArgumentsString(periphery)*/);
   if(pReference && (!pReference->getName().isEmpty()))
      name=pReference->getName();
   else
      name=periphery.getName();

   line+=macroLine(QString("ARENA_%1_%2_NAME").arg(type).arg(counter)
                      , name);
   pname=periphery.getName();

   // Avoid double definitions of enums in libarena config header
   if(name==pname)
      pname+="___";

   line+=macroLine(QString("ARENA_%1_%2_PNAME").arg(type).arg(counter)
                   , pname);

   line+=macroLine(QString("ARENA_%1_%2_ID").arg(type).arg(counter)
                   , QString("%1").arg(periphery.getId()) );

   line+=macroLine(QString("ARENA_%1_%2_PINS").arg(type).arg(counter)
                     , peripheralPins( periphery ) );
   
   if( pReference && (pReference->getRelation() == ERelation::placeholder ) )
   {
      line+=macroLine(QString("ARENA_%1_%2_PLACEHOLDER").arg(type).arg(counter)
                        , QString("1") );
   }

   return(line);
}



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