//----------------------------------------------------------------------------
///
/// \file   resolverPredefined.cpp
///
/// \brief  Resolver class for references with predefined periphery path
///
/// \date   20230329
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


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


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


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

#include <QDebug>

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

#include "resolverPredefined.h"


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


CResolverPredefined::CResolverPredefined(CApp *app, CBoard *board)
   :m_pApp(app)
   ,m_pBoard(board)
{
}


CPeriphery *CResolverPredefined::resolveReference(CReference &reference)
{
   // qWarning() << "Resolving Predefined: " << reference.getPredefined();
   m_predefinedString=reference.getPredefined();

   m_predefined=reference.getPredefined().split(" ");
   m_pos=0;
   return( resolveReferencePredefined( reference) );
}


bool CResolverPredefined::verifyMatch(CReference &reference, CPeripheryPtr periphery)
{
   if( !reference.getPeripheryName().isEmpty() )
   {
      if( reference.getPeripheryName() != periphery->getPeripheryName() )
      {
         qWarning() << "Periphery name '" << reference.getPeripheryName()
                    << "' does not match '" << periphery->getPeripheryName()
                    << "'";
         return(false);
      }
   }
   if( !reference.getAlternateFunction().isEmpty() )
   {
      if( ! periphery->getConstAlternateFunctions()
                     .contains( reference.getAlternateFunction() ) )
      {
         qWarning() << "Periphery '" << periphery->getPeripheryName()
                    << "' does not contain af. '"
                    << reference.getAlternateFunction()
                    << "'";

         return(false);
      }
   }
   if( !reference.getPeripheryType().isEmpty() )
   {
      if( reference.getPeripheryType() != periphery->getPeripheryType() )
      {
         qWarning() << "Periphery type '" << reference.getPeripheryType()
                    << "' does not match '" << periphery->getPeripheryType()
                    << "'";
         return(false);
      }
   }
   return(true);
}


CPeriphery *CResolverPredefined::resolveReferencePredefined(CReference &reference )
{
   if ( m_pos >= m_predefined.count() )
   {
      qFatal("%s: error: Not enough predefined elements: reference %s '%s'; has %d elements"
             , qPrintable( m_pBoard->getMainFile() )
             , qPrintable( reference.getName() )
             , qPrintable( m_predefinedString )
             , (int)m_predefined.count() );
   }
   QString peripheryName=m_predefined[m_pos];

   // Cut off possible fabricated markings
   cutFabricateMarker( peripheryName );

   CPeripheryPtr periphery=m_pBoard->findPeripheryByPeripheryName( peripheryName );
   if(!periphery)
   {
      qFatal( "%s: error: The periphery could not be found by name: %s"
              , qPrintable( m_pApp->getMainFile() )
              , qPrintable( peripheryName ) );
   }
   if( ! verifyMatch(reference, periphery) )
   {
      qWarning() << "Not plausible: " << reference.getName()
                 << " does not match" << periphery->getName() << "/"
                 << periphery->getPeripheryName();
      periphery.clear();
   }

   if(periphery)
   {
      m_pos++;
      if( !resolveConsumed( periphery ) )
      {
         return(nullptr);
      }

      if( ! reference.getPeripheryLink() )
      {
         reference.link( periphery );
      }

      if( periphery->getRelation() == ERelation::fabricate )
      {
         //qWarning() << "Fabricating " << periphery->getPeripheryName();
         m_pBoard->addPeriphery( periphery->fabricate() );
      }
   }

   return( periphery.dataNoCheck() );
}


bool CResolverPredefined::resolveConsumed(CPeripheryPtr periphery)
{
   for( CReference &consumed : periphery->getConsumesList() )
   {
      CPeriphery *periphery=resolveReferencePredefined( consumed );
      if( periphery == nullptr )
      {
         return( false);
      }
   }
   return(true);
}


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