//+------------------------------------------------------------------+
//|                                             RiskOfRuinChart.mqh  |
//+------------------------------------------------------------------+
#ifndef RISKOFRUINCHART_MQH
#define RISKOFRUINCHART_MQH

#include <Canvas\Canvas.mqh>
#include "RiskTypes.mqh"

//+------------------------------------------------------------------+
//| CRiskOfRuinChart                                                 |
//| Renders the risk-of-ruin curve as a connected line, with a       |
//| vertical marker at the trader's current risk-per-trade setting,  |
//| using a CCanvas panel.                                           |
//+------------------------------------------------------------------+
class CRiskOfRuinChart
  {
private:
   CCanvas               m_canvas;
   string                m_object_name;
   string                m_font_name;
   int                   m_font_size;
   uint                  m_font_flags;

public:
                     CRiskOfRuinChart(void);
                    ~CRiskOfRuinChart(void);

   bool                  Draw(const CRiskOfRuinResult &curve[], int count,
                              double current_risk_percent, double current_ror_value,
                              int x, int y, int width, int height);
   void                  Clear(void);
  };

//+------------------------------------------------------------------+
//| Constructor: assigns a fixed object name for the canvas panel.   |
//| This dashboard only ever creates one ruin curve panel, so a      |
//| single constant name is sufficient; running the script twice in  |
//| the same session reuses that name, which Clear() is written to   |
//| handle safely regardless of which instance created the original  |
//| panel.                                                           |
//+------------------------------------------------------------------+
CRiskOfRuinChart::CRiskOfRuinChart(void)
  {
   m_object_name = "RiskOfRuinPanel";
   m_font_name   = "Arial";
   m_font_size   = 12;
   m_font_flags  = FW_BOLD;
  }

//+------------------------------------------------------------------+
//| Destructor: intentionally does not remove the canvas panel. The  |
//| panel is a chart object owned by the chart itself, and must      |
//| remain visible after the CRiskOfRuinChart instance that drew it  |
//| goes out of scope at the end of a script's OnStart.              |
//+------------------------------------------------------------------+
CRiskOfRuinChart::~CRiskOfRuinChart(void)
  {
  }

//+------------------------------------------------------------------+
//| Draw                                                             |
//| Plots the ruin probability curve as a connected line across the  |
//| risk-per-trade range, then overlays a vertical marker line at    |
//| current_risk_percent labeled with the caller's own already-      |
//| computed ruin probability for that exact percentage.             |
//+------------------------------------------------------------------+
bool CRiskOfRuinChart::Draw(const CRiskOfRuinResult &curve[], int count,
                            double current_risk_percent, double current_ror_value,
                            int x, int y, int width, int height)
  {
   Clear();
   if(!m_canvas.CreateBitmapLabel(m_object_name, x, y, width, height, COLOR_FORMAT_ARGB_NORMALIZE))
     {
      ::Print("RiskAnalyzer: CreateBitmapLabel failed, error ", ::GetLastError());
      return(false);
     }
   m_canvas.FontSet(m_font_name, m_font_size, m_font_flags);
   ::TextSetFont(m_font_name, m_font_size, m_font_flags);
   m_canvas.Erase(::ColorToARGB(clrWhiteSmoke, 255));
   if(count < 2)
     {
      m_canvas.Update();
      return(true);
     }
//--- the risk-per-trade range is taken directly from the curve's own bounds
   double risk_min = curve[0].risk_percent;
   double risk_max = curve[count - 1].risk_percent;
   double risk_range = risk_max - risk_min;
   if(risk_range <= 0.0)
      risk_range = 1.0;
//--- finds the ruin probability range, always anchored at zero for readability
   double ror_max = 0.0;
   for(int i = 0; i < count; i++)
      if(curve[i].ror > ror_max)
         ror_max = curve[i].ror;
   if(ror_max <= 0.0)
      ror_max = 1.0;
   int plot_left   = 50;
   int plot_right  = width - 10;
   int plot_top    = 30;
   int plot_bottom = height - 20;
//--- draws the ruin probability curve as a series of connected segments
   int prev_x = 0;
   int prev_y = 0;
   for(int i = 0; i < count; i++)
     {
      int px = plot_left + (int)(((curve[i].risk_percent - risk_min) / risk_range) * (plot_right - plot_left));
      int py = plot_bottom - (int)((curve[i].ror / ror_max) * (plot_bottom - plot_top));
      if(i > 0)
         m_canvas.Line(prev_x, prev_y, px, py, ::ColorToARGB(clrDarkSlateBlue, 255));
      prev_x = px;
      prev_y = py;
     }
//--- overlay a vertical marker at the exact current risk-per-trade setting.
//--- current_ror_value is the caller's own already-computed result for this
//--- exact percentage, not a lookup against the sampled curve, so the
//--- labeled figure is genuinely exact rather than an approximation from
//--- the nearest sampled point
   int marker_x = plot_left + (int)(((current_risk_percent - risk_min) / risk_range) * (plot_right - plot_left));
//--- clamp the marker inside the plotted area; a risk percentage outside
//--- the sampled range would otherwise draw off the edge of the panel
   if(marker_x < plot_left)
      marker_x = plot_left;
   if(marker_x > plot_right)
      marker_x = plot_right;
   m_canvas.LineVertical(marker_x, plot_top, plot_bottom, ::ColorToARGB(clrCrimson, 255));
   string marker_text = "Current: " + ::DoubleToString(current_risk_percent, 1) + "%  RoR " +
                        ::DoubleToString(current_ror_value * 100.0, 3) + "%";
   m_canvas.TextOut(marker_x + 6, plot_top, marker_text, ::ColorToARGB(clrCrimson, 255));
   m_canvas.Update();
   return(true);
  }

//+------------------------------------------------------------------+
//| Clear                                                            |
//| Removes any chart object with this name, whether or not this     |
//| specific instance was the one that created it. A freshly         |
//| constructed instance has no memory of a panel left behind by an  |
//| earlier run of the script under the same object name, so deletion|
//| is attempted unconditionally by name rather than gated on        |
//| instance-local state.                                            |
//+------------------------------------------------------------------+
void CRiskOfRuinChart::Clear(void)
  {
   ::ObjectDelete(0, m_object_name);
  }

#endif // RISKOFRUINCHART_MQH
//+------------------------------------------------------------------+