﻿//+------------------------------------------------------------------+
//|                                        ParameterConfigDialog.mqh |
//|                                  Copyright 2026, MetaQuotes Ltd. |
//|                          https://www.mql5.com/en/users/lynnchris |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "3.0"

#ifndef _PARAMETER_CONFIG_DIALOG_MQH
#define _PARAMETER_CONFIG_DIALOG_MQH

#include <Controls\Dialog.mqh>
#include <Controls\Edit.mqh>
#include <Controls\Button.mqh>
#include <Controls\Label.mqh>
#include "ParameterDefinitions.mqh"
#include "ChartLauncher.mqh"

//--- Forward declarations to break circular dependencies
class CSearchPanel;
class CParameterConfigDialog;
extern CParameterConfigDialog *g_paramDialog;

//+------------------------------------------------------------------+
//| Parameter configuration dialog – shows editable parameter fields |
//+------------------------------------------------------------------+
class CParameterConfigDialog : public CAppDialog
  {
private:
   //--- Layout constants (spacing and control sizes)
   enum { MARGIN=10, LABEL_WIDTH=120, CONTROL_WIDTH=150, CONTROL_HEIGHT=22, ROW_HEIGHT=28 };

   //--- Dynamic control arrays (one set per parameter)
   CLabel            m_labels[];       
   CEdit             m_editInt[];     
   CEdit             m_editDouble[];   
   CEdit             m_editEnum[];     

   SParameterDef     m_defs[];         
   int               m_paramCount;     

   ENUM_INDICATOR    m_indicatorType;  
   string            m_targetSymbol;   
   CSearchPanel      *m_parentPanel;    

   CButton           m_btnOK;          
   CButton           m_btnCancel;     

   void              BuildControls();          
   void              ReadValues(MqlParam &params[]);   
   bool              ValidateValues();         

public:
                     CParameterConfigDialog();
                    ~CParameterConfigDialog();

   bool              Create(const long chart, const string name, const ENUM_INDICATOR indicatorType);
   void              SetIndicatorInfo(const ENUM_INDICATOR type, const string symbol);
   void              SetParentPanel(CSearchPanel *parent) { m_parentPanel = parent; }
   void              DetachParent() { m_parentPanel = NULL; }
   void              CloseDialog();     

   virtual bool      OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   void              ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   bool              IsVisible() const { return CAppDialog::IsVisible(); }

   void              DestroyControls();  
  };

//+------------------------------------------------------------------+
//| Constructor / Destructor                                         |
//+------------------------------------------------------------------+
CParameterConfigDialog::CParameterConfigDialog() : m_paramCount(0), m_indicatorType(IND_CUSTOM), m_targetSymbol(""), m_parentPanel(NULL) {}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CParameterConfigDialog::~CParameterConfigDialog()
  {
//--- Re‑show the main panel if it still exists
   if(m_parentPanel != NULL)
      m_parentPanel.ShowPanel();
   g_paramDialog = NULL;
//--- Destroy all dynamically created controls
   DestroyControls();
   Destroy(0);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CParameterConfigDialog::DestroyControls()
  {
   for(int i=0; i<ArraySize(m_labels); i++)
      m_labels[i].Destroy(0);
   for(int i=0; i<ArraySize(m_editInt); i++)
      m_editInt[i].Destroy(0);
   for(int i=0; i<ArraySize(m_editDouble); i++)
      m_editDouble[i].Destroy(0);
   for(int i=0; i<ArraySize(m_editEnum); i++)
      m_editEnum[i].Destroy(0);
   m_btnOK.Destroy(0);
   m_btnCancel.Destroy(0);
//--- Clear the arrays
   ArrayResize(m_labels, 0);
   ArrayResize(m_editInt, 0);
   ArrayResize(m_editDouble, 0);
   ArrayResize(m_editEnum, 0);
  }

//+------------------------------------------------------------------+
//| Sets the indicator info to be used when attaching                |
//+------------------------------------------------------------------+
void CParameterConfigDialog::SetIndicatorInfo(const ENUM_INDICATOR type, const string symbol)
  {
   m_indicatorType = type;
   m_targetSymbol = symbol;
  }

//+------------------------------------------------------------------+
//| Closes the dialog – hides it without destroying                  |
//+------------------------------------------------------------------+
void CParameterConfigDialog::CloseDialog()
  {
//--- Re‑show the parent panel
   if(m_parentPanel != NULL)
      m_parentPanel.ShowPanel();
   g_paramDialog = NULL;
   Hide();   
  }

//+------------------------------------------------------------------+
//| Creates the dialog and builds its controls                       |
//+------------------------------------------------------------------+
bool CParameterConfigDialog::Create(const long chart, const string name, const ENUM_INDICATOR indicatorType)
  {
//--- Get parameter definitions for this indicator
   m_paramCount = CParameterDefinitions::GetDefinitions(indicatorType, m_defs);
   if(m_paramCount == 0)
      return(false);   //--- No parameters – no dialog needed

//--- Calculate dialog size based on the number of parameters
   int dialogHeight = MARGIN + ROW_HEIGHT * m_paramCount + 60;
   int dialogWidth = MARGIN + LABEL_WIDTH + CONTROL_WIDTH + MARGIN + MARGIN;

//--- Create the underlying dialog window
   if(!CAppDialog::Create(0, name, 0, 100, 100, 100 + dialogWidth, 100 + dialogHeight))
      return(false);

//--- Build the controls inside the dialog
   BuildControls();

//--- OK button
   int btnY = dialogHeight - 45;
   int btnX = (dialogWidth / 2) - 65;
   if(!m_btnOK.Create(0, "OKBtn", 0, btnX, btnY, btnX + 60, btnY + 25))
      return(false);
   if(!Add(m_btnOK))
      return(false);
   m_btnOK.Text("OK");

//--- Cancel button
   btnX = (dialogWidth / 2) + 5;
   if(!m_btnCancel.Create(0, "CancelBtn", 0, btnX, btnY, btnX + 60, btnY + 25))
      return(false);
   if(!Add(m_btnCancel))
      return(false);
   m_btnCancel.Text("Cancel");

   return(true);
  }

//+------------------------------------------------------------------+
//| Builds the parameter controls (labels + edit boxes)              |
//+------------------------------------------------------------------+
void CParameterConfigDialog::BuildControls()
  {
   if(m_paramCount == 0)
      return;

//--- Resize control arrays to match the number of parameters
   ArrayResize(m_labels, m_paramCount);
   ArrayResize(m_editInt, m_paramCount);
   ArrayResize(m_editDouble, m_paramCount);
   ArrayResize(m_editEnum, m_paramCount);

   int yPos = MARGIN + 10;

   for(int i = 0; i < m_paramCount; i++)
     {
      //--- Create a label for the parameter name
      if(!m_labels[i].Create(0, "lbl" + IntegerToString(i), 0, MARGIN, yPos, MARGIN + LABEL_WIDTH, yPos + CONTROL_HEIGHT))
         continue;
      if(!Add(m_labels[i]))
         continue;
      m_labels[i].Text(m_defs[i].name);

      //--- Create the appropriate edit control based on parameter type
      switch(m_defs[i].type)
        {
         case PARAM_INTEGER:
           {
            //--- Simple edit box for integer values
            if(!m_editInt[i].Create(0, "edt" + IntegerToString(i), 0, MARGIN + LABEL_WIDTH + 5, yPos,
                                    MARGIN + LABEL_WIDTH + 5 + CONTROL_WIDTH, yPos + CONTROL_HEIGHT))
               break;
            if(!Add(m_editInt[i]))
               break;
            m_editInt[i].Text(IntegerToString(m_defs[i].default_int));
            break;
           }
         case PARAM_DOUBLE:
           {
            //--- Edit box for double values
            if(!m_editDouble[i].Create(0, "edtd" + IntegerToString(i), 0, MARGIN + LABEL_WIDTH + 5, yPos,
                                       MARGIN + LABEL_WIDTH + 5 + CONTROL_WIDTH, yPos + CONTROL_HEIGHT))
               break;
            if(!Add(m_editDouble[i]))
               break;
            m_editDouble[i].Text(DoubleToString(m_defs[i].default_double, 2));
            break;
           }
         case PARAM_ENUM:
           {
            //--- Enum parameters use a simple edit box where the user types the value name
            //--- (We avoid combobox because of event handling differences across MT5 builds)
            if(!m_editEnum[i].Create(0, "ede" + IntegerToString(i), 0, MARGIN + LABEL_WIDTH + 5, yPos,
                                     MARGIN + LABEL_WIDTH + 5 + CONTROL_WIDTH, yPos + CONTROL_HEIGHT))
               break;
            if(!Add(m_editEnum[i]))
               break;
            //--- Set the default text from the enum definition
            string defaultText = "";
            for(int j = 0; j < ArraySize(m_defs[i].enum_values); j++)
              {
               if(m_defs[i].enum_codes[j] == m_defs[i].default_enum)
                 {
                  defaultText = m_defs[i].enum_values[j];
                  break;
                 }
              }
            m_editEnum[i].Text(defaultText);
            break;
           }
        }
      yPos += ROW_HEIGHT;
     }
  }

//+------------------------------------------------------------------+
//| Reads the values from the controls into a MqlParam array         |
//+------------------------------------------------------------------+
void CParameterConfigDialog::ReadValues(MqlParam &params[])
  {
   ArrayResize(params, m_paramCount);
   for(int i = 0; i < m_paramCount; i++)
     {
      switch(m_defs[i].type)
        {
         case PARAM_INTEGER:
            params[i].type = TYPE_INT;
            params[i].integer_value = (int)StringToInteger(m_editInt[i].Text());
            break;
         case PARAM_DOUBLE:
            params[i].type = TYPE_DOUBLE;
            params[i].double_value = StringToDouble(m_editDouble[i].Text());
            break;
         case PARAM_ENUM:
           {
            //--- Match the typed text to one of the enum values
            string text = m_editEnum[i].Text();
            int foundCode = m_defs[i].default_enum;
            for(int j = 0; j < ArraySize(m_defs[i].enum_values); j++)
              {
               if(StringCompare(m_defs[i].enum_values[j], text, false) == 0)
                 {
                  foundCode = m_defs[i].enum_codes[j];
                  break;
                 }
              }
            params[i].type = TYPE_INT;
            params[i].integer_value = foundCode;
            break;
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Validates integer values (range check)                           |
//+------------------------------------------------------------------+
bool CParameterConfigDialog::ValidateValues()
  {
   for(int i = 0; i < m_paramCount; i++)
     {
      switch(m_defs[i].type)
        {
         case PARAM_INTEGER:
           {
            int val = (int)StringToInteger(m_editInt[i].Text());
            if(val < m_defs[i].min_value || val > m_defs[i].max_value)
              {
               Print("Invalid value for ", m_defs[i].name, ": ", val);
               return(false);
              }
            break;
           }
         default:
            break;
        }
     }
   return(true);
  }

//+------------------------------------------------------------------+
//| Event handler – catches OK and Cancel clicks                     |
//+------------------------------------------------------------------+
bool CParameterConfigDialog::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   bool handled = CAppDialog::OnEvent(id, lparam, dparam, sparam);

   if(id == CHARTEVENT_CUSTOM)
     {
      if(sparam == "OKBtn")
        {
         MqlParam params[];
         ReadValues(params);
         if(ValidateValues())
           {
            AttachIndicator(m_indicatorType, m_targetSymbol, params);
           }
         CloseDialog();
         return(true);
        }
      else
         if(sparam == "CancelBtn")
           {
            CloseDialog();
            return(true);
           }
     }

   return(handled);
  }

//+------------------------------------------------------------------+
//| Chart event forwarder                                            |
//+------------------------------------------------------------------+
void CParameterConfigDialog::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   CAppDialog::ChartEvent(id, lparam, dparam, sparam);
  }

#endif // _PARAMETER_CONFIG_DIALOG_MQH
//+------------------------------------------------------------------+
