//+------------------------------------------------------------------+
//|                                  Fractal Support Resistance.mq4  |
//|                                  Copyright 2020, Alexander Elgin |
//|                                              alexmost113@mail.ru |
//+------------------------------------------------------------------+
// modified by banzai
// BT variant: on/off chart button (code from CentreOfGravityV2_BT.mq4)
#property copyright "Alexander Elgin"
#property link      "alexmost113@mail.ru"
#property indicator_chart_window
#property indicator_buffers 0

#define PERIODS_NUMBER 5
#define INDICATOR_NAME "Fractal Support Resistance"
#define SUPPORT "Support"
#define RESISTANCE "Resistance"
#define BAR_TO_START_SCAN_FROM 2

extern string              note1                = "------------------------------";
extern color               H1Color              = clrGreen;
extern color               H4Color              = clrDodgerBlue;
extern color               D1Color              = clrDarkOrange;
extern color               W1Color              = clrRed;
extern color               MN1Color             = clrPurple;
extern string              note2                = "------------------------------";
extern ENUM_LINE_STYLE     H1LineStyle          = STYLE_DOT;
extern ENUM_LINE_STYLE     H4LineStyle          = STYLE_DOT;
extern ENUM_LINE_STYLE     D1LineStyle          = STYLE_SOLID;
extern ENUM_LINE_STYLE     W1LineStyle          = STYLE_SOLID;
extern ENUM_LINE_STYLE     MN1LineStyle         = STYLE_SOLID;
extern string              note3                = "------------------------------";
extern int                 H1LineWidth          = 1;
extern int                 H4LineWidth          = 1;
extern int                 D1LineWidth          = 1;
extern int                 W1LineWidth          = 1;
extern int                 MN1LineWidth         = 1;
extern string              note4                = "------------------------------";
extern bool                DisplayTextLabel     = true;
extern int                 LabelFontSize        = 10;
extern string              LabelFont            = "Arial";
extern int                 ShiftLabel           = 10;//Label Shift +move right -move left
/*
extern string             note5                 = "------------------------------";
extern string             Resistance3LabelFont     = "Arial";
extern int                Resistance3LabelFontSize = 8;
extern color              Resistance3Color      = clrLime;
extern color              Resistance3Label      = clrLime;
extern ENUM_LINE_STYLE    Resistance3Style      = STYLE_DASH;
extern int                Resistance3Width      = 1;
extern string             note6                 = "------------------------------";
extern string             Resistance2LabelFont     = "Arial";
extern int                Resistance2LabelFontSize = 8;
extern color              Resistance2Color      = clrGreen;
extern color              Resistance2Label      = clrGreen;
extern ENUM_LINE_STYLE    Resistance2Style      = STYLE_DASH;
extern int                Resistance2Width      = 1;
extern string             note7                 = "------------------------------";
extern string             Resistance1LabelFont     = "Arial";
extern int                Resistance1LabelFontSize = 8;
extern color              Resistance1Color      = clrDarkGreen;
extern color              Resistance1Label      = clrDarkGreen;
extern ENUM_LINE_STYLE    Resistance1Style      = STYLE_DASH;
extern int                Resistance1Width      = 1;
extern string             note8                 = "------------------------------";
extern string             PivotLabelFont           = "Arial Black";
extern int                PivotLabelFontSize       = 10;
extern color              PivotColor            = clrBlue;
extern color              PivotLabel            = clrBlue;
extern ENUM_LINE_STYLE    PivotStyle            = STYLE_SOLID;
extern int                PivotWidth            = 1;
extern string             note9                 = "------------------------------";
extern string             Support1LabelFont        = "Arial";
extern int                Support1LabelFontSize    = 8;
extern color              Support1Color         = clrMaroon;
extern color              Support1Label         = clrMaroon;
extern ENUM_LINE_STYLE    Support1Style         = STYLE_DASH;
extern int                Support1Width         = 1;
extern string             note10                 = "------------------------------";
extern string             Support2LabelFont        = "Arial";
extern int                Support2LabelFontSize    = 8;
extern color              Support2Color         = clrCrimson;
extern color              Support2Label         = clrCrimson;
extern ENUM_LINE_STYLE    Support2Style         = STYLE_DASH;
extern int                Support2Width         = 1;
extern string             note11                 = "------------------------------";
extern string             Support3LabelFont        = "Arial";
extern int                Support3LabelFontSize    = 8;
extern color              Support3Color         = clrRed;
extern color              Support3Label         = clrRed;
extern ENUM_LINE_STYLE    Support3Style         = STYLE_DASH;
extern int                Support3Width         = 1;
//+------------------------------------------------------------------------------------------------------------------+
*/
//+------------------------------------------------------------------------------------------------------------------+
//Forex-Station button template start41; copy and paste
extern string             button_note1          = "------------------------------"; // ------------------------------
extern int                btn_Subwindow         = 0;                                // What window to put the button on.  If <0, the button will use the same sub-window as the indicator.
extern ENUM_BASE_CORNER   btn_corner            = CORNER_LEFT_UPPER;                // button corner on chart for anchoring
extern string             btn_text              = "FSR";                            // a button name
extern string             btn_Font              = "Arial";                          // button font name
extern int                btn_FontSize          = 9;                                // button font size               
extern color              btn_text_ON_color     = clrLime;                          // ON color when the button is turned on
extern color              btn_text_OFF_color    = clrRed;                           // OFF color when the button is turned off
extern color              btn_background_color  = clrDimGray;                       // background color of the button
extern color              btn_border_color      = clrBlack;                         // border color the button
extern int                button_x              = 20;                               // x coordinate of the button     
extern int                button_y              = 80;                               // y coordinate of the button     
extern int                btn_Width             = 80;                               // button width
extern int                btn_Height            = 20;                               // button height
extern string             UniqueButtonID        = "FractalSR";                      // Unique ID for each button        
extern string             button_note2          = "------------------------------"; // ------------------------------
bool show_data, recalc=false;
string IndicatorObjPrefix, buttonId;
//"",btn_Subwindow,btn_corner,btn_text,btn_Font,btn_FontSize,btn_text_ON_color,btn_text_OFF_color,btn_background_color,btn_border_color,button_x,button_y,btn_Width,btn_Height,UniqueButtonID,"",
//Forex-Station button template end41; copy and paste

int timeframes[PERIODS_NUMBER] = {PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1};

int   styles[5];
color colors[5];
int   widths[5];

//+------------------------------------------------------------------------------------------------------------------+
//Forex-Station button template start42; copy and paste
int OnInit()
{
   IndicatorDigits(Digits);
   IndicatorObjPrefix = "__" + btn_text + "__";
      
   // The leading "_" gives buttonId a *unique* prefix.  Furthermore, prepending the swin is usually unique unless >2+ of THIS indy are displayed in the SAME sub-window. (But, if >2 used, be sure to shift the buttonId position)
   buttonId = "_" + UniqueButtonID + IndicatorObjPrefix + "_BT_";
   if (ObjectFind(buttonId)<0) 
      createButton(buttonId, btn_text, btn_Width, btn_Height, btn_Font, btn_FontSize, btn_background_color, btn_border_color, btn_text_ON_color);
   ObjectSetInteger(0, buttonId, OBJPROP_YDISTANCE, button_y);
   ObjectSetInteger(0, buttonId, OBJPROP_XDISTANCE, button_x);  

   init2();
   show_data = ObjectGetInteger(0, buttonId, OBJPROP_STATE);
  
   if (show_data) ObjectSetInteger(0,buttonId,OBJPROP_COLOR,btn_text_ON_color); 
   else ObjectSetInteger(0,buttonId,OBJPROP_COLOR,btn_text_OFF_color);
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------------------------------------------------------+
void createButton(string buttonID,string buttonText,int width2,int height,string font,int fontSize,color bgColor,color borderColor,color txtColor)
{
      ObjectDelete    (0,buttonID);
      ObjectCreate    (0,buttonID,OBJ_BUTTON,btn_Subwindow,0,0);
      ObjectSetInteger(0,buttonID,OBJPROP_COLOR,txtColor);
      ObjectSetInteger(0,buttonID,OBJPROP_BGCOLOR,bgColor);
      ObjectSetInteger(0,buttonID,OBJPROP_BORDER_COLOR,borderColor);
      ObjectSetInteger(0,buttonID,OBJPROP_BORDER_TYPE,BORDER_RAISED);
      ObjectSetInteger(0,buttonID,OBJPROP_XSIZE,width2);
      ObjectSetInteger(0,buttonID,OBJPROP_YSIZE,height);
      ObjectSetString (0,buttonID,OBJPROP_FONT,font);
      ObjectSetString (0,buttonID,OBJPROP_TEXT,buttonText);
      ObjectSetInteger(0,buttonID,OBJPROP_FONTSIZE,fontSize);
      ObjectSetInteger(0,buttonID,OBJPROP_SELECTABLE,0);
      ObjectSetInteger(0,buttonID,OBJPROP_CORNER,btn_corner);
      ObjectSetInteger(0,buttonID,OBJPROP_HIDDEN,1);
      ObjectSetInteger(0,buttonID,OBJPROP_XDISTANCE,9999);
      ObjectSetInteger(0,buttonID,OBJPROP_YDISTANCE,9999);
      // Upon creation, set the initial state to "true" which is "on", so one will see the indicator by default
      ObjectSetInteger(0, buttonId, OBJPROP_STATE, true);
}
//+------------------------------------------------------------------------------------------------------------------+
void OnDeinit(const int reason) 
{
   // If just changing a TF', the button need not be deleted, therefore the 'OBJPROP_STATE' is also preserved.
   if(reason != REASON_CHARTCHANGE) ObjectDelete(buttonId);
   deinit2(); 
}
//+------------------------------------------------------------------------------------------------------------------+
void OnChartEvent(const int id, //don't change anything here
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   // If another indy on the same chart has enabled events for create/delete/mouse-move, just skip this events up front because they aren't
   //    needed, AND in the worst case, this indy might cause MT4 to hang!!  Skipping the events seems to help, along with other (major) changes to the code below.
   if(id==CHARTEVENT_OBJECT_CREATE || id==CHARTEVENT_OBJECT_DELETE) return; // This appears to make this indy compatible with other programs that enabled CHART_EVENT_OBJECT_CREATE and/or CHART_EVENT_OBJECT_DELETE
   if(id==CHARTEVENT_MOUSE_MOVE    || id==CHARTEVENT_MOUSE_WHEEL)   return; // If this, or another program, enabled mouse-events, these are not needed below, so skip it unless actually needed. 

   if (id==CHARTEVENT_OBJECT_CLICK && sparam == buttonId)
   {
      show_data = ObjectGetInteger(0, buttonId, OBJPROP_STATE);
      
      if (show_data)
      {
         ObjectSetInteger(0,buttonId,OBJPROP_COLOR,btn_text_ON_color); 
         // Is it a problem to call 'start()' ??  Possibly it makes no difference, but now calling "mystart()" instead of "start()"; and "start()" simply runs "mystart()", so should be same as before.
         recalc=true;
         for (int ForexStation=0; ForexStation<indicator_buffers; ForexStation++)
              SetIndexStyle(ForexStation,DRAW_LINE);
         mystart();
      }
      else
      {
         ObjectSetInteger(0,buttonId,OBJPROP_COLOR,btn_text_OFF_color);
         for (int Forex=0; Forex<indicator_buffers; Forex++)
              SetIndexStyle(Forex,DRAW_NONE);
         deinit2();  
      }
   }
}
//Forex-Station button template end42; copy and paste
//+------------------------------------------------------------------------------------------------------------------+
int init2()
{
   IndicatorShortName(INDICATOR_NAME);
   DeleteSRObjects();

   colors[0] = H1Color;
   colors[1] = H4Color;
   colors[2] = D1Color;
   colors[3] = W1Color;
   colors[4] = MN1Color;

   styles[0] = H1LineStyle;
   styles[1] = H4LineStyle;
   styles[2] = D1LineStyle;
   styles[3] = W1LineStyle;
   styles[4] = MN1LineStyle;

   widths[0] = H1LineWidth;
   widths[1] = H4LineWidth;
   widths[2] = D1LineWidth;
   widths[3] = W1LineWidth;
   widths[4] = MN1LineWidth;

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------------------------------------------------------+
int deinit2()
{
   DeleteSRObjects();
   return(0);
}

//+------------------------------------------------------------------------------------------------------------------+
int start() {return(mystart()); }
//+------------------------------------------------------------------------------------------------------------------+
int mystart()
{
   int counted_bars=IndicatorCounted();
   if (show_data)
   {
      if(recalc) 
      {
         // If a button goes from off-to-on, everything must be recalculated.  The 'recalc' variable is used as a trigger to do this.
         counted_bars = 0;
         recalc=false;
      }
      for(int timeframe_index = 0; timeframe_index < ArraySize(timeframes); timeframe_index++) {
         if(Period() <= timeframes[timeframe_index]) {
            drawResistance(getUpperFractalBar(timeframes[timeframe_index], BAR_TO_START_SCAN_FROM), timeframe_index);
            drawSupport(getLowerFractalBar(timeframes[timeframe_index], BAR_TO_START_SCAN_FROM), timeframe_index);
         }
      }
   }
   return(0);
}
//+------------------------------------------------------------------------------------------------------------------+
void DeleteSRObjects()
{
   string object_types[2] = {SUPPORT, RESISTANCE};

   for(int timeframe_index = 0; timeframe_index < ArraySize(timeframes); timeframe_index++)
      for(int object_type_index = 0; object_type_index < ArraySize(object_types); object_type_index++)
      {
         ObjectDelete(getTrendLineName(object_types[object_type_index], timeframes[timeframe_index]));
         ObjectDelete("banzai" + getTrendLineName(object_types[object_type_index], timeframes[timeframe_index]));
      }
}
//+------------------------------------------------------------------------------------------------------------------+
void drawResistance(int bar_index, int timeframe_index) {
	if(bar_index > 0) drawTrendLine(getTrendLineName(RESISTANCE, timeframes[timeframe_index]), iHigh(Symbol(), timeframes[timeframe_index], bar_index), colors[timeframe_index], styles[timeframe_index], widths[timeframe_index]);
}
//+------------------------------------------------------------------+
int getUpperFractalBar(int timeframe, int starting_bar) {
	for(int bar = starting_bar; bar < Bars; bar++)
		if(isUpperFractal(timeframe, bar)) return(bar);
	return (-1);
}
//+------------------------------------------------------------------+
bool isUpperFractal(int timeframe, int bar) {
	for(int offset = -2; offset <= 2; offset++)
		if( (offset != 0) && (iHigh(Symbol(), timeframe, bar + offset) > iHigh(Symbol(), timeframe, bar)) ) return(false);
	return (true);
}
//+------------------------------------------------------------------+
int getLowerFractalBar(int timeframe, int starting_bar) {
	for(int bar = starting_bar; bar < Bars; bar++)
		if(isLowerFractal(timeframe, bar)) return(bar);
	return (-1);
}
//+------------------------------------------------------------------+
bool isLowerFractal(int timeframe, int bar) {
	for(int offset = -2; offset <= 2; offset++)
		if( (offset != 0) && (iLow(Symbol(), timeframe, bar + offset) < iLow(Symbol(), timeframe, bar)) ) return(false);
	return (true);
}
//+------------------------------------------------------------------+
void drawSupport(int bar_index, int timeframe_index) {
	if(bar_index > 0) drawTrendLine(getTrendLineName(SUPPORT, timeframes[timeframe_index]), iLow(Symbol(), timeframes[timeframe_index], bar_index), colors[timeframe_index], styles[timeframe_index], widths[timeframe_index]);
}
//+------------------------------------------------------------------+
void drawTrendLine(string object_name, double price, color line_color, int line_style, int line_width) {
	ObjectDelete(object_name);
	ObjectCreate(object_name, OBJ_HLINE, 0, Time[0], price, Time[Bars - 1], price);
	ObjectSet(object_name, OBJPROP_COLOR, line_color);
	ObjectSet(object_name, OBJPROP_STYLE, line_style);
	ObjectSet(object_name, OBJPROP_WIDTH, line_width);
   if (DisplayTextLabel)
      {
        ObjectDelete("banzai"+object_name);
        if (ObjectFind("banzai"+object_name)!=0)
           {
            ObjectCreate ("banzai"+object_name,OBJ_TEXT,0,Time[10]+Period()*60*ShiftLabel, price, Time[Bars - 1], price);
            ObjectSetText("banzai"+object_name,object_name,LabelFontSize,LabelFont,EMPTY);
            ObjectSet    ("banzai"+object_name,OBJPROP_COLOR,line_color);
           }
        else
            ObjectMove("banzai"+object_name,0,Time[10]+Period()*60*ShiftLabel, price);
      }
}
//+------------------------------------------------------------------+
string getTrendLineName(string object_type, int timeframe) {
	return(object_type + " " + getTimeframeName(timeframe));
}
//+------------------------------------------------------------------+
string getTimeframeName(int timeframe) {
	static int timeframe_periods[] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1};
	static string timeframe_names[] = {"M1", "M5", "M15", "M30", "H1", "H4", "D1", "W1", "MN1"};
	
	for(int i = 0; i < ArraySize(timeframe_periods); i++)
		if(timeframe == timeframe_periods[i]) return (timeframe_names[i]);

	return("Unknown");
}
//+------------------------------------------------------------------+
