//+------------------------------------------------------------------+
//|                                                 SpecialChart.mqh |
//|                        Copyright 2012, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"

#include <Canvas\Canvas.mqh>
#include <Arrays\ArrayDouble.mqh>
//+------------------------------------------------------------------+
//| A special class for drawing multiple balance graphs              |
//+------------------------------------------------------------------+
class CSpecialChart: public CCanvas
  {
private:
   color             m_bkgroundcolor;  // Background color
   color             m_framecolor;     // Frame color
   color             m_linecolor;      // Line color
   int               m_framewidth;     // Frame width in pixels
   int               m_linewidth;      // Line width in pixels
   int               m_lines;          // The number of lines on the chart
   CArrayDouble      m_seria[];        // Arrays to store the chart values
   bool              m_profitseria[];  // If the series is profitable or not
   int               m_lastseria_index;// The index of a new line on the chart
   color             m_profit;         // The color of the profitable series
   color             m_loss;           // The color of the losing series
public:
   //--- Constructor/destructor
                     CSpecialChart():m_lastseria_index(0),m_profit(clrGreen),m_loss(clrRed){};
                    ~CSpecialChart() { CCanvas::Destroy(); }
   //--- The color of the background, frame and line
   void              SetBackground(const color clr){ m_bkgroundcolor=clr;      };
   void              SetFrameColor(const color clr){ m_framecolor=clr;         };
   void              SetLineColor(const color clr) { m_linecolor=clr;          };
   //--- The width of the frame and line
   void              SetFrameWidth(const int w)    { m_framewidth=w;           };
   void              SetLineWidth(const int w)     { m_linewidth=w;            };
   //--- Setting the number of lines on the chart
   void              SetLines(const int l) { m_lines=l;ArrayResize(m_seria,l); ArrayResize(m_profitseria,l);};
   //--- updating an object on a screen
   void              Update();
   //--- Adding data from the array
   void              AddSeria(const double  &array[],bool profit);
   //--- Draws the chart 
   void              Draw(const int seria_index,color clr);
   //---             transforms the representation of color from the 'color' type to the 'uint' type
   uint              uCLR(const color clr) { return(XRGB((clr)&0x0FF,(clr)>>8,(clr)>>16));};
   //--- Draws a line in the common terms
   void              Line(int x1,int y1,int x2,int y2,uint col);
   //--- Getting the max and min value in the series 
   double            MaxValue(const int seria_index);
   double            MinValue(const int seria_index);
  };
//+------------------------------------------------------------------+
//|  Chart Update                                                    |
//+------------------------------------------------------------------+
void CSpecialChart::Update(void)
  {
//--- Fill the background
   CCanvas::Erase(CSpecialChart::uCLR(m_bkgroundcolor));
//--- Draw the frame
   CCanvas::FillRectangle(m_framewidth,m_framewidth,
                          m_width-m_framewidth-1,
                          m_height-m_framewidth-1,
                          CSpecialChart::uCLR(m_framecolor));

//--- Draw each series on the 80% of available area vertically and horizontally
   for(int i=0;i<m_lines;i++)
     {
      color clr=m_loss;
      if(m_profitseria[i]) clr=m_profit;
      Draw(i,clr);
      //Print(__FUNCSIG__," - Drawing: ",i);
     }
//--- Update the chart
   CCanvas::Update();
  }
//+------------------------------------------------------------------+
//|  Add a new data series to draw on the chart                      |
//+------------------------------------------------------------------+
void CSpecialChart::AddSeria(const double &array[],bool profit)
  {
//PrintFormat("Add an array tu the series No. %d",m_lastseria_index);
   m_seria[m_lastseria_index].Resize(0);
   m_seria[m_lastseria_index].AddArray(array);
   m_profitseria[m_lastseria_index]=profit;
//--- Keep track of the index of the last line (currently not used)  
   m_lastseria_index++;
   if(m_lastseria_index>=m_lines) m_lastseria_index=0;
  }
//+------------------------------------------------------------------+
//|  Get the maximum value                                           |
//+------------------------------------------------------------------+
double CSpecialChart::MaxValue(const int seria_index)
  {
   double res=m_seria[seria_index].At(0);
   int total=m_seria[seria_index].Total();
//--- Go through and compare
   for(int i=1;i<total;i++)
     {
      if(m_seria[seria_index].At(i)>res) res=m_seria[seria_index].At(i);
     }
//--- Result
   return res;
  }
//+------------------------------------------------------------------+
//|  Get the minimum value                                           |
//+------------------------------------------------------------------+
double CSpecialChart::MinValue(const int seria_index)
  {
   double res=m_seria[seria_index].At(0);;
   int total=m_seria[seria_index].Total();
//--- Go through and compare  
   for(int i=1;i<total;i++)
     {
      if(m_seria[seria_index].At(i)<res) res=m_seria[seria_index].At(i);
     }
//--- Result
   return res;
  }
//+------------------------------------------------------------------+
//| Overloading the basic drawing function                           |
//+------------------------------------------------------------------+
void CSpecialChart::Line(int x1,int y1,int x2,int y2,uint col)
  {
//--- As the Y-axis is turned upside down, we need to prepare y1 and y2
   int y1_adj=m_height-y1;
   int y2_adj=m_height-y2;
//--- instead of the natural color, pass the color in the CSimpleCanvas format
   CCanvas::Line(x1,y1_adj,x2,y2_adj,CSpecialChart::uCLR(col));
//---
  }
//+------------------------------------------------------------------+
//|  Drwaing all lines on the chart                                  |
//+------------------------------------------------------------------+
void CSpecialChart::Draw(const int seria_index,color clr)
  {
//--- Prepare coefficients to convert the values ??to pixels
   double min=MaxValue(seria_index);
   double max=MinValue(seria_index);
   double size=m_seria[seria_index].Total();
//--- Indents from the chart edge
   double x_indent=m_width*0.1;
   double y_indent=m_height*0.1;
//--- Calculate the coefficients
   double k_y=(max-min)/(m_height-2*m_framewidth-2*y_indent);
   double k_x=(size)/(m_width-2*m_framewidth-2*x_indent);
//--- Constant
   double start_x=x_indent;
   double start_y=m_height-y_indent;
//--- Now draw a broken line passing through all points of the series
   for(int i=1;i<size;i++)
     {
      //--- Convert the values into pixels
      int x1=(int)((i-0)/k_x+start_x);  // Measure the value of the number along the horizontal axis
      int y1=(int)(start_y-(m_seria[seria_index].At(i)-min)/k_y);    // along the vertical axis
      int x2=(int)((i-1-0)/k_x+start_x);// Measure the value of the number along the horizontal axis
      int y2=(int)(start_y-(m_seria[seria_index].At(i-1)-min)/k_y);  // along the vertical axis
      //--- Draw a line from the previous point to the current one
      Line(x1,y1,x2,y2,clr);
     }
//--- Draw and update
   CCanvas::Update();
  }
//+------------------------------------------------------------------+
