//----------------------------------------------------------------------------
///
/// \file   main.cpp
///
/// \brief  main file for pinmux
///
/// \date   20180129
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


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


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


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

#include <QFile>
#include <QJsonParseError>
#include <QJsonDocument>
#include <QDebug>
#include <QCommandLineParser>
#include <QFileInfo>
#include <QDir>

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

#include "board.h"
#include "app.h"
#include "pinmux.h"
#include "writerPlatform.h"
#include "writerArena.h"
#include "writerDesc.h"
#include "writerLayout.h"
#include "writerCMake.h"
#include "writerCMakeDeps.h"
#include "writerLinkerScript.h"
#include "writerPinout.h"
#include "writerDot.h"
#include "writerSymbolMap.h"
#include "writerConfigHeader.h"
#include "writerPredefined.h"
#include "writerWireing.h"
#include <git_version_pinmuxer.h>

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

void writeFiles( CPinmux& pinmux, const QString& basePath, CConstructorPool& constructors )
{
   CWriterCMake writerCMake(pinmux, basePath);
   writerCMake.writeCMake(/*basePath+"arena_generated.cmake",*/ constructors);

   CWriterCMakeDeps writerCMakeDeps(pinmux, basePath);
   writerCMakeDeps.writeCMake(/*basePath+"arena_generated.cmake",*/ constructors);

   CWriterLayout writerLayout(pinmux, basePath);
   writerLayout.writeFiles( /*basePath*/ );

   CWriterPinout writerPinout(pinmux, basePath);
   writerPinout.writeFiles( /*basePath*/ );

   CWriterDot writerDot(pinmux, basePath);
   writerDot.writeFiles( /*basePath*/ );

   CWriterSymbolMap writerSymbolMap(pinmux, constructors, basePath);
   writerSymbolMap.writeFiles( /*outSymmap*/ );

   CWriterConfigHeader writerConfigHeader(pinmux, basePath);
   writerConfigHeader.writeFiles( basePath + "arena_app.h" );

   CWriterDesc writerDesc(pinmux, basePath);
   writerDesc.writeFiles();

   CWriterPredefined writerPredefined(pinmux, basePath);
   writerPredefined.writeFiles();

   CWriterWireing writerWireing(pinmux, basePath);
   writerWireing.writeFiles();
   return;
}

int main(int argc, char *argv[])
{
   QFile file;
   QJsonDocument settdoc;
   QJsonObject jsonObject;
   CBoard board;
   CApp app;
   CConstructorPool constructors;
   CPinmux pinmux;
   QString outHeader;
   QString outSymmap;
   QString basePath;
   int sta=0;

   QCoreApplication qapp(argc, argv);
   QCoreApplication::setApplicationName("pinmuxer");
   QCoreApplication::setApplicationVersion( GIT_TAG );

   QCommandLineParser parser;
   parser.setApplicationDescription("Pinmuxer");
   parser.addHelpOption();
   parser.addVersionOption();
   // printf( "pinmuxer " GIT_SEMI "\n" );

   QCommandLineOption boardOption(QStringList() << "b" << "board",
           "Board description file", "file");
   QCommandLineOption appOption(QStringList() << "a" << "app",
           "App description file", "file");
   QCommandLineOption frameworkOption(QStringList() << "f" << "framework",
           "App framework file", "file");
   QCommandLineOption outOption(QStringList() << "o" << "out",
           "Output directory", "directory");
   QCommandLineOption cmakeOption(QStringList() << "c" << "cmake",
           "Write cmake file only");
   QCommandLineOption variantOption(QStringList() << "t" << "variant",
           "create variant", "variant");
   QCommandLineOption subsetOption(QStringList() << "s" << "subset",
           "create additional variants", "name(variant)");
   QCommandLineOption pathOption(QStringList() << "p" << "path",
           "arena board and app directories", "directories");

   parser.addOptions( {boardOption, appOption, frameworkOption, outOption
                       , cmakeOption, variantOption, subsetOption, pathOption });
   parser.process(qapp);

   if(  ( parser.value(boardOption).isEmpty() )
     || ( ( ! parser.value(cmakeOption).isEmpty() ) &&  parser.value(appOption).isEmpty()  )
   )
   {
      parser.showHelp(22);
   }

   if ( parser.isSet( variantOption ) )
   {
      app.setVariant( parser.value( variantOption ) );
   }

   if ( parser.isSet( pathOption ) )
   {
      QStringList pathList=parser.value( pathOption ).split(":");
      for( auto path: pathList)
      {
         app.addPath( path + "/apps" );
         board.addPath( path + "/boards" );
         constructors.addPath( path + "/frameworks" );
      }
   }

   QFileInfo appInfo(parser.value(appOption));
   QString appName = appInfo.baseName();
   QFileInfo boardInfo(parser.value(boardOption));
   QString boardName = boardInfo.baseName();

   if(parser.isSet(outOption))
   {
         outHeader=parser.value(outOption) + "/";
         outSymmap=parser.value(outOption) + "/";
         basePath=parser.value(outOption) + "/";
   }
   outHeader+="arena_app.h";
   outSymmap+="arena_app.symmap";
   basePath+="";

   CWriterLinkerScript writerLinkerScript(pinmux, basePath);
   CWriterCMake writerCMake(pinmux, basePath);
   CWriterPlatform writerPlatform(pinmux, constructors, basePath);

   board.setMainFile( parser.value(boardOption) );
   if( ! board.loadFile( parser.value(boardOption) ) )
   {
      qFatal("Could not load board file");
   }

   if( parser.isSet( frameworkOption ) )
   {
      if ( ! constructors.loadFile( parser.value( frameworkOption ) ) )
      {
         qFatal("Could not load framework file");
      }
   }

   app.setBoardId( board.getId() );
   if(!parser.isSet(cmakeOption))
   {
      app.setMainFile( parser.value(appOption) );
      if ( ! app.loadFile( parser.value(appOption) ) )
      {
         qFatal("Could not load app file");
      }
      if( ! parser.isSet( frameworkOption ) )
      {
         qFatal("Framework not set in arguments");
      }
   }


   pinmux.setBoardApp(board, app);

   // This property should be in the cmake file. It was originally set in the
   // writerLinkerScript, but we only want one linker script per app
   pinmux.getBoard()->addProperty("cmake.ARENA_LINKERSCRIPT", "arena_generated.ld" );
   // Always create linker script; it will add properties
   writerLinkerScript.writeLinkerScript( );

   if(parser.isSet(cmakeOption))
   {
      writerCMake.writeCMake(/*basePath+"arena_generated.cmake",*/ constructors);
      CWriterCMakeDeps writerCMakeDeps(pinmux, basePath);
      //writerCMakeDeps.touch();
      writerCMakeDeps.writeCMake(/*basePath+"arena_generated.cmake",*/ constructors);
   }
   else
   {
      pinmux.getBoard()->setOptions(  pinmux.getApp()->getOptions() );
      pinmux.getBoard()->cleanupMissingOptions( );

      pinmux.resolveApp();
      pinmux.dump(parser.value(outOption) + "/board.log");

      if( constructors.count() == 0 )
      {
         qFatal("There are no constructors loaded. Something is wrong in your framework files.");
      }

      writerPlatform.init();
      writerPlatform.writeHeader(/*basePath+"platform_generated.hpp"*/);
      writerPlatform.writeImplementation(/*basePath+"platform_generated.cpp"*/);

      writeFiles( pinmux, basePath, constructors);

      if( parser.isSet(subsetOption) )
      {
         QStringList list( parser.value( subsetOption ).split(":") );
         if( list.count() != 2 )
         {
            qFatal("Format for --subset argument not correct: '%s'."
                   " I need something like 'BootLoader:bootloader'"
                   , qPrintable( parser.value( subsetOption ) ) );
         }
         qWarning("Subset variant: '%s'", qPrintable( list[1] ) );
         
         pinmux.reset();
         pinmux.filterSubsetVariant( list[1] );
         pinmux.resolveApp();

         qInfo("Creating additional variant '%s'", qPrintable(list[0]));
         writerPlatform.setPostfix( list[0] );
         writerPlatform.initFiles();
         writerPlatform.writeHeader(/*basePath+"platform_generated.hpp"*/);
         writerPlatform.writeImplementation(/*basePath+"platform_generated.cpp"*/);
      }
   }

   return( sta );
}


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