/*
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                                                 ┃
┃            Class Name: CompSynt.cpp                                                             ┃
┃                Author: Michael Krämer                                                           ┃
┃                 Email: Michael@dk8pp.de                                                         ┃
┃                  Date: 09.02.2026 15:38:00                                                      ┃
┃                  Tool: Qt                                                                       ┃
┃                Device: Windows/Linux                                                            ┃
┃               Version: 0.1                                                                      ┃
┃        Program status: still testing                                                            ┃
┃                                                                                                 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃                                                                                                 ┃
┃  Purpose: Synthesize specific component from a set of standard components                       ┃
┃           Currently supported: resistor, resistor network or capacitor                          ┃
┃                                                                                                 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃                                                                                                 ┃
┃  © Copyright 2026 Michael Krämer, DK8PP                                                         ┃
┃                                                                                                 ┃
┃  This program is free software: you can redistribute it and/or modify it under the terms of     ┃
┃  the GNU Lesser General Public License as published by the Free Software Foundation, either     ┃
┃  version 3 of the License, or (at your option) any later version.                               ┃
┃                                                                                                 ┃
┃  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;      ┃
┃  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.      ┃
┃  See the GNU Lesser General Public License for more details.                                    ┃
┃                                                                                                 ┃
┃  You should have received a copy of the GNU Lesser General Public License along with this       ┃
┃  program.   If not, see <http://www.gnu.org/licenses/>.                                         ┃
┃                                                                                                 ┃
┃  ============================================================================================   ┃
┃                                                                                                 ┃
┃  Dieses Programm ist Freie Software: Sie können es unter den Bedingungen der GNU Lesser         ┃
┃  General Public License, wie von der Free Software Foundation, Version 3 der Lizenz oder        ┃
┃  (nach Ihrer Wahl) jeder neueren veröffentlichten Version, weiter verteilen und/oder            ┃
┃  modifizieren.                                                                                  ┃
┃                                                                                                 ┃
┃  Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch OHNE   ┃
┃  JEDE GEWÄHR,; sogar ohne die implizite Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN        ┃
┃  BESTIMMTEN ZWECK. Siehe die GNU Lesser General Public License für weitere Einzelheiten.        ┃
┃                                                                                                 ┃
┃  Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit diesem Programm      ┃
┃  erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.                             ┃
┃                                                                                                 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

ToDo:

*/

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Includes                                                                                  │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
#define DECLARE_VARS
#include "CompSynt.h"

#include <cmath>
#include "ui_CompSynt.h"

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Defines                                                                                   │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       global variables                                                                          │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/

IEC_TABLE iec_e6 =
                {100.0, 150.0, 220.0, 330.0, 470.0, 680.0} ;

/* e12 is a superset of e6 */
IEC_TABLE iec_e12 =
                {100.0, 120.0, 150.0, 180.0, 220.0, 270.0, 330.0, 390.0, 470.0, 560.0, 680.0, 820.0} ;

/* e24 is a superset of e12 */
IEC_TABLE iec_e24 =
                {100.0, 110.0, 120.0, 130.0, 150.0, 160.0, 180.0, 200.0, 220.0, 240.0, 270.0, 300.0,
                 330.0, 360.0, 390.0, 430.0, 470.0, 510.0, 560.0, 620.0, 680.0, 750.0, 820.0, 910.0} ;

/* Note that e48 is NOT a superset of e24 */
IEC_TABLE iec_e48 =
                {100.0, 105.0, 110.0, 115.0, 121.0, 127.0, 133.0, 140.0, 147.0, 154.0, 162.0, 169.0,
                 178.0, 187.0, 196.0, 205.0, 215.0, 226.0, 237.0, 249.0, 261.0, 274.0, 287.0, 301.0,
                 316.0, 332.0, 348.0, 365.0, 383.0, 402.0, 422.0, 442.0, 464.0, 487.0, 511.0, 536.0,
                 562.0, 590.0, 619.0, 649.0, 681.0, 715.0, 750.0, 787.0, 825.0, 866.0, 909.0, 953.0} ;

/* e96 is a superset of e48 */
IEC_TABLE iec_e96 =
                {100.0, 102.0, 105.0, 107.0, 110.0, 113.0, 115.0, 118.0, 121.0, 124.0, 127.0, 130.0,
                 133.0, 137.0, 140.0, 143.0, 147.0, 150.0, 154.0, 158.0, 162.0, 165.0, 169.0, 174.0,
                 178.0, 182.0, 187.0, 191.0, 196.0, 200.0, 205.0, 210.0, 215.0, 221.0, 226.0, 232.0,
                 237.0, 243.0, 249.0, 255.0, 261.0, 267.0, 274.0, 280.0, 287.0, 294.0, 301.0, 309.0,
                 316.0, 324.0, 332.0, 340.0, 348.0, 357.0, 365.0, 374.0, 383.0, 392.0, 402.0, 412.0,
                 422.0, 432.0, 442.0, 453.0, 464.0, 475.0, 487.0, 499.0, 511.0, 523.0, 536.0, 549.0,
                 562.0, 576.0, 590.0, 604.0, 619.0, 634.0, 649.0, 665.0, 681.0, 698.0, 715.0, 732.0,
                 750.0, 768.0, 787.0, 806.0, 825.0, 845.0, 866.0, 887.0, 909.0, 931.0, 953.0, 976.0 } ;

/* e192 is a superset of e96 */
IEC_TABLE iec_e192 =
                {100.0, 101.0, 102.0, 104.0, 105.0, 106.0, 107.0, 109.0, 110.0, 111.0, 113.0, 114.0,
                 115.0, 117.0, 118.0, 120.0, 121.0, 123.0, 124.0, 126.0, 127.0, 129.0, 130.0, 132.0,
                 133.0, 135.0, 137.0, 138.0, 140.0, 142.0, 143.0, 145.0, 147.0, 149.0, 150.0, 152.0,
                 154.0, 156.0, 158.0, 160.0, 162.0, 164.0, 165.0, 167.0, 169.0, 172.0, 174.0, 176.0,
                 178.0, 180.0, 182.0, 184.0, 187.0, 189.0, 191.0, 193.0, 196.0, 198.0, 200.0, 203.0,
                 205.0, 208.0, 210.0, 213.0, 215.0, 218.0, 221.0, 223.0, 226.0, 229.0, 232.0, 234.0,
                 237.0, 240.0, 243.0, 246.0, 249.0, 252.0, 255.0, 258.0, 261.0, 264.0, 267.0, 271.0,
                 274.0, 277.0, 280.0, 284.0, 287.0, 291.0, 294.0, 298.0, 301.0, 305.0, 309.0, 312.0,
                 316.0, 320.0, 324.0, 328.0, 332.0, 336.0, 340.0, 344.0, 348.0, 352.0, 357.0, 361.0,
                 365.0, 370.0, 374.0, 379.0, 383.0, 388.0, 392.0, 397.0, 402.0, 407.0, 412.0, 417.0,
                 422.0, 427.0, 432.0, 437.0, 442.0, 448.0, 453.0, 459.0, 464.0, 470.0, 475.0, 481.0,
                 487.0, 493.0, 499.0, 505.0, 511.0, 517.0, 523.0, 530.0, 536.0, 542.0, 549.0, 556.0,
                 562.0, 569.0, 576.0, 583.0, 590.0, 597.0, 604.0, 612.0, 619.0, 626.0, 634.0, 642.0,
                 649.0, 657.0, 665.0, 673.0, 681.0, 690.0, 698.0, 706.0, 715.0, 723.0, 732.0, 741.0,
                 750.0, 759.0, 768.0, 777.0, 787.0, 796.0, 806.0, 816.0, 825.0, 835.0, 845.0, 856.0,
                 866.0, 876.0, 887.0, 898.0, 909.0, 920.0, 931.0, 942.0, 953.0, 965.0, 976.0, 988.0 } ;

QString LE_default_style ;
QString LE_error_style ("color: Red;") ;

CompSynt::CompSynt(QWidget *parent)
   : QMainWindow(parent)
   , ui(new Ui::CompSynt)
{
   ui->setupUi(this);
   QCoreApplication::setOrganizationName(OrganizationName) ;    /* defines registry tree */
   QCoreApplication::setApplicationName(ApplicationName) ;      /* defines registry tree */
   loadSettings() ;                                             /* read initialization from registry */

//   Init_Controls() ;


//         ╭──────────────────────────────────────────────────────────────────────────────── const QObject *sender
//         │                           ╭──────────────────────────────────────────────────── const char *signal
//         │                           │                                 ╭────────────────── const QObject *receiver
//         │                           │                                 │             ╭──── const char *method/slot
//         │                           │                                 │             │
   connect(ui->PUB_Start,              &QPushButton::clicked,            this,         &CompSynt::PUB_Start_clicked);
   connect(ui->PUB_SuggestSupplement,  &QPushButton::clicked,            this,         &CompSynt::PUB_SuggestSupplement_clicked);
   connect(ui->RB_R_IEC,               &QPushButton::clicked,            this,         &CompSynt::RB_R_IEC_clicked);
   connect(ui->RB_R_Private,           &QPushButton::clicked,            this,         &CompSynt::RB_R_Private_clicked);
   connect(ui->GB_Set,                 &QGroupBox::clicked,              this,         &CompSynt::QA_About_clicked);
   connect(ui->QA_About,               &QAction::triggered,              this,         &CompSynt::QA_About_clicked);
   connect(ui->QA_Exit,                &QAction::triggered,              this,         &CompSynt::QA_Exit_clicked);
   connect(ui->QA_Import,              &QAction::triggered,              this,         &CompSynt::QA_Import_clicked);
   connect(ui->QA_Export,              &QAction::triggered,              this,         &CompSynt::QA_Export_clicked);
   connect(ui->QA_Config,              &QAction::triggered,              this,         &CompSynt::QA_Config_clicked);



   LE_default_style = ui->LE_R_Target->styleSheet() ; /* save default style */

   if (ui->RB_R_IEC->isChecked()) RB_R_IEC_clicked() ;
   if (ui->RB_R_Private->isChecked()) RB_R_Private_clicked() ;

   iec_table.reserve(std::size(iec_e24) + std::size(iec_e192)) ;
   iec_table.clear() ; /* probably not required */

   solutions = nullptr ;

}

CompSynt::~CompSynt()
{
   saveSettings() ; /* write ini-file */
   solutions = Clear_Solutions(solutions) ;
   delete ui ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       QA_Exit_clicked                                                                           │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::QA_Exit_clicked()
{
   this->close() ; /* will send a closeEvent */
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       QA_About_clicked                                                                          │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::QA_About_clicked()
{
    InfoDialog InfoDialog(nullptr, &ProgramInfo) ;
//    SecDialog.setModal(true) ; (no access to first window when 2nd is open, all data is local on stack)
    InfoDialog.exec() ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       QA_Config_clicked                                                                         │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::QA_Config_clicked()
{
    ConfigDialog ConfigDialog(this) ;
//    SecDialog.setModal(true) ; (no access to first window when 2nd is open, all data is local on stack)
    ConfigDialog.exec() ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       RB_R_IEC_clicked                                                                          │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::RB_R_IEC_clicked()
{
   activate(SET_IEC) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       RB_R_Private_clicked                                                                      │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::RB_R_Private_clicked()
{
   if (!Import_PrivateFile(LastFile_R))
      activate(SET_PRIVATE) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       set_active                                                                                │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Activate IEC or Private set                                                                     │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::activate(int set)
{
QFileInfo fi ;

   if (set == SET_IEC)
   {
      ui->CB_R_E6->  setEnabled(true) ;
      ui->CB_R_E12-> setEnabled(true) ;
      ui->CB_R_E24-> setEnabled(true) ;
      ui->CB_R_E48-> setEnabled(true) ;
      ui->CB_R_E96-> setEnabled(true) ;
      ui->CB_R_E192->setEnabled(true) ;
      ui->LE_R_PowerRating->setEnabled(true) ;
      ui->LE_R_MaxVoltage->setEnabled(true) ;

      ui->LE_FileName->setText("") ;
      SetMainStatus("") ;
   }

   if (set == SET_PRIVATE)
   {
      ui->CB_R_E6->  setEnabled(false) ;
      ui->CB_R_E12-> setEnabled(false) ;
      ui->CB_R_E24-> setEnabled(false) ;
      ui->CB_R_E48-> setEnabled(false) ;
      ui->CB_R_E96-> setEnabled(false) ;
      ui->CB_R_E192->setEnabled(false) ;

      ui->LE_R_PowerRating->setEnabled(false) ;
      ui->LE_R_MaxVoltage->setEnabled(false) ;

      if (LastFile_R.size() != 0)
      {
         fi = QFileInfo(LastFile_R) ;
         ui->LE_FileName->setText(fi.baseName()) ;
      }
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       QA_Import_clicked                                                                         │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Import private file                                                                             │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::QA_Import_clicked()
{
QString filename ;

   filename = QFileDialog::getOpenFileName(this,
      tr("Open Text file"), LastFile_R, tr("Text Files") + "(*.csv *.txt *.dat)") ;
   if (!Import_PrivateFile(filename))
   { /* file successfully imported */
      activate(SET_PRIVATE) ;
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Import_PrivateFile                                                                        │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Import private file                                                                             │
│                                                                                                 │
│ Returns true on error                                                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
bool CompSynt::Import_PrivateFile(QString filename)
{
QFileInfo fi ;
QFile file ;
QString line ;
QStringList token ;
uint32_t valcntr  = 0;
uint32_t linenr  = 0;
bool input_error  = false;
COMPONENT comp ;

//                       ╭────────────────────────────────────────────────────── string to be decoded and returned
//                       │   ╭────────────────────────────────────────────────── default if input empty
//                       │   │   ╭────────────────────────────────────────────── result value if no error
//                       │   │   │    ╭───────────────────────────────────────── required field, return error if empty
//                       │   │   │    │      ╭────────────────────────────────── value must be positive
//                       │   │   │    │      │     ╭──────────────────────────── true if input string is empty
//                       │   │   │    │      │     │     ╭────────────────────── true if relative value was specified, e.g. %
//                       │   │   │    │      │     │     │     ╭──────────────── true on conversion error or missing required input
//                       │   │   │    │      │     │     │     │
//                       │   │   │    │      │     │     │     │
//                       │   │   │    │      │     │     │     │
CONVERSION local_conv = {"", "", 0.0, false, true, true, true, true} ;

   input_error = true ;
   fi = QFileInfo(filename) ;
   if (filename.size() != 0)
   {
      private_table.clear() ;
      valcntr = 0 ;
      LastFile_R = filename ;
      file.setFileName(filename) ;
      if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
      { /* error handling */
         SetMainStatus(file.errorString()) ;
         return(input_error) ;
      }

      QTextStream in(&file) ;
      linenr = 0 ;
      line = in.readLine() ;
      input_error = false ;
      while (!line.isNull() && !input_error)
      { /* process file */
         if (linenr != 0)
         { /* first line (header line) is discarded */
            line = line.split(QRegularExpression("[\\#/]"))[0] ; /* strip off any comment starting with '#' or '/' */
            line.remove(QRegularExpression("\\s")) ; /* remove whitespaces */
            if (line.size() > 0)
            { /* line is not empty */
               token = line.split(QRegularExpression(";")) ;
               comp = DEFAULT_COMPONENT ;
               if (!token.empty())
               {
                  local_conv.str = token[0] ;
                  get_double(&local_conv) ;
                  if ((!local_conv.error) && (!local_conv.empty)) comp.value = local_conv.value ;
                  input_error |= local_conv.error ;

                  if (token.size() > 1)
                  {
                     local_conv.str = token[1] ;
                     get_double(&local_conv) ;
                     if ((!local_conv.error) && (!local_conv.empty)) comp.tolerance = local_conv.value ;
                     input_error |= local_conv.error ;

                     if (token.size() > 2)
                     {
                        local_conv.str = token[2] ;
                        get_double(&local_conv) ;
                        if ((!local_conv.error) && (!local_conv.empty)) comp.max_power = local_conv.value ;
                        input_error |= local_conv.error ;

                        if (token.size() > 3)
                        {
                           local_conv.str = token[3] ;
                           get_double(&local_conv) ;
                           if ((!local_conv.error) && (!local_conv.empty)) comp.max_voltage = local_conv.value ;
                           input_error |= local_conv.error ;
                        }

                     }
                  }
                  if (!input_error) private_table.push_back(comp) ;
               }
            }
         }
         line = in.readLine() ;
         linenr++ ;
      }
      if (input_error)
         SetMainStatus(fi.fileName() + ": " + QString(tr("Data error in line") + " %L1").arg(linenr)) ;
      else
      {
         if (valcntr<=private_table.size())
            SetMainStatus(fi.fileName() + QString(": %L1 " + tr("values read")).arg(private_table.size())) ;
         else
            SetMainStatus(fi.fileName()
                        + QString(": " + tr("overflow") +", " + "%L1 "
                        + tr("values used") + ", " + "%L2 "
                        + tr("discarded")).arg(private_table.size()).arg(valcntr-private_table.size())) ;
      }
      file.close() ;
   }
   return(input_error) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       QA_Export_clicked                                                                         │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Export private file                                                                             │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::QA_Export_clicked()
{
QString filename ;
QFileInfo fi ;
QFile file ;
QString line ;
QString fmt1 ;
QStringList const token ;
uint32_t icntr  = 0;
PARMS parameter ;

   if (!getParms(&parameter)) return ; /* return on parameter error */

   filename = QFileDialog::getSaveFileName(this, tr("Select output file"), LastFile_R, tr("Text Files") + "(*.csv *.txt *.dat)") ;
   fi = QFileInfo(filename) ;
   if (filename.size() != 0)
   {
      LastFile_R = filename ;
      file.setFileName(filename) ;
      if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
      { /* error handling */
         SetMainStatus(file.errorString()) ;
         return ;
      }
      QTextStream out(&file) ;
      make_IECMasterTable(&iec_table, log10rmin, rdecades, nullptr) ;

      if (iec_table.empty())
      { /* IEC table not yet created */
         SetMainStatus(tr("IEC table is empty")) ;
         return ;
      }
      else
      { /* write IEC table in csv-Format */
         if (useLocale) fmt1 = "%L1" ; else fmt1 = "%1" ;
         out << tr("Res;Tol;Pmax;Umax;Comment") + "\n" ;
         for (icntr=0; icntr<iec_table.size();icntr++)
         {
            if (private_fileformat == FMT_UNITS)
            {
               line = pval(iec_table.at(icntr).value) + "Ω;"
                    + ui->LE_R_Tolerance->text() + ";"
                    + ui->LE_R_PowerRating->text() + ";"
                    + ui->LE_R_MaxVoltage->text() + ";"
                    + QString("\n") ; /* new line */
               line.remove(u' ') ;
               out << line ;
            }

            if (private_fileformat == FMT_FLOAT)
            {
               line = QString(fmt1 + ";").arg(iec_table.at(icntr).value, 0, 'f', 2) /* Res */
                    + QString(fmt1 + ";").arg(parameter.tolerance, 0, 'f', 4) /* tolerance */
                    + QString(fmt1 + ";").arg(parameter.max_power, 0, 'f', 3) /* max power */
                    + QString(fmt1 + ";").arg(parameter.max_voltage, 0, 'f', 0) /* max voltage */
                    + QString("\n") ; /* new line */
               line.remove(u' ') ;
               out << line ;
            }

            if (private_fileformat == FMT_EXP)
            {
               line = QString(fmt1 + ";").arg(iec_table.at(icntr).value, 0, 'e', 3) /* Res */
                    + QString(fmt1 + ";").arg(parameter.tolerance, 0, 'e', 3) /* tolerance */
                    + QString(fmt1 + ";").arg(parameter.max_power, 0, 'e', 3) /* max power */
                    + QString(fmt1 + ";").arg(parameter.max_voltage, 0, 'e', 3) /* max voltage */
                    + QString("\n") ; /* new line */
               line.remove(u' ') ;
               out << line ;
            }
         }
         SetMainStatus(tr("IEC table was successfully exported")) ;
         return ;
      }

      file.close() ;
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       PUB_SuggestSupplement_clicked                                                             │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::PUB_SuggestSupplement_clicked()
{
//QString const tmpstr ;
QDateTime start_dt ;
QDateTime end_dt ;
uint32_t elapsed  = 0;
PARMS parameter ;
uint32_t iter  = 0;
bool terminate = false ;
uint32_t count  = 0;
SOLUTION *sol_supplement = nullptr ;
SOLUTION *sol_curr = nullptr ;
SOLUTION *sol_new = nullptr ;
SOLUTION *curr_sol  = nullptr;
uint32_t sol_count = 0 ;
uint32_t unprinted  = 0;
COMPONENT supplement ;

   Prepare_OutputWindow(ui->TE_OutputWindow) ;  /* prepare output window (clear and set format) */
   solutions = Clear_Solutions(solutions) ;     /* clear any previous result */
   active_table.clear() ;                       /* clear active table */
   iec_table.clear() ;                          /* clear IEC table */

   if (private_table.empty())
   {
      SetMainStatus(tr("please import private file first")) ;
      return ;
   }

   if (!getParms(&parameter)) return ; /* return on parameter error */

   start_dt = QDateTime::currentDateTime() ;    /* get timestamp */

   make_IECMasterTable(&iec_table, log10rmin, rdecades, &parameter) ;

   generate_ActiveTable(&active_table, &private_table, nullptr) ;

   terminate = false ;
   count = 0 ;

   for (iter=0; (!terminate) && (iter < iec_table.size()); iter++)
   {
      supplement = iec_table.at(iter) ;
      generate_ActiveTable(&active_table, &private_table, &supplement) ;

      if (active_table.size() != private_table.size())
      { /* supplement was not yet in the list */

         solutions = Sort_Solutions(FindSolutions(&active_table, &parameter)) ;

         curr_sol = solutions ;
         while ((curr_sol != nullptr) /* forward to first solution which uses this supplement (if any) */
             && (curr_sol->comp[0].value != supplement.value)
             && (curr_sol->comp[1].value != supplement.value)
             && (curr_sol->comp[2].value != supplement.value)) curr_sol = curr_sol->next ;
         if (curr_sol != nullptr)
         { /* supplement found */
            count++ ;

            /* dequeue solution from list */
            sol_new = curr_sol ;
            if (curr_sol == solutions) solutions = curr_sol->next ;
            if (curr_sol->prev != nullptr) curr_sol->prev->next = curr_sol->next ;
            if (curr_sol->next != nullptr) curr_sol->next->prev = curr_sol->prev ;
            sol_new->next = nullptr ;
            sol_new->prev = nullptr ;
            sol_new->supplement = supplement ;

            if (sol_supplement == nullptr)
               sol_supplement = sol_new ; /* list was empty so far */
            else
            { /* append first solution to supplement list */
               sol_curr = sol_supplement ;
               while (sol_curr->next != nullptr) sol_curr = sol_curr->next ;
               sol_curr->next = sol_new ;
               sol_new->prev = sol_curr ;
            }

            solutions = Clear_Solutions(solutions) ;     /* clear */
         }
      }
   }

   end_dt = QDateTime::currentDateTime() ;
   elapsed = end_dt.toMSecsSinceEpoch() - start_dt.toMSecsSinceEpoch() ;

   sol_supplement = Sort_Solutions(sol_supplement) ;

   if (sol_supplement != nullptr)
   { /* print */

      curr_sol = sol_supplement ;
      sol_count = 0 ;
      unprinted = 0 ;

      /* display each solution, discard if printline_count is exceeded */
      while ((curr_sol != nullptr) && (sol_count < printline_count))
      {
         if (!PrintSolution(ui->TE_OutputWindow, curr_sol)) unprinted++ ;
         else sol_count++ ;
         curr_sol = curr_sol->next ;
      }

      if (curr_sol != nullptr)
      { /* some solutions remain unprinted */
         while (curr_sol != nullptr) {sol_count++ ; curr_sol = curr_sol->next ;}
         ui->TE_OutputWindow->append(QString("%L1 "+tr("more solutions not displayed")).arg(sol_count-printline_count)) ;
      }

      if (unprinted != 0)
      { /* some solutions remain unprinted due to exceeded power or voltage */
         ui->TE_OutputWindow->append(QString("%L1 "+tr("solutions discarded due to exceeded voltage or power")).arg(unprinted)) ;
      }

      /* move to the top of the window */
      ui->TE_OutputWindow->moveCursor(QTextCursor::Start) ;

   }

   Clear_Solutions(sol_supplement) ;     /* clear */

   if (count != 0)
      SetMainStatus(QString(tr("done!") + " %L1 " + tr("solutions found in") + " %L2 ms").arg(count).arg(elapsed)) ;
   else
      SetMainStatus(QString(tr("done! No solution found in") + " %L1 ms").arg(elapsed)) ;

}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       PUB_Start_clicked                                                                         │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::PUB_Start_clicked()
{
SOLUTION *curr_sol  = nullptr;
QString const print_line ;
QString const tmpstr ;
uint32_t sol_count = 0 ;
QDateTime start_dt ;
QDateTime end_dt ;
uint32_t elapsed  = 0;
PARMS parameter ;
uint32_t unprinted  = 0;

   Prepare_OutputWindow(ui->TE_OutputWindow) ;  /* prepare output window (clear and set format) */
   solutions = Clear_Solutions(solutions) ;     /* clear any previous result */
   iec_table.clear() ;                          /* clear IEC table */
   active_table.clear() ;                       /* clear active table */

   if ((ui->RB_R_Private->isChecked()) && (private_table.empty()))
   { SetMainStatus(tr("please import private file first")) ; return ; }

   if (!getParms(&parameter)) return ; /* return on parameter error */

   start_dt = QDateTime::currentDateTime() ;    /* get timestamp */

   make_IECMasterTable(&iec_table, log10rmin, rdecades, &parameter) ;

   if (ui->RB_R_IEC->isChecked())
   {
      generate_ActiveTable(&active_table, &iec_table, nullptr) ;
   }
   else
   {
      generate_ActiveTable(&active_table, &private_table, nullptr) ;
   }

   solutions = Sort_Solutions(FindSolutions(&active_table, &parameter)) ;

   end_dt = QDateTime::currentDateTime() ;
   elapsed = end_dt.toMSecsSinceEpoch() - start_dt.toMSecsSinceEpoch() ;

   if (solutions != nullptr)
   { /* print */

      curr_sol = solutions ;
      sol_count = 0 ;
      unprinted = 0 ;

      /* display each solution, discard if printline_count is exceeded */
      while ((curr_sol != nullptr) && (sol_count < printline_count))
      {
         if (!PrintSolution(ui->TE_OutputWindow, curr_sol)) unprinted++ ;
         else sol_count++ ;
         curr_sol = curr_sol->next ;
      }

      if (curr_sol != nullptr)
      { /* some solutions remain unprinted */
         while (curr_sol != nullptr) {sol_count++ ; curr_sol = curr_sol->next ;}
         ui->TE_OutputWindow->append(QString("%L1 "+tr("more solutions not displayed")).arg(sol_count-printline_count)) ;
      }

      if (unprinted != 0)
      { /* some solutions remain unprinted due to exceeded power or voltage */
         ui->TE_OutputWindow->append(QString("%L1 "+tr("solutions discarded due to exceeded voltage or power")).arg(unprinted)) ;
      }

      /* move to the top of the window */
      ui->TE_OutputWindow->moveCursor(QTextCursor::Start) ;

   }

   SetMainStatus(QString(tr("done!") + " %L1 " + tr("solutions found in") + " %L2 ms").arg(sol_count).arg(elapsed)) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       getParms                                                                                  │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Get parameters for subsequent search.                                                           │
│                                                                                                 │
│ Return true on success, false on error.                                                         │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
bool CompSynt::getParms(PARMS *parameter)
{
bool input_error = false ;

//                        ╭────────────────────────────────────────────────────── string to be decoded and returned
//                        │   ╭────────────────────────────────────────────────── default if input empty
//                        │   │        ╭───────────────────────────────────────── result value if no error
//                        │   │        │    ╭──────────────────────────────────── required field, return error if empty
//                        │   │        │    │      ╭───────────────────────────── value must be positive
//                        │   │        │    │      │     ╭─────────────────────── true if input string is empty
//                        │   │        │    │      │     │     ╭───────────────── true if relative value was specified, e.g. %
//                        │   │        │    │      │     │     │     ╭─────────── true on conversion error or missing required input
//                        │   │        │    │      │     │     │     │
//                        │   │        │    │      │     │     │     │
//                        │   │        │    │      │     │     │     │
CONVERSION targetval   = {"", "100 Ω", 0.0, true,  true, true, true, true} ;
CONVERSION max_error   = {"", "2.5 %", 0.0, true,  true, true, true, true} ;
CONVERSION tolerance   = {"", "1 %",   0.0, true,  true, true, true, true} ;
CONVERSION voltage     = {"", "",      0.0, false, true, true, true, true} ;
CONVERSION power       = {"", "",      0.0, false, true, true, true, true} ;
CONVERSION max_voltage = {"", "",      0.0, false, true, true, true, true} ;

   input_error  = decode_double(ui->LE_R_Target, &targetval) ;
   input_error |= decode_double(ui->LE_R_MaxError, &max_error) ;
   input_error |= decode_double(ui->LE_R_Tolerance, &tolerance) ;
   input_error |= decode_double(ui->LE_R_Voltage, &voltage) ;
   input_error |= decode_double(ui->LE_R_PowerRating, &power) ;
   input_error |= decode_double(ui->LE_R_MaxVoltage, &max_voltage) ;

   if (input_error) {SetMainStatus(tr("input error")) ; return(false) ;}

   parameter->tolerance         = tolerance.value ;
   parameter->max_voltage       = max_voltage.value ;
   parameter->max_power         = power.value ;
   parameter->value             = targetval.value ;
   parameter->max_error         = max_error.value ;
   parameter->applied_voltage   = voltage.value ;

   if (!max_error.relative) max_error.value = max_error.value / targetval.value ; /* deviation specified in percent */

   return(true) ;

}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       FindSolutions                                                                             │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Find solutions                                                                                  │
│                                                                                                 │
│ Returns sorted linked list of all solutions or NULL if none found.                              │
│ Solutions are owned by the caller.                                                              │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::FindSolutions(COMP_TABLE *ct, PARMS *parameter)
{
QFuture<SOLUTION *> res_rs ;
QFuture<SOLUTION *> res_rss ;
QFuture<SOLUTION *> res_rpp ;
QFuture<SOLUTION *> res_rssp ;
QFuture<SOLUTION *> res_rsss ;
QFuture<SOLUTION *> res_rppp ;
QFuture<SOLUTION *> res_rspp ;

SOLUTION *rs_solutions  = nullptr;
SOLUTION *rss_solutions  = nullptr;
SOLUTION *rpp_solutions  = nullptr;
SOLUTION *rssp_solutions  = nullptr;
SOLUTION *rsss_solutions  = nullptr;
SOLUTION *rppp_solutions  = nullptr;
SOLUTION *rspp_solutions  = nullptr;

SOLUTION *mysolutions = nullptr ;

   if (ui->CB_NT_RS->isChecked())   res_rs   = QtConcurrent::run(CompSynt::topo_rs,   ct, parameter) ;
   if (ui->CB_NT_RSS->isChecked())  res_rss  = QtConcurrent::run(CompSynt::topo_rss,  ct, parameter) ;
   if (ui->CB_NT_RPP->isChecked())  res_rpp  = QtConcurrent::run(CompSynt::topo_rpp,  ct, parameter) ;
   if (ui->CB_NT_RSSP->isChecked()) res_rssp = QtConcurrent::run(CompSynt::topo_rssp, ct, parameter) ;
   if (ui->CB_NT_RSSS->isChecked()) res_rsss = QtConcurrent::run(CompSynt::topo_rsss, ct, parameter) ;
   if (ui->CB_NT_RPPP->isChecked()) res_rppp = QtConcurrent::run(CompSynt::topo_rppp, ct, parameter) ;
   if (ui->CB_NT_RSPP->isChecked()) res_rspp = QtConcurrent::run(CompSynt::topo_rspp, ct, parameter) ;

   mysolutions = nullptr ;

   if (ui->CB_NT_RS->isChecked())
   {
      res_rs.waitForFinished() ;
      rs_solutions = res_rs.result() ;
      mysolutions = append_solutions(mysolutions, rs_solutions) ;
   }

   if (ui->CB_NT_RSS->isChecked())
   {
      res_rss.waitForFinished() ;
      rss_solutions = res_rss.result() ;
      mysolutions = append_solutions(mysolutions, rss_solutions) ;
   }

   if (ui->CB_NT_RPP->isChecked())
   {
      res_rpp.waitForFinished() ;
      rpp_solutions = res_rpp.result() ;
      mysolutions = append_solutions(mysolutions, rpp_solutions) ;
   }

   if (ui->CB_NT_RSSP->isChecked())
   {
      res_rssp.waitForFinished() ;
      rssp_solutions = res_rssp.result() ;
      mysolutions = append_solutions(mysolutions, rssp_solutions) ;
   }

   if (ui->CB_NT_RSSS->isChecked())
   {
      res_rsss.waitForFinished() ;
      rsss_solutions = res_rsss.result() ;
      mysolutions = append_solutions(mysolutions, rsss_solutions) ;
   }

   if (ui->CB_NT_RPPP->isChecked())
   {
      res_rppp.waitForFinished() ;
      rppp_solutions = res_rppp.result() ;
      mysolutions = append_solutions(mysolutions, rppp_solutions) ;
   }

   if (ui->CB_NT_RSPP->isChecked())
   {
      res_rspp.waitForFinished() ;
      rspp_solutions = res_rspp.result() ;
      mysolutions = append_solutions(mysolutions, rspp_solutions) ;
   }

   return(Sort_Solutions(mysolutions)) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Sort_Solutions                                                                            │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Sort solutions                                                                                  │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::Sort_Solutions(SOLUTION *solutions)
{
SOLUTION *curr = nullptr ;
SOLUTION **array = nullptr ;
uint32_t count = 0 ;
uint32_t i  = 0;

   if (solutions != nullptr)
   {
      curr = solutions ;
      count = 0 ;
      /* count number of solutions */
      while (curr != nullptr) {count++ ; curr = curr->next ;}

      if (count > 0)
      {
         /* allocate array of pointers to solutions */
         array = new SOLUTION *[count] ;

         curr = solutions ;
         count = 0 ;
         while (curr != nullptr)
         { /* fill array */
            array[count++] = curr ;
            curr = curr->next ;
         }

         /* sort array by error */
         qsort(&array[0], count, sizeof(SOLUTION *), CompSynt::sol_sort) ;

         /* build new chain */
         solutions = array[0] ;
         for (i=0; i<count; i++)
         {
            if (i > 0)
               array[i]->prev = array[i-1] ;
            else
               array[i]->prev = nullptr ;

            if (i < (count-1))
               array[i]->next = array[i+1] ;
            else
               array[i]->next = nullptr ;
         }

         /* delete array of pointers to solutions */
         delete[] array ;
      }
   }

   return(solutions) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Clear_Solutions                                                                           │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ release memory of any previous solutions                                                        │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::Clear_Solutions(SOLUTION *solutions)
{
SOLUTION  const*curr  = nullptr;
SOLUTION *next  = nullptr;

   curr = solutions ;
   while (curr != nullptr)
   {
      next = curr->next ;
      delete curr ;
      curr = next ;
   }

   return(nullptr) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Prepare_OutputWindow                                                                      │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Prepare output window, clear and set format                                                     │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::Prepare_OutputWindow(QTextEdit *win)
{
QTextCharFormat const cfm ;
QTextBlockFormat bfm ;
QTextCursor cursor ;
/* set output format to single line */
   cursor = win->textCursor() ;
   bfm.setLineHeight(1, QTextBlockFormat::SingleHeight) ;
   cursor.setBlockFormat(bfm) ;
   win->clear() ;
   win->setTextCursor(cursor) ;
//   cfm.setFontItalic(true) ;
//   ui->TE_OutputWindow->setCurrentCharFormat(cfm) ;
   win->setAlignment((QFlag) output_alignment) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       PrintSolution                                                                             │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Print a solution to QTextEdit                                                                   │
│                                                                                                 │
│ Returns true if solution was printed, false if it was not printed, because power or voltage     │
│ limit was exceeded.                                                                             │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
bool CompSynt::PrintSolution(QTextEdit *te, SOLUTION *sol)
{
COMPONENT comp ;
bool printed = false ;
QString fmt1 ;

   if (useLocale) fmt1 = "%L1" ; else fmt1 = "%1" ;

   if (sol->supplement.value != 0.0)
      te->insertPlainText(QString("+" + pval(sol->supplement.value) + "Ω => ")) ;

   switch(sol->topology)
   {
      case TOPO_S:
         comp = sol->comp[0] ;
         if (!(discardOutOfRange
             && (((comp.max_power != 0)   && (sol->power[0] > comp.max_power))
              || ((comp.max_voltage != 0) && (sol->voltage[0] > comp.max_voltage))) ))
         {
            te->setTextColor(colorNormal) ;
            if ((comp.max_power != 0) && (sol->power[0] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[0] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" (" + fmt1 + "% "+tr("error")+")").arg(100.0 * sol->error, 0, 'f', 2)) ;
            printed = true ;
         }
      break ;

      case TOPO_SS:
         comp = sol->comp[0] ;
         if (!(discardOutOfRange
              && (((comp.max_power != 0)   && (fmax(sol->power[0],sol->power[1]) > comp.max_power))
              || ((comp.max_voltage != 0) && (fmax(sol->voltage[0],sol->voltage[1]) > comp.max_voltage))) ))
         {
            te->setTextColor(colorNormal) ;
            if ((comp.max_power != 0) && (sol->power[0] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[0] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;

            comp = sol->comp[1] ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" - ")) ;
            if ((comp.max_power != 0) && (sol->power[1] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[1] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;

            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" = ") + pval(sol->actual)
                              + QString("Ω (" + fmt1 + "% "+tr("error")+")").arg(100.0 * sol->error, 0, 'f', 2)) ;
            printed = true ;
         }
      break ;

      case TOPO_PP:
         comp = sol->comp[0] ;
         if (!(discardOutOfRange
              && (((comp.max_power != 0)   && (fmax(sol->power[0],sol->power[1]) > comp.max_power))
              || ((comp.max_voltage != 0) && (fmax(sol->voltage[0],sol->voltage[1]) > comp.max_voltage))) ))
         {
            te->setTextColor(colorNormal) ;
            if ((comp.max_power != 0) && (sol->power[0] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[0] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;

            comp = sol->comp[1] ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" || ")) ;
            if ((comp.max_power != 0) && (sol->power[1] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[1] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;

            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" = ") + pval(sol->actual)
                              + QString("Ω (" + fmt1 + "% "+tr("error")+")").arg(100.0 * sol->error, 0, 'f', 2)) ;
            printed = true ;
         }
      break ;

      case TOPO_SSS:
         comp = sol->comp[0] ;
         if (!(discardOutOfRange
              && (((comp.max_power != 0)   && (fmax(sol->power[0],fmax(sol->power[1],sol->power[2])) > comp.max_power))
              || ((comp.max_voltage != 0) && (fmax(sol->voltage[0],fmax(sol->voltage[1],sol->voltage[1])) > comp.max_voltage))) ))
         {
            te->setTextColor(colorNormal) ;
            if ((comp.max_power != 0) && (sol->power[0] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[0] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" - ")) ;

            comp = sol->comp[1] ;
            if ((comp.max_power != 0) && (sol->power[1] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[1] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" - ")) ;

            comp = sol->comp[2] ;
            if ((comp.max_power != 0) && (sol->power[2] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[2] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" = ") + pval(sol->actual)
                           + QString("Ω (" + fmt1 + "% "+tr("error")+")").arg(100.0 * sol->error, 0, 'f', 2)) ;
            printed = true ;
         }
      break ;

      case TOPO_PPP:
         comp = sol->comp[0] ;
         if (!(discardOutOfRange
              && (((comp.max_power != 0)   && (fmax(sol->power[0],fmax(sol->power[1],sol->power[2])) > comp.max_power))
              || ((comp.max_voltage != 0) && (fmax(sol->voltage[0],fmax(sol->voltage[1],sol->voltage[1])) > comp.max_voltage))) ))
         {
            te->setTextColor(colorNormal) ;
            if ((comp.max_power != 0) && (sol->power[0] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[0] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" || ")) ;

            comp = sol->comp[1] ;
            if ((comp.max_power != 0) && (sol->power[1] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[1] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" || ")) ;

            comp = sol->comp[2] ;
            if ((comp.max_power != 0) && (sol->power[2] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[2] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" = ") + pval(sol->actual)
                              + QString("Ω (" + fmt1 + "% "+tr("error")+")").arg(100.0 * sol->error, 0, 'f', 2)) ;
            printed = true ;
         }
      break ;

      case TOPO_SPP:
         comp = sol->comp[0] ;
         if (!(discardOutOfRange
              && (((comp.max_power != 0)   && (fmax(sol->power[0],fmax(sol->power[1],sol->power[2])) > comp.max_power))
              || ((comp.max_voltage != 0) && (fmax(sol->voltage[0],fmax(sol->voltage[1],sol->voltage[1])) > comp.max_voltage))) ))
         {
            te->setTextColor(colorNormal) ;
            if ((comp.max_power != 0) && (sol->power[0] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[0] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" - (")) ;

            comp = sol->comp[1] ;
            if ((comp.max_power != 0) && (sol->power[1] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[1] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" || ")) ;

            comp = sol->comp[2] ;
            if ((comp.max_power != 0) && (sol->power[2] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[2] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(") = ") + pval(sol->actual)
                              + QString("Ω (" + fmt1 + "% "+tr("error")+")").arg(100.0 * sol->error, 0, 'f', 2)) ;
            printed = true ;
         }
      break ;

      case TOPO_SSP:
         comp = sol->comp[0] ;
         if (!(discardOutOfRange
              && (((comp.max_power != 0)   && (fmax(sol->power[0],fmax(sol->power[1],sol->power[2])) > comp.max_power))
              || ((comp.max_voltage != 0) && (fmax(sol->voltage[0],fmax(sol->voltage[1],sol->voltage[1])) > comp.max_voltage))) ))
         {
            te->setTextColor(colorNormal) ;
            if ((comp.max_power != 0) && (sol->power[0] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[0] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" || (")) ;

            comp = sol->comp[1] ;
            if ((comp.max_power != 0) && (sol->power[1] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[1] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(" - ")) ;

            comp = sol->comp[2] ;
            if ((comp.max_power != 0) && (sol->power[2] > comp.max_power)) te->setTextColor(colorExPower) ;
            if ((comp.max_voltage != 0) && (sol->voltage[2] > comp.max_voltage)) te->setTextColor(colorExVoltage) ;
            te->insertPlainText(pval(comp.value) + QString("Ω")) ;
            te->setTextColor(colorNormal) ;
            te->insertPlainText(QString(") = ") + pval(sol->actual)
                              + QString("Ω (" + fmt1 + "% "+tr("error")+")").arg(100.0 * sol->error, 0, 'f', 2)) ;
            printed = true ;
         }
      break ;

      default: break ;
   }

   te->insertPlainText(QString("\n")) ;

   return(printed) ;

}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       append_solutions                                                                          │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Append linked list <chain2> to linked list <chain1>                                             │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::append_solutions(SOLUTION *chain1, SOLUTION *chain2)
{
SOLUTION *next  = nullptr;
   if ((chain1 == nullptr) && (chain2 == nullptr)) return(nullptr) ;
   if (chain1 == nullptr) return(chain2) ;
   if (chain2 == nullptr) return(chain1) ;

/* both chains are not NULL */
   next = chain1 ;
   while (next->next != nullptr) next = next->next ; /* forward to end of chain1 */
   next->next = chain2 ;
   chain2->prev = next ;

   return(chain1) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       SetMainStatus                                                                             │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::SetMainStatus(const QString &msg)
{
   ui->statusbar->showMessage(msg, STATUSBAR_TIMEOUT_MS) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       pval                                                                                      │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Format an output value. Use suffixes 'k' or 'M' where appropriate.                              │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
QString CompSynt::pval(double val)
{
QString res ;
QChar suffix ;
bool append_suffix = false ;
QString fmt1 ;
double limit ;

   if (val < 1)
   {
      val *= 1000.0 ;
      suffix = u'm' ;
      append_suffix = true ;
   }

   if (val < 1)
   {
      val *= 1000.0 ;
      suffix = u'µ' ;
      append_suffix = true ;
   }

   if (val < 1)
   {
      val *= 1000.0 ;
      suffix = u'n' ;
      append_suffix = true ;
   }

   if (val < 1)
   {
      val *= 1000.0 ;
      suffix = u'p' ;
      append_suffix = true ;
   }

   if (val >= 1000.0)
   {
      val /= 1000.0 ;
      suffix = u'k' ;
      append_suffix = true ;
   }

   if (val >= 1000.0)
   {
      val /= 1000.0 ;
      suffix = u'M' ;
      append_suffix = true ;
   }

   if (useLocale) fmt1 = "%L1" ; else fmt1 = "%1" ;
   limit = 0.5 / pow(10.0, (double) decimal_places) ;
   if (val - (double)((uint32_t) val) >= limit) res = QString(fmt1).arg(val, 0, 'f', decimal_places) ;
   else res = QString(fmt1).arg(val, 0, 'f', 0) ;

   if (append_suffix) res.append(suffix) ;

   return(res) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       decode_double                                                                             │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Decode Line Edit to double                                                                      │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
bool CompSynt::decode_double(QLineEdit *le, CONVERSION *res)
{
   res->str = le->text() ;
   get_double(res) ;
   if (res->empty && !(res->deflt).isEmpty())
   {
      res->str = res->deflt ;
      get_double(res) ; /* repeat once with default value */
   }
   res->error = res->error || (res->empty && res->required) || ((res->positive) && (res->value < 0)) ;
   if (res->error)
   {
      le->setStyleSheet(LE_error_style) ;
   }
   else
   {
      le->setText(res->str) ;
      le->setStyleSheet(LE_default_style) ;
   }
   return(res->error) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       get_double                                                                                │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Parse and decode an input string with a numeric value and an optional suffix (k,M,G...).        │
│ Decimal points are supported as '.' or ','.                                                     │
│                                                                                                 │
│ return true on success, false on decoding error.                                                │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
CONVERSION *CompSynt::get_double(CONVERSION *conv)
{
bool ok = false ;
QString match1 ;
QString match2 ;
double mult  = NAN;
//QRegularExpression re(QStringLiteral(u"([-+]?\\d*[.,]?\\d*)\\s*([TGMkmuµnp%]?\\D*)")) ;
QRegularExpression const re(QStringLiteral(u"([-+]?[\\d.]*,?\\d*e?[+-]?\\d+)\\s*([TGMkmuµnp%]?\\D*)")) ;
QRegularExpressionMatch match ;
QLocale const default_locale ;

   conv->empty = true ;
   conv->relative = false ;
   conv->error = false ;
   mult = 1.0 ;

   if (conv->str.isEmpty() && (!conv->required)) return(conv) ;

   match = re.match(conv->str) ;

   if (!match.hasMatch()) conv->error = true ;
   else
   {
      match1 = match.captured(1) ;
      conv->empty = match1.isEmpty() ;
      if (!conv->empty)
      {
         conv->str = match1 ;
         match2 = match.captured(2) ;
         if (!match2.isEmpty())
         {
            conv->str = conv->str+" "+match2 ;
            if (match2[0] == u'T') mult = 1e12  ;
            if (match2[0] == u'G') mult = 1e9  ;
            if (match2[0] == u'M') mult = 1e6  ;
            if (match2[0] == u'k') mult = 1e3  ;
            if (match2[0] == u'm') mult = 1e-3  ;
            if (match2[0] == u'u') mult = 1e-6  ;
            if (match2[0] == u'µ') mult = 1e-6  ;
            if (match2[0] == u'n') mult = 1e-9  ;
            if (match2[0] == u'p') mult = 1e-12  ;
            if (match2[0] == u'%') {mult = 1e-2  ; conv->relative = true ;}
         }

         if (useLocale)
            conv->value = mult * default_locale.toDouble(match1, &ok) ; /* get value in default locale */
         else
            conv->value = mult * match1.toDouble(&ok) ; /* get value in C locale */
         conv->error = !ok ;
      }
   }

   return(conv) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       ct_sort                                                                                   │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Sort source component table to destination in ascending order                                   │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
bool CompSynt::ct_sort(double a, double b)
{
   return(a < b) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       ct_sortprivate                                                                            │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Sort private component table including limits by value in ascending order                       │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
bool CompSynt::ct_sortprivate(COMPONENT a, COMPONENT b)
{
   return(a.value < b.value) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       sol_sort                                                                                  │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Sort array of SOLUTION pointers                                                                 │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
int CompSynt::sol_sort(const void *a, const void *b)
{
SOLUTION  const*pa  = nullptr;
SOLUTION  const*pb  = nullptr;

   pa = *((SOLUTION **) a) ;
   pb = *((SOLUTION **) b) ;

   if (pa->error > pb->error) return( 1) ;
   if (pa->error < pb->error) return(-1) ;

/* same error, sort by topology */
   if (pa->topology > pb->topology) return( 1) ;
   if (pa->topology < pb->topology) return(-1) ;

/* same error, same topology, then sort by first value */
   if (pa->comp[0].value > pb->comp[0].value) return( 1) ;
   if (pa->comp[0].value < pb->comp[0].value) return(-1) ;

/* same error, same topology, same first value, then sort by second value */
   if (pa->comp[1].value > pb->comp[1].value) return( 1) ;
   if (pa->comp[1].value < pb->comp[1].value) return(-1) ;

   return(0) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       enqueue                                                                                   │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Enqueue current solution if component deviation is below configured value.                      │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::enqueue(SOLUTION *sol_chain, SOLUTION *sol_tmp)
{
double deviation = 0 ; /* deviation between the individual components */
uint32_t i  = 0;
SOLUTION *new_sol  = nullptr;

   switch (sol_tmp->topology)
   {
      case TOPO_SS:
      case TOPO_PP:
         deviation = fmax(sol_tmp->comp[0].value, sol_tmp->comp[1].value)
                   / fmin(sol_tmp->comp[0].value, sol_tmp->comp[1].value) ;
      break ;

      case TOPO_PPP:
      case TOPO_SSS:
      case TOPO_SPP:
      case TOPO_SSP:
      case TOPO_PPS:
      case TOPO_SSS1:
      case TOPO_SSS2:
         deviation = fmax(sol_tmp->comp[2].value, fmax(sol_tmp->comp[0].value, sol_tmp->comp[1].value))
                   / fmin(sol_tmp->comp[2].value, fmin(sol_tmp->comp[0].value, sol_tmp->comp[1].value)) ;
      break ;

      default:
         deviation = 0 ;
      break ;
   }

   if (deviation > (double) resdev)
   {
      new_sol = sol_chain ;
   }
   else

   {
      new_sol = new SOLUTION ;
      sol_copy(new_sol, sol_tmp) ;
      new_sol->prev = sol_chain ;
      new_sol->next = nullptr ;
      if (sol_chain != nullptr) sol_chain->next = new_sol ;
   }
   return(new_sol) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       sol_copy                                                                                  │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Copy a solution                                                                                 │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::sol_copy(SOLUTION *sol_dest, SOLUTION *sol_src)
{
uint32_t i  = 0;

   sol_dest->prev        = sol_src->prev ;              /* pointer to previous solution */
   sol_dest->next        = sol_src->next ;              /* pointer to next solution */
   sol_dest->target      = sol_src->target ;            /* target value */
   sol_dest->actual      = sol_src->actual ;            /* actual value */
   sol_dest->error       = sol_src->error ;             /* error */
   sol_dest->max_error   = sol_src->max_error ;         /* maximum error */
   sol_dest->supplement  = sol_src->supplement ;        /* pointer to supplement */
   sol_dest->topology    = sol_src->topology ;          /* network topology */

   for (i=0; i<COMP_COUNT; i++)
   {
      sol_dest->comp[i]    = sol_src->comp[i] ;         /* pointers to selected components */
      sol_dest->voltage[i] = sol_src->voltage[i] ;      /* voltage across a component (or 0 if unused) */
      sol_dest->power[i]   = sol_src->power[i] ;        /* power dissipation of a component (or 0 if unused) */
   }

   return(sol_dest) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       sol_init                                                                                  │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Initialize a solution with target values or zero if appropriate                                 │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::sol_init(SOLUTION *sol, PARMS *parameter, TOPO topology)
{
uint32_t i  = 0;

   sol->prev = nullptr ;
   sol->next = nullptr ;
   sol->target = parameter->value ;
   sol->actual = 0.0 ;
   sol->error = 0.0 ;
   sol->max_error = parameter->max_error ;
   sol->supplement = DEFAULT_COMPONENT ;
   sol->topology = topology ;

   for (i=0; i<COMP_COUNT; i++)
   {
      sol->comp[i]    = DEFAULT_COMPONENT ;  /* init components */
      sol->voltage[i] = 0.0 ;   /* voltage across a component (or 0 if unused) */
      sol->power[i]   = 0.0 ;   /* power dissipation of a component (or 0 if unused) */
   }

   return(sol) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       search_single                                                                             │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Search for single resistor between min and max                                                  │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
COMP_TABLE *CompSynt::search_single(COMP_TABLE *ct_src, COMP_TABLE *ct_dest, double min, double max)
{
uint32_t cntr  = 0;

   ct_dest->clear() ;
   if (min < 0.0) min = 0.0 ; /* might happen when min is calculated */
   if (max < 0.0) max = DBL_MAX ; /* might happen when max is calculated */
   for (cntr=0; (cntr<ct_src->size() && (ct_src->at(cntr).value<min)); cntr++) ;
   for (      ; (cntr<ct_src->size() && (ct_src->at(cntr).value<max)); cntr++)
      ct_dest->push_back(ct_src->at(cntr)) ;
   return(ct_dest) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       search_parallel                                                                           │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Search for two parallel resistors between min and max                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
COMP_TABLE *CompSynt::search_parallel(COMP_TABLE *ct_src, COMP_TABLE *ct_dest, double min, double max, double start)
{
uint32_t cntr1  = 0;
uint32_t cntr2  = 0;
double res ;
double r1 ;
double r2 ;
double tol1 ;
double tol2 ;
bool tol_exceeded ;

   ct_dest->clear() ;
   if (min < 0.0) min = 0.0 ; /* might happen when min is calculated */
   if (max < 0.0) max = DBL_MAX ; /* might happen when max is calculated */
   /* ignore all below start */
   for (cntr1=0; (cntr1<ct_src->size() && (ct_src->at(cntr1).value<start)); cntr1++) ;
   /* ignore all below minimum */
   for (       ; (cntr1<ct_src->size() && (ct_src->at(cntr1).value<min)); cntr1++) ;
   for (       ;  cntr1<ct_src->size()                                  ; cntr1++)
   { /* process all above minimum */
      for (cntr2=cntr1; cntr2<ct_src->size(); cntr2++)
      { /* R2 could be equal to R1 and above */
         r1 = ct_src->at(cntr1).value ;
         r2 = ct_src->at(cntr2).value ;
         res = 1.0 / ((1/r1) + (1/r2)) ;
         tol_exceeded = false ;

         if ((res >= min) && (res <= max) && (!tol_exceeded))
         { /* add R1 and R2 to vector */
            ct_dest->push_back(ct_src->at(cntr1)) ;
            ct_dest->push_back(ct_src->at(cntr2)) ;
         }
      }
   }
   return(ct_dest) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       search_serial                                                                             │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Search for two serial resistors between min and max                                             │
│                                                                                                 │
│ Start search at res >= start                                                                    │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
COMP_TABLE *CompSynt::search_serial(COMP_TABLE *ct_src, COMP_TABLE *ct_dest, double min, double max, double start)
{
uint32_t cntr1  = 0;
uint32_t cntr2  = 0;
double res ;
double r1 ;
double r2 ;
double tol1 ;
double tol2 ;
bool tol_exceeded ;

   ct_dest->clear() ;
   if (min < 0.0) min = 0.0 ; /* might happen when min is calculated */
   if (max < 0.0) max = DBL_MAX ; /* might happen when max is calculated */
   /* ignore all above maximum */
   for (cntr1=0; (cntr1<ct_src->size() && (ct_src->at(cntr1).value<start)); cntr1++) ;
   for (       ; (cntr1<ct_src->size() && (ct_src->at(cntr1).value<=max)); cntr1++)
   { /* process up to maximum */
      for (cntr2=cntr1; (cntr2<ct_src->size() && (ct_src->at(cntr2).value<=max)); cntr2++)
      { /* R2 could be equal to R1 and above, but not higher than maximum */
         r1 = ct_src->at(cntr1).value ;
         r2 = ct_src->at(cntr2).value ;
         res = r1 + r2 ;
         tol_exceeded = false ;

         if ((res >= min) && (res <= max) && (!tol_exceeded))
         { /* add R1 and R2 to vector */
            ct_dest->push_back(ct_src->at(cntr1)) ;
            ct_dest->push_back(ct_src->at(cntr2)) ;
         }
      }
   }
   return(ct_dest) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       topo_rs                                                                                   │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Analyse RS topology                                                                             │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::topo_rs(COMP_TABLE *ct, PARMS *parameter)
{ /* just one resistor */
SOLUTION  *sol_root = nullptr ;
SOLUTION *sol_chain = nullptr ;
SOLUTION sol_tmp ;
uint32_t loopcntr  = 0;
double curr  = NAN;
double ulimit  = NAN;
double llimit  = NAN;
uint32_t i = 0 ;
COMP_TABLE new_table ;

   sol_init(&sol_tmp, parameter, TOPO_S) ;

   ulimit = parameter->value * (1.0 + parameter->max_error) ; /* upper limit */
   llimit = parameter->value * (1.0 - parameter->max_error) ; /* lower limit */

   search_single(ct, &new_table, llimit, ulimit) ;

   for (i=0; i<new_table.size(); i++)
   {
      curr = new_table.at(i).value ;
      sol_tmp.actual = curr ;
      sol_tmp.error = fabs(parameter->value - curr) / parameter->value ;
      sol_tmp.comp[0]    = new_table.at(i) ;
      sol_tmp.voltage[0] = parameter->applied_voltage ;
      sol_tmp.power[0] = parameter->applied_voltage * parameter->applied_voltage / curr ;
      sol_chain = enqueue(sol_chain, &sol_tmp) ;
      if (sol_root == nullptr) sol_root = sol_chain ;
   }
   return(sol_root) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       topo_rss                                                                                  │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Analyse RSS topology                                                                            │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::topo_rss(COMP_TABLE *ct, PARMS *parameter)
{ /* two serial resistors */
SOLUTION *sol_root = nullptr ;
SOLUTION *sol_chain = nullptr ;
SOLUTION sol_tmp ;

double llimit  = NAN;
double ulimit  = NAN;
double curr  = NAN;
double val1  = NAN;
double val2  = NAN;
double i_current  = NAN;
uint32_t outer_cntr  = 0;
uint32_t inner_cntr  = 0;
uint32_t i = 0 ;
COMP_TABLE new_table ;

   sol_init(&sol_tmp, parameter, TOPO_SS) ;

   ulimit = parameter->value * (1.0 + parameter->max_error) ; /* upper limit */
   llimit = parameter->value * (1.0 - parameter->max_error) ; /* lower limit */

   search_serial(ct, &new_table, llimit, ulimit, 0.0) ;

   for (i=0; i<new_table.size(); i+=2)
   {
      curr = new_table.at(i).value + new_table.at(i+1).value ;
      sol_tmp.actual = curr ;
      sol_tmp.error = fabs(parameter->value - curr) / parameter->value ;
      val1 = new_table.at(i).value ;
      val2 = new_table.at(i+1).value ;
      sol_tmp.comp[0]   = new_table.at(i) ;     /* first serial resistor */
      sol_tmp.comp[1]   = new_table.at(i+1) ;     /* second serial resistor */

      i_current = parameter->applied_voltage / (val1 + val2) ;
      sol_tmp.voltage[0] = val1 * i_current ;
      sol_tmp.voltage[1] = val2 * i_current ;
      sol_tmp.power[0] = sol_tmp.voltage[0] * i_current ;
      sol_tmp.power[1] = sol_tmp.voltage[1] * i_current ;

      sol_chain = enqueue(sol_chain, &sol_tmp) ;
      if (sol_root == nullptr) sol_root = sol_chain ;
   }

   return(sol_root) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       topo_rpp                                                                                  │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Analyse RPP topology                                                                            │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::topo_rpp(COMP_TABLE *ct, PARMS *parameter)
{ /* two parallel resistors */
SOLUTION *sol_root = nullptr ;
SOLUTION *sol_chain = nullptr ;
SOLUTION sol_tmp ;

double llimit  = NAN;
double ulimit  = NAN;
double curr  = NAN;
double val1  = NAN;
double val2  = NAN;
uint32_t outer_cntr  = 0;
uint32_t inner_cntr  = 0;
uint32_t i = 0 ;
COMP_TABLE new_table ;

   sol_init(&sol_tmp, parameter, TOPO_PP) ;

   ulimit = parameter->value * (1.0 + parameter->max_error) ; /* upper limit */
   llimit = parameter->value * (1.0 - parameter->max_error) ; /* lower limit */

   search_parallel(ct, &new_table, llimit, ulimit, 0.0) ;
   for (i=0; i<new_table.size(); i+=2)
   {
      curr = 1/((1/new_table.at(i).value)+(1/new_table.at(i+1).value)) ;

      sol_tmp.actual = curr ;
      sol_tmp.error = fabs(parameter->value - curr) / parameter->value ;
      val1 = new_table.at(i).value ;
      val2 = new_table.at(i+1).value ;
      sol_tmp.comp[0]   = new_table.at(i) ;     /* first parallel resistor */
      sol_tmp.comp[1]   = new_table.at(i+1) ;     /* second parallel resistor */

      sol_tmp.voltage[0] = parameter->applied_voltage ;
      sol_tmp.voltage[1] = parameter->applied_voltage ;
      sol_tmp.power[0] = parameter->applied_voltage * parameter->applied_voltage / val1 ;
      sol_tmp.power[1] = parameter->applied_voltage * parameter->applied_voltage / val2 ;

      sol_chain = enqueue(sol_chain, &sol_tmp) ;
      if (sol_root == nullptr) sol_root = sol_chain ;
   }

   return(sol_root) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       topo_rsss                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Analyse RSSS topology                                                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::topo_rsss(COMP_TABLE *ct, PARMS *parameter)
{ /* three serial resistors */
SOLUTION *sol_root = nullptr ;
SOLUTION *sol_chain = nullptr ;
SOLUTION sol_tmp ;

double llimit  = NAN;
double ulimit  = NAN;
double curr  = NAN;
double val1  = NAN;
double val2  = NAN;
double val3  = NAN;
double limit1  = NAN;
double limit2  = NAN;
uint32_t outer_cntr  = 0;
uint32_t middle_cntr  = 0;
uint32_t inner_cntr  = 0;
double i_current  = NAN;
uint32_t i = 0 ;
double r1 ;
double r2 ;
double r3 ;
double rmin ;
double rmax ;
COMP_TABLE new_table ;

   sol_init(&sol_tmp, parameter, TOPO_SSS) ;

   ulimit = parameter->value * (1.0 + parameter->max_error) ; /* upper limit */
   llimit = parameter->value * (1.0 - parameter->max_error) ; /* lower limit */

   for (outer_cntr = 0; (outer_cntr < ct->size()) && (ct->at(outer_cntr).value < ulimit); outer_cntr++)
   { /* do while r1 is below upper limit */
      r1 = ct->at(outer_cntr).value ;
      new_table.clear() ;
      search_serial(ct, &new_table, llimit-r1, ulimit-r1, r1) ;
      for (i=0; i<new_table.size(); i+=2)
      {
         r2 = new_table.at(i).value ;
         r3 = new_table.at(i+1).value ;
         curr = r1 + r2 + r3 ;
         if ((curr >= llimit) && (curr <= ulimit))
         {
            sol_tmp.actual = curr ;
            sol_tmp.error = fabs(parameter->value - curr) / parameter->value ;
            val1 = r1 ;
            val2 = r2 ;
            val3 = r3 ;
            sol_tmp.comp[0]   = ct->at(outer_cntr) ;  /* first serial resistor */
            sol_tmp.comp[1]   = new_table.at(i) ; /* second serial resistor */
            sol_tmp.comp[2]   = new_table.at(i+1) ;  /* third serial resistor */

            i_current = parameter->applied_voltage / (val1 + val2 + val3) ;
            sol_tmp.voltage[0] = val1 * i_current ;
            sol_tmp.voltage[1] = val2 * i_current ;
            sol_tmp.voltage[2] = val3 * i_current ;
            sol_tmp.power[0] = val1 * i_current * i_current ;
            sol_tmp.power[1] = val2 * i_current * i_current ;
            sol_tmp.power[2] = val3 * i_current * i_current ;

            sol_chain = enqueue(sol_chain, &sol_tmp) ;
            if (sol_root == nullptr) sol_root = sol_chain ;
         }
      }
   }

   return(sol_root) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       topo_rppp                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Analyse RPPP topology                                                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::topo_rppp(COMP_TABLE *ct, PARMS *parameter)
{ /* three parallel resistors */
SOLUTION *sol_root = nullptr ;
SOLUTION *sol_chain = nullptr ;
SOLUTION sol_tmp ;

double llimit  = NAN;
double ulimit  = NAN;
double ilimit  = NAN;
double iilimit  = NAN;
double curr  = NAN;
double val1  = NAN;
double val2  = NAN;
double val3  = NAN;
double minres  = NAN;
uint32_t outer_cntr  = 0;
uint32_t inner_cntr  = 0;
uint32_t iinner_cntr  = 0;
uint32_t i = 0 ;
double r1 ;
double r2 ;
double r3 ;
double rmin ;
double rmax ;
COMP_TABLE new_table ;

   sol_init(&sol_tmp, parameter, TOPO_PPP) ;

   ulimit = parameter->value * (1.0 + parameter->max_error) ; /* upper limit */
   llimit = parameter->value * (1.0 - parameter->max_error) ; /* lower limit */

   /* ignore all below lower limit */
   for (outer_cntr=0; (outer_cntr<ct->size() && (ct->at(outer_cntr).value < llimit)); outer_cntr++) ;
   for (            ; outer_cntr < ct->size(); outer_cntr++)
   { /* process all above minimum */
      r1 = ct->at(outer_cntr).value ;
      new_table.clear() ;
      rmin = 1.0 / ((1.0/llimit) - (1.0/r1)) ;
      rmax = 1.0 / ((1.0/ulimit) - (1.0/r1)) ;
      search_parallel(ct, &new_table, rmin, rmax, r1) ;

      for (i=0; i<new_table.size(); i+=2)
      {
         r2 = new_table.at(i).value ;
         r3 = new_table.at(i+1).value ;
         curr = 1.0 / ((1.0/r1) + (1.0/r2) + (1.0/r3)) ;
         if ((curr >= llimit) && (curr <= ulimit))
         {
            sol_tmp.actual = curr ;
            sol_tmp.error = fabs(parameter->value - curr) / parameter->value ;
            val1 = r1 ;
            val2 = r2 ;
            val3 = r3 ;
            sol_tmp.comp[0]   = ct->at(outer_cntr) ;  /* first serial resistor */
            sol_tmp.comp[1]   = new_table.at(i) ; /* second serial resistor */
            sol_tmp.comp[2]   = new_table.at(i+1) ;  /* third serial resistor */

            sol_tmp.voltage[0] = parameter->applied_voltage ;
            sol_tmp.voltage[1] = parameter->applied_voltage ;
            sol_tmp.voltage[2] = parameter->applied_voltage ;
            sol_tmp.power[0] = parameter->applied_voltage * parameter->applied_voltage / val1 ;
            sol_tmp.power[1] = parameter->applied_voltage * parameter->applied_voltage / val2 ;
            sol_tmp.power[2] = parameter->applied_voltage * parameter->applied_voltage / val3 ;

            sol_chain = enqueue(sol_chain, &sol_tmp) ;
            if (sol_root == nullptr) sol_root = sol_chain ;
         }
      }
   }

   return(sol_root) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       topo_rssp                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Analyse RSSP topology                                                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::topo_rssp(COMP_TABLE *ct, PARMS *parameter)
{ /* two serial resistors parallel to one resistor */
SOLUTION *sol_root = nullptr ;
SOLUTION *sol_chain = nullptr ;
SOLUTION sol_tmp ;

double llimit  = NAN;
double ulimit  = NAN;
double llimitres  = NAN;
double curr  = NAN;
double val1  = NAN;
double val2  = NAN;
double val3  = NAN;
double res_ser  = NAN;
double i_current  = NAN;
uint32_t outer_cntr  = 0;
uint32_t middle_cntr  = 0;
uint32_t inner_cntr  = 0;
uint32_t i = 0 ;
double r1 ;
double r2 ;
double r3 ;
double rmin ;
double rmax ;
COMP_TABLE new_table ;

   sol_init(&sol_tmp, parameter, TOPO_SSP) ;

   ulimit = parameter->value * (1.0 + parameter->max_error) ; /* upper limit */
   llimit = parameter->value * (1.0 - parameter->max_error) ; /* lower limit */

   /* ignore all below lower limit */
   for (outer_cntr=0; (outer_cntr<ct->size() && (ct->at(outer_cntr).value < llimit)); outer_cntr++) ;
   for (            ; outer_cntr < ct->size(); outer_cntr++)
   { /* process all above minimum */
      r1 = ct->at(outer_cntr).value ;
      new_table.clear() ;
      rmin = 1.0 / ((1.0/llimit) - (1.0/r1)) ;
      rmax = 1.0 / ((1.0/ulimit) - (1.0/r1)) ;
      search_serial(ct, &new_table, rmin, rmax, 0.0) ;

      for (i=0; i<new_table.size(); i+=2)
      {
         r2 = new_table.at(i).value ;
         r3 = new_table.at(i+1).value ;
         curr = 1.0 / ((1.0/r1) + (1.0/(r2+r3))) ;
         if ((curr >= llimit) && (curr <= ulimit))
         {
            sol_tmp.actual = curr ;
            sol_tmp.error = fabs(parameter->value - curr) / parameter->value ;
            val1 = r1 ;
            val2 = r2 ;
            val3 = r3 ;
            sol_tmp.comp[0]   = ct->at(outer_cntr) ;  /* single parallel resistor */
            sol_tmp.comp[1]   = new_table.at(i) ; /* first serial resistor */
            sol_tmp.comp[2]   = new_table.at(i+1) ;  /* second serial resistor */

            res_ser = val2 + val3 ;
            i_current = parameter->applied_voltage / res_ser ;
            sol_tmp.voltage[0] = parameter->applied_voltage ;
            sol_tmp.voltage[1] = val2 * i_current ;
            sol_tmp.voltage[2] = val3 * i_current ;

            sol_tmp.power[0] = sol_tmp.voltage[0] * sol_tmp.voltage[0] / val1 ;
            sol_tmp.power[1] = sol_tmp.voltage[1] * i_current ;
            sol_tmp.power[2] = sol_tmp.voltage[2] * i_current ;

            sol_chain = enqueue(sol_chain, &sol_tmp) ;
            if (sol_root == nullptr) sol_root = sol_chain ;
         }
      }
   }

   return(sol_root) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       topo_rspp                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Analyse RSPP topology                                                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SOLUTION *CompSynt::topo_rspp(COMP_TABLE *ct, PARMS *parameter)
{ /* one resistor serial to two parallel resistors */
SOLUTION *sol_root = nullptr ;
SOLUTION *sol_chain = nullptr ;
SOLUTION sol_tmp ;

double llimit  = NAN;
double ulimit  = NAN;
double mllimit  = NAN;
double mulimit  = NAN;
double curr  = NAN;
double val1  = NAN;
double val2  = NAN;
double val3  = NAN;
double i_current  = NAN;
double res_par  = NAN;
uint32_t outer_cntr  = 0;
uint32_t middle_cntr  = 0;
uint32_t i = 0 ;
double r1 ;
double r2 ;
double r3 ;
double rmin ;
double rmax ;
COMP_TABLE new_table ;
uint32_t inner_cntr  = 0;

   sol_init(&sol_tmp, parameter, TOPO_SPP) ;

   ulimit = parameter->value * (1.0 + parameter->max_error) ; /* upper limit */
   llimit = parameter->value * (1.0 - parameter->max_error) ; /* lower limit */

   for (outer_cntr=0; (outer_cntr<ct->size() && (ct->at(outer_cntr).value < ulimit)); outer_cntr++)
   { /* process all below maximum */
      r1 = ct->at(outer_cntr).value ;
      new_table.clear() ;
      search_parallel(ct, &new_table, llimit-r1, ulimit-r1, 0.0) ;

      for (i=0; i<new_table.size(); i+=2)
      {
         r2 = new_table.at(i).value ;
         r3 = new_table.at(i+1).value ;
         curr = r1 + 1.0 / ((1.0/r2) + (1.0/r3)) ;
         if ((curr >= llimit) && (curr <= ulimit))
         {
            sol_tmp.actual = curr ;
            sol_tmp.error = fabs(parameter->value - curr) / parameter->value ;
            val1 = r1 ;
            val2 = r2 ;
            val3 = r3 ;
            sol_tmp.comp[0]   = ct->at(outer_cntr) ;  /* serial resistor */
            sol_tmp.comp[1]   = new_table.at(i) ; /* first parallel resistor */
            sol_tmp.comp[2]   = new_table.at(i+1) ;  /* second parallel resistor */

            res_par = 1/(1/val2 + 1/val3) ;

            i_current = parameter->applied_voltage / (val1 + res_par) ;
            sol_tmp.voltage[0] = val1 * i_current ;
            sol_tmp.voltage[1] = res_par * i_current ;
            sol_tmp.voltage[2] = res_par * i_current ;
            sol_tmp.power[0] = val1 * i_current * i_current ;
            sol_tmp.power[1] = sol_tmp.voltage[1] * sol_tmp.voltage[1] / val2 ;
            sol_tmp.power[2] = sol_tmp.voltage[2] * sol_tmp.voltage[2] / val3 ;

            sol_chain = enqueue(sol_chain, &sol_tmp) ;
            if (sol_root == nullptr) sol_root = sol_chain ;
         }
      }
   }

   return(sol_root) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       make_IECMasterTable                                                                       │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Make IEC master table from currently selected IEC series                                        │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
COMP_TABLE *CompSynt::make_IECMasterTable(COMP_TABLE *ct_dest,
                                int32_t min_val,
                                uint32_t decade_cnt,
                                PARMS *parameter)
{
uint32_t icntr  = 0;
uint32_t ocntr  = 0;
double mult  = NAN;
double tolerance  = NAN;
double max_power  = NAN;
double max_voltage  = NAN;
//double static tmp_array[CT_SIZE_PER_DECADE] ;
static IEC_TABLE ct_tmp ;
COMPONENT newcomp ;

   ct_tmp.clear() ;
   ct_dest->clear() ;

   if (ui->CB_R_E6->isChecked())   ct_append(&ct_tmp, &iec_e6) ;
   if (ui->CB_R_E12->isChecked())  ct_append(&ct_tmp, &iec_e12) ;
   if (ui->CB_R_E24->isChecked())  ct_append(&ct_tmp, &iec_e24) ;
   if (ui->CB_R_E48->isChecked())  ct_append(&ct_tmp, &iec_e48) ;
   if (ui->CB_R_E96->isChecked())  ct_append(&ct_tmp, &iec_e96) ;
   if (ui->CB_R_E192->isChecked()) ct_append(&ct_tmp, &iec_e192) ;

   tolerance   = (parameter == nullptr) ? 0.0 : parameter->tolerance ;
   max_power   = (parameter == nullptr) ? 0.0 : parameter->max_power ;
   max_voltage = (parameter == nullptr) ? 0.0 : parameter->max_voltage ;

   if (!ct_tmp.empty())
   {
      sort(ct_tmp.begin(), ct_tmp.end(), ct_sort) ;
//      sort(ct_tmp.begin(), ct_tmp.end()) ;
      mult = pow(10.0, (double) min_val) ;
      for (ocntr=0; ocntr<decade_cnt; ocntr++)
      {
         for (icntr=0; icntr<ct_tmp.size(); icntr++)
         {
            newcomp.value = ct_tmp.at(icntr) * mult ;
            newcomp.tolerance = tolerance ;
            newcomp.max_power = max_power ;
            newcomp.max_voltage = max_voltage ;
            ct_dest->push_back(newcomp) ;
         }
         mult *= 10.0 ;
      }
   }

   return(ct_dest) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       generate_ActiveTable                                                                      │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Generate active table to be used for subsequent search                                          │
│                                                                                                 │
│ Copy source table to destination, optionally append a single supplement component               │
│ and sort new table. supplement can be NULL.                                                     │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
COMP_TABLE *CompSynt::generate_ActiveTable(COMP_TABLE *ct_dest,
                             COMP_TABLE *ct_src,
                             COMPONENT *supplement)
{
uint32_t i  = 0;
COMPONENT comp ;

   /* remove supplement if it is already in the source list */
   for (i=0; ((i<ct_src->size()) && (supplement != nullptr)); i++)
      if (ct_src->at(i).value == supplement->value) supplement = nullptr ;

   ct_dest->clear() ; /* clear table */
   for (i=0; i<ct_src->size(); i++)
   { /* copy source to destination */
      comp.value       = ct_src->at(i).value ;
      comp.max_power   = ct_src->at(i).max_power ;
      comp.max_voltage = ct_src->at(i).max_voltage ;
      comp.tolerance   = ct_src->at(i).tolerance ;
      ct_dest->push_back(comp) ;
   }

   if (supplement != nullptr)
   { /* append supplement */
      comp.value       = supplement->value ;
      comp.max_power   = supplement->max_power ;
      comp.max_voltage = supplement->max_voltage ;
      comp.tolerance   = supplement->tolerance ;
      ct_dest->push_back(comp) ;
   }

   if (!ct_dest->empty())
   { /* sort table if not empty */
      sort(ct_dest->begin(), ct_dest->end(), ct_sortprivate) ;
   }

   return(ct_dest) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       ct_append                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Append source component table to destination, skip existing values                              │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
IEC_TABLE *CompSynt::ct_append(IEC_TABLE *ct_dest, IEC_TABLE *ct_src)
{
uint32_t scnt  = 0;
uint32_t dcnt  = 0;
   for (scnt=0; scnt<ct_src->size(); scnt++)
   {
      for (dcnt=0; dcnt<ct_dest->size(); dcnt++)
      {
         if (ct_dest->at(dcnt) == ct_src->at(scnt)) break ;
      }
      if (dcnt == ct_dest->size())
      { /* value not found, append */
         ct_dest->push_back(ct_src->at(scnt)) ;
      }
   }

   return(ct_dest) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       loadSettings                                                                              │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Load initialization settings from registry or ini-file and set dialogs accordingly.             │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::loadSettings()
{
QSettings const settings;
//
   QSettings::setDefaultFormat(QSettings::NativeFormat);

   restoreGeometry(settings.value(KEY_WIN + "geometry").toByteArray()) ;
   restoreState(settings.value(KEY_WIN + "windowState").toByteArray()) ;

   ui->LE_R_Target->setText(       settings.value(KEY_RES + "Target", "").toString()) ;
   ui->LE_R_MaxError->setText(     settings.value(KEY_RES + "MaxError", "").toString()) ;
   ui->LE_R_Tolerance->setText(    settings.value(KEY_RES + "Tolerance", "").toString()) ;
   ui->LE_R_Voltage->setText(      settings.value(KEY_RES + "Voltage", "").toString()) ;
   ui->LE_R_PowerRating->setText(  settings.value(KEY_RES + "PowerRating", "").toString()) ;
   ui->LE_R_MaxVoltage->setText(   settings.value(KEY_RES + "MaxVoltage", "").toString()) ;

   ui->CB_R_E6->setChecked(        settings.value(KEY_RES + "E6",      false).toBool()) ;
   ui->CB_R_E12->setChecked(       settings.value(KEY_RES + "E12",     false).toBool()) ;
   ui->CB_R_E24->setChecked(       settings.value(KEY_RES + "E24",     false).toBool()) ;
   ui->CB_R_E48->setChecked(       settings.value(KEY_RES + "E48",     false).toBool()) ;
   ui->CB_R_E96->setChecked(       settings.value(KEY_RES + "E96",     false).toBool()) ;
   ui->CB_R_E192->setChecked(      settings.value(KEY_RES + "E192",    false).toBool()) ;

   ui->CB_NT_RS->setChecked(       settings.value(KEY_RES + "NT_RS",   false).toBool()) ;
   ui->CB_NT_RSS->setChecked(      settings.value(KEY_RES + "NT_RSS",  false).toBool()) ;
   ui->CB_NT_RPP->setChecked(      settings.value(KEY_RES + "NT_RPP",  false).toBool()) ;
   ui->CB_NT_RSSP->setChecked(     settings.value(KEY_RES + "NT_RSSP", false).toBool()) ;
   ui->CB_NT_RSSS->setChecked(     settings.value(KEY_RES + "NT_RSSS", false).toBool()) ;
   ui->CB_NT_RPPP->setChecked(     settings.value(KEY_RES + "NT_RPPP", false).toBool()) ;
   ui->CB_NT_RSPP->setChecked(     settings.value(KEY_RES + "NT_RSPP", false).toBool()) ;

   ui->RB_R_IEC->setChecked(       settings.value(KEY_RES + "RB_R_IEC", false).toBool()) ;
   ui->RB_R_Private->setChecked(   settings.value(KEY_RES + "RB_R_Private", false).toBool()) ;

   private_fileformat = settings.value(KEY_PROG + "PrivateFileFormat", FMT_UNITS).toInt() ;
   printline_count = settings.value(KEY_PROG + "PrintLines", 100).toInt() ;
   decimal_places = settings.value(KEY_PROG + "DecimalPlaces", 2).toInt() ;
   output_alignment = settings.value(KEY_PROG + "OutputAlignment", Qt::AlignRight).toInt() ;
   useLocale = settings.value(KEY_PROG + "UseLocale", true).toBool() ;

   rdecades = settings.value(KEY_RES + "DecadeCount", 8).toInt() ;
   cdecades = settings.value(KEY_CAP + "DecadeCount", 10).toInt() ;
   log10rmin = settings.value(KEY_RES + "Log10RMin", -3).toInt() ;
   resdev = settings.value(KEY_RES + "MaxDeviation", 100).toInt() ;
   log10cmin = settings.value(KEY_CAP + "Log10CMin", -14).toInt() ;

   discardOutOfRange = settings.value(KEY_RES + "DiscardOutOfRange", false).toBool() ;
   LastFile_R = settings.value(KEY_RES + "LastFile", "").toString() ;

   colorNormalName    = settings.value(KEY_PROG + "ColorNormal", "Blue").toString() ;
   colorExPowerName   = settings.value(KEY_PROG + "ColorExceededPower", "Red").toString() ;
   colorExVoltageName = settings.value(KEY_PROG + "ColorExceededVoltage", "Magenta").toString() ;

   colorNormal        = QColor(colorNormalName) ;       /* color for normal results */
   colorExPower       = QColor(colorExPowerName) ;      /* color for results with exceeded power */
   colorExVoltage     = QColor(colorExVoltageName) ;    /* color for normal exceeded voltage */

}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       saveSettings                                                                              │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Save initialization settings to registry or ini-file.                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void CompSynt::saveSettings()
{
QSettings settings ;

   QSettings::setDefaultFormat(QSettings::NativeFormat) ;

   settings.setValue(KEY_RES  + "Target",        ui->LE_R_Target->text()) ;
   settings.setValue(KEY_RES  + "MaxError",      ui->LE_R_MaxError->text()) ;
   settings.setValue(KEY_RES  + "Tolerance",     ui->LE_R_Tolerance->text()) ;
   settings.setValue(KEY_RES  + "Voltage",       ui->LE_R_Voltage->text()) ;
   settings.setValue(KEY_RES  + "PowerRating",   ui->LE_R_PowerRating->text()) ;
   settings.setValue(KEY_RES  + "MaxVoltage",    ui->LE_R_MaxVoltage->text()) ;

   settings.setValue(KEY_RES  + "E6",            ui->CB_R_E6->isChecked()) ;
   settings.setValue(KEY_RES  + "E12",           ui->CB_R_E12->isChecked()) ;
   settings.setValue(KEY_RES  + "E24",           ui->CB_R_E24->isChecked()) ;
   settings.setValue(KEY_RES  + "E48",           ui->CB_R_E48->isChecked()) ;
   settings.setValue(KEY_RES  + "E96",           ui->CB_R_E96->isChecked()) ;
   settings.setValue(KEY_RES  + "E192",          ui->CB_R_E192->isChecked()) ;

   settings.setValue(KEY_RES  + "NT_RS",         ui->CB_NT_RS->isChecked()) ;
   settings.setValue(KEY_RES  + "NT_RSS",        ui->CB_NT_RSS->isChecked()) ;
   settings.setValue(KEY_RES  + "NT_RPP",        ui->CB_NT_RPP->isChecked()) ;
   settings.setValue(KEY_RES  + "NT_RSSP",       ui->CB_NT_RSSP->isChecked()) ;
   settings.setValue(KEY_RES  + "NT_RSSS",       ui->CB_NT_RSSS->isChecked()) ;
   settings.setValue(KEY_RES  + "NT_RPPP",       ui->CB_NT_RPPP->isChecked()) ;
   settings.setValue(KEY_RES  + "NT_RSPP",       ui->CB_NT_RSPP->isChecked()) ;

   settings.setValue(KEY_RES  + "RB_R_IEC",      ui->RB_R_IEC->isChecked()) ;
   settings.setValue(KEY_RES  + "RB_R_Private",  ui->RB_R_Private->isChecked()) ;

   settings.setValue(KEY_WIN  + "geometry",             saveGeometry()) ;
   settings.setValue(KEY_WIN  + "windowState",          saveState()) ;

   settings.setValue(KEY_PROG + "PrintLines",           printline_count) ;
   settings.setValue(KEY_PROG + "DecimalPlaces",        decimal_places) ;
   settings.setValue(KEY_PROG + "PrivateFileFormat",    private_fileformat) ;
   settings.setValue(KEY_PROG + "OutputAlignment",      output_alignment) ;
   settings.setValue(KEY_PROG + "UseLocale",            useLocale) ;

   settings.setValue(KEY_RES  + "DecadeCount",          rdecades) ;
   settings.setValue(KEY_RES  + "MaxDeviation",         resdev) ;
   settings.setValue(KEY_CAP  + "DecadeCount",          cdecades) ;
   settings.setValue(KEY_RES  + "Log10RMin",            log10rmin) ;
   settings.setValue(KEY_CAP  + "Log10CMin",            log10cmin) ;
   settings.setValue(KEY_RES  + "DiscardOutOfRange",    discardOutOfRange) ;
   settings.setValue(KEY_RES  + "LastFile",             LastFile_R) ;

   settings.setValue(KEY_PROG + "ColorNormal",          colorNormalName) ;
   settings.setValue(KEY_PROG + "ColorExceededPower",   colorExPowerName) ;
   settings.setValue(KEY_PROG + "ColorExceededVoltage", colorExVoltageName) ;

}

