/*
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                                                 ┃
┃            Class Name: CompSynt.h                                                               ┃
┃                Author: Michael Krämer                                                           ┃
┃                 Email: Michael@dk8pp.de                                                         ┃
┃                  Date: 27.11.2024 13:25:54                                                      ┃
┃                  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/>.                             ┃
┃                                                                                                 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
*/
#ifndef COMPSYNT_H
#define COMPSYNT_H

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Includes                                                                                  │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
#include <QMainWindow>
#include <QCheckBox>
#include <QThread>
#include <QtConcurrentRun>
#include <QFuture>
#include <QLineEdit>
#include <QDateTime>
#include <QStringList>
#include <QFileDialog>
#include <QFileInfo>
#include <QSettings>
#include <QChar>
#include <QRegularExpression>
#include <QTextBlockFormat>
#include <QTextCharFormat>
#include <QTextEdit>
//#include <cmath>
//#include <complex>
#include <algorithm>
#include "infodialog.h"
#include "configdialog.h"
#include <cfloat>

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Defines                                                                                   │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
#ifdef DECLARE_VARS
  #define _EXTERN_
#else
  #define _EXTERN_ extern
#endif

/* definitions for registry */
#define OrganizationName QString("DK8PP Freeware")
#define ApplicationName QString("CompSynt")
#define KEY_PROG QString("Program/")
#define KEY_RES QString("Resistor/")
#define KEY_CAP QString("Capacitor/")
#define KEY_WIN QString("Window/")

/* program information */
#define PURPOSE "Purpose: Synthesize specific component from a set of standard components\n\n"
#define PROGRAMVERSION 21               /* will be displayed as n.nn */
#define AUTHOR "Michael Krämer, DK8PP"
#define COPYRIGHT " Copyright © 2024-2026 "
#define COPYRIGHTDETAILS "\nThis program comes with ABSOLUTELY NO WARRANTY;\n" \
                         "This is free software, and you are welcome to redistribute it under certain conditions.\n" \
                         "Press the LGPL button for details.\n\n"
#define VERSION_STRING (" - Version " + QString::number(PROGRAMVERSION/100) + "." + QString::number(PROGRAMVERSION%100).rightJustified(2,'0'))
#define COMPILE_DT (QString("compiled on ") + __DATE__ + ", " + __TIME__)

#define STATUSBAR_TIMEOUT_MS 0 /* timeout for statusbar messages in milliseconds */

#define PROGRAM_INFO \
           ApplicationName + VERSION_STRING + ", " + COMPILE_DT + "\n\n" + \
           PURPOSE + ApplicationName + COPYRIGHT + AUTHOR + COPYRIGHTDETAILS + \
           "for updates check: http://freeware.dk8pp.de/ or email to: Michael@dk8pp.de"

#define COMP_COUNT 3 /* maximum number of components within one network */

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       structs and enums                                                                         │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/

typedef enum {TOPO_S, TOPO_SS, TOPO_PP, TOPO_PPP, TOPO_SPP, TOPO_SSS, TOPO_SSP, TOPO_SSS1, TOPO_SSS2, TOPO_PPS, TOPO_NOCONF} TOPO ;
/* TOPO is the topology of the network.
   TOPO_S:    1 single R/C
   TOPO_SS:   2 serial R/C
   TOPO_PP:   2 parallel R/C
   TOPO_PPP:  3 parallel R/C
   TOPO_SPP:  1 serial R/C, 2 parallel R/C
   TOPO_SSS:  3 serial R/C
   TOPO_SSP:  2 serial R/C, 1 parallel R/C

the following definitions are for resistor networks only
   TOPO_SSS1: 3 serial R, tap between first two resistors
   TOPO_SSS2: 3 serial R, tap between last two resistors
   TOPO_PPS:  2 parallel R, 1 serial R               */

typedef enum {R=0, C, RN, COMPSIZE, NONE} COMP ;
typedef enum {ohm=0, farad, volt} UNIT ;
typedef enum {FMT_UNITS=0, FMT_FLOAT, FMT_EXP, FMT_NONE} FILE_FORMAT ; /* format for private file */
typedef enum {SET_IEC=0, SET_PRIVATE, SET_NONE} SET ;

/* component */
typedef struct comp
               {double value ;                  /* value of component */
                double max_power ;              /* max power dissipation */
                double max_voltage ;            /* maximum voltage */
                double tolerance ;              /* tolerance */
               } COMPONENT ;

#define DEFAULT_COMPONENT {0.0, 0.0, 0.0, 0.0}

/* IEC table, just the component values without limits */
typedef std::vector<double> IEC_TABLE ;

/* component table including limits */
typedef std::vector<COMPONENT> COMP_TABLE ;

/* one element of linked list of solutions */
typedef struct sol
               {struct sol *prev ;              /* pointer to previous solution */
                struct sol *next ;              /* pointer to next solution */
                double target ;                 /* target value */
                double actual ;                 /* actual value */
                double error ;                  /* error */
                double max_error ;              /* maximum error */
                bool discard_oor ;              /* discard solution if voltage or power is out of range */
                COMPONENT comp[COMP_COUNT] ;    /* selected components */
                double voltage[COMP_COUNT] ;    /* voltage across a component (or 0 if unused) */
                double power[COMP_COUNT] ;      /* power dissipation of a component (or 0 if unused) */
                COMPONENT supplement ;          /* supplement component */
                TOPO topology ;                 /* network topology */
               } SOLUTION ;

/* specified parameters for component search */
typedef struct parms
               {double value ;                  /* target value */
                double max_error ;              /* maximum error */
                double applied_voltage ;        /* applied voltage across the network */
                double tolerance ;              /* tolerance of individual component */
                double max_power ;              /* power rating of individual resistor */
                double max_voltage ;            /* maximum permitted voltage across a resistor */
               } PARMS ;

/* conversion result */
typedef struct conversion
               {QString str ;                   /* string to be decoded and returned */
                QString deflt ;                 /* default if input empty */
                double value ;                  /* result value if no error */
                bool required ;                 /* required field, return error if empty */
                bool positive ;                 /* value must be positive */
                bool empty ;                    /* true if input string is empty */
                bool relative ;                 /* true if relative value was specified, e.g. % */
                bool error ;                    /* true on conversion error or missing required input */
               } CONVERSION ;

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       global variables                                                                          │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
_EXTERN_ int32_t resdev ;     /* maximum deviation of resistors */

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Function prototypes                                                                       │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
QT_BEGIN_NAMESPACE
namespace Ui { class CompSynt; }
QT_END_NAMESPACE

class CompSynt : public QMainWindow
{
   Q_OBJECT

public:
   CompSynt(QWidget *parent = nullptr);
   ~CompSynt();
   uint32_t printline_count = 100 ;                     /* number of output lines */
   uint32_t decimal_places = 2 ;                        /* number of decimal places for output window */
   uint32_t output_alignment = Qt::AlignRight ;         /* alignment of output */
   bool discardOutOfRange = false ;                     /* discard solution if voltage or power is out of range */
   uint32_t rdecades = 8 ;                              /* number of decades for resistors */
   uint32_t cdecades = 10 ;                             /* number of decades for capacitors */
   int32_t log10rmin = -3 ;                             /* log10 of smallest resistance to consider */
   int32_t log10cmin = -14 ;                            /* log10 of smallest capacitance to consider */
   uint32_t private_fileformat = FMT_UNITS ;            /* format for private file */
   bool useLocale = true ;                              /* use locale */
   QString colorNormalName = "Blue" ;                   /* color for normal results */
   QString colorExPowerName = "Red" ;                   /* color for results with exceeded power */
   QString colorExVoltageName = "Magenta" ;             /* color for normal exceeded voltage */
   QColor colorNormal = QColorConstants::Blue ;         /* color for normal results */
   QColor colorExPower = QColorConstants::Red ;         /* color for results with exceeded power */
   QColor colorExVoltage = QColorConstants::Magenta ;   /* color for normal exceeded voltage */
   bool decode_double(QLineEdit *le, CONVERSION *res) ;

private slots:
   void PUB_Start_clicked() ;
   void PUB_SuggestSupplement_clicked() ;
   void SetMainStatus(const QString &msg) ;
   void RB_R_Private_clicked() ;
   void RB_R_IEC_clicked() ;
   void QA_About_clicked() ;
   void QA_Exit_clicked() ;
   void QA_Import_clicked() ;
   void QA_Export_clicked() ;
   void QA_Config_clicked() ;

private:
   Ui::CompSynt *ui ;
   QString ProgramInfo = PROGRAM_INFO ;
   static SOLUTION *topo_rs(  COMP_TABLE *ct, PARMS *parameters) ;
   static SOLUTION *topo_rss( COMP_TABLE *ct, PARMS *parameters) ;
   static SOLUTION *topo_rpp( COMP_TABLE *ct, PARMS *parameters) ;
   static SOLUTION *topo_rssp(COMP_TABLE *ct, PARMS *parameters) ;
   static SOLUTION *topo_rsss(COMP_TABLE *ct, PARMS *parameters) ;
   static SOLUTION *topo_rppp(COMP_TABLE *ct, PARMS *parameters) ;
   static SOLUTION *topo_rspp(COMP_TABLE *ct, PARMS *parameters) ;
   static bool ct_sort(double a, double b) ;
   static int sol_sort(const void *a, const void *b) ;
   static bool ct_sortprivate(COMPONENT a, COMPONENT b) ;
   static SOLUTION *sol_init(SOLUTION *sol, PARMS *parameters, TOPO topology) ;
   static SOLUTION *sol_copy(SOLUTION *sol_dest, SOLUTION *sol_src) ;
   static SOLUTION *enqueue(SOLUTION *sol_chain, SOLUTION *sol_tmp) ;
   static COMP_TABLE *search_single(COMP_TABLE *ct_src,
                                    COMP_TABLE *ct_dest,
                                    double min, double max) ;
   static COMP_TABLE *search_serial(COMP_TABLE *ct_src,
                                    COMP_TABLE *ct_dest,
                                    double min, double max,
                                    double start) ;
   static COMP_TABLE *search_parallel(COMP_TABLE *ct_src,
                                      COMP_TABLE *ct_dest,
                                      double min, double max,
                                      double start) ;
   void create_cct(void) ;
   void loadSettings() ;
   void saveSettings() ;
   COMP_TABLE iec_table ;       /* ??? */
   COMP_TABLE active_table ;
   COMP_TABLE private_table ;
   IEC_TABLE *ct_append(IEC_TABLE *ct_dest, IEC_TABLE *ct_src) ;
   COMP_TABLE *generate_ActiveTable(COMP_TABLE *ct_dest,
                             COMP_TABLE *ct_src,
                             COMPONENT *supplement) ;
   COMP_TABLE *make_IECMasterTable(COMP_TABLE *ct_dest,
                                int32_t min_val,
                                uint32_t decade_cnt,
                                PARMS *parameter) ;
   CONVERSION *get_double(CONVERSION *conv) ;
   bool getParms(PARMS *parameter) ;
   QString pval(double val) ;
   bool PrintSolution(QTextEdit *te, SOLUTION *sol) ;
   void Prepare_OutputWindow(QTextEdit *win) ;
   bool Import_PrivateFile(QString filename) ;
   void activate(int set) ;
   SOLUTION *Sort_Solutions(SOLUTION *solutions) ;
   SOLUTION *FindSolutions(COMP_TABLE *ct, PARMS *parameter) ;
   SOLUTION *Clear_Solutions(SOLUTION *solutions) ;
   SOLUTION *solutions = NULL ;
   SOLUTION *append_solutions(SOLUTION *chain1, SOLUTION *chain2) ;
   QString LastFile_R = "" ;                            /* last file */
};

#endif // COMPSYNT_H
