#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1 Aqua
#property indicator_color2 Yellow
#property indicator_color3 Lime
#property indicator_color4 Red
#property indicator_width1 1
#property indicator_width2 1
#property indicator_width3 3
#property indicator_width4 3

//
//
//
//
//

extern string TimeFrame       = "Current time frame";
extern int    MA_Price        = 0;    //Applied Price: 0-C,1-O,2-H,3-L,4-Median,5-Typical,6-Weighted
extern int    MA_Length       = 5;    //MA's Period 
extern int    MA_Mode         = 0;    //MA's Method:0-SMA,1-EMA,2-SMMA,3-LWMA  
extern int    ATR_Length      = 11;   //ATR's Period
extern double Kv              = 1.3;  //Volatility's Factor or Multiplier
extern double MoneyRisk       = 0.15; //Offset Factor 
extern bool   alertsOn        = true;
extern bool   alertsOnCurrent = false;
extern bool   alertsMessage   = true;
extern bool   alertsSound     = false;
extern bool   alertsEmail     = false;
extern string soundFile       = "alert2.wav";

// Button position settings
extern int    ButtonX         = 10;   // Distance from right edge (pixels)
extern int    ButtonY         = 25;   // Distance from top edge (pixels)

//
//
//
//
//

double UpBuffer[];
double DnBuffer[];
double UpSignal[];
double DnSignal[];
double smin[];
double smax[];
double trend[];

//
//
//
//
//

string indicatorFileName;
int    timeFrame;
bool   returnBars;
bool   calculateValue;

// ON/OFF toggle state
bool   indicatorEnabled = true;
bool   forceRecalc      = false;  // forces full redraw when switched back ON

// Button object name
string BTN_NAME = "FijiTrend_ToggleBtn";

//+------------------------------------------------------------------+
//| Draw or refresh the ON/OFF button                                |
//+------------------------------------------------------------------+

void CreateButton()
{
   if (ObjectFind(BTN_NAME) < 0)
      ObjectCreate(BTN_NAME, OBJ_BUTTON, 0, 0, 0);

   ObjectSet(BTN_NAME, OBJPROP_CORNER,    1);       // Top-right corner
   ObjectSet(BTN_NAME, OBJPROP_XDISTANCE, ButtonX);
   ObjectSet(BTN_NAME, OBJPROP_YDISTANCE, ButtonY);
   ObjectSet(BTN_NAME, OBJPROP_XSIZE,     80);
   ObjectSet(BTN_NAME, OBJPROP_YSIZE,     22);
   ObjectSet(BTN_NAME, OBJPROP_BACK,      false);
   ObjectSetString(0, BTN_NAME, OBJPROP_FONT, "Arial Bold");
   ObjectSet(BTN_NAME, OBJPROP_FONTSIZE,  9);

   if (indicatorEnabled)
   {
      ObjectSetString(0, BTN_NAME, OBJPROP_TEXT, "Fiji: ON");
      ObjectSet(BTN_NAME, OBJPROP_COLOR,        White);
      ObjectSet(BTN_NAME, OBJPROP_BGCOLOR,       Green);
      ObjectSet(BTN_NAME, OBJPROP_BORDER_COLOR,  DarkGreen);
   }
   else
   {
      ObjectSetString(0, BTN_NAME, OBJPROP_TEXT, "Fiji: OFF");
      ObjectSet(BTN_NAME, OBJPROP_COLOR,        White);
      ObjectSet(BTN_NAME, OBJPROP_BGCOLOR,       Red);
      ObjectSet(BTN_NAME, OBJPROP_BORDER_COLOR,  DarkRed);
   }
   ChartRedraw();
}

//+------------------------------------------------------------------+
//| Wipe all indicator drawings                                      |
//+------------------------------------------------------------------+

void ClearBuffers()
{
   for (int i = 0; i < Bars; i++)
   {
      UpBuffer[i] = EMPTY_VALUE;
      DnBuffer[i] = EMPTY_VALUE;
      UpSignal[i] = EMPTY_VALUE;
      DnSignal[i] = EMPTY_VALUE;
      trend[i]    = 0;
      smin[i]     = 0;
      smax[i]     = 0;
   }
}

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

int init()
{
   IndicatorBuffers(7);
   SetIndexBuffer(0, UpBuffer); SetIndexStyle(0, DRAW_ARROW); SetIndexArrow(0, 246); SetIndexLabel(0, "UpTrend");
   SetIndexBuffer(1, DnBuffer); SetIndexStyle(1, DRAW_ARROW); SetIndexArrow(1, 248); SetIndexLabel(1, "DnTrend");
   SetIndexBuffer(2, UpSignal); SetIndexStyle(2, DRAW_ARROW); SetIndexArrow(2, 233); SetIndexLabel(2, "UpSignal");
   SetIndexBuffer(3, DnSignal); SetIndexStyle(3, DRAW_ARROW); SetIndexArrow(3, 234); SetIndexLabel(3, "DnSignal");
   SetIndexBuffer(4, smin);
   SetIndexBuffer(5, smax);
   SetIndexBuffer(6, trend);

   indicatorFileName = WindowExpertName();
   calculateValue    = (TimeFrame == "calculateValue"); if (calculateValue) return(0);
   returnBars        = (TimeFrame == "returnBars");     if (returnBars)     return(0);
   timeFrame         = stringToTimeFrame(TimeFrame);

   IndicatorShortName(timeFrameToString(timeFrame) + " Fiji Trend");

   // Create the toggle button on chart
   CreateButton();

   return(0);
}

//+------------------------------------------------------------------+
//| Remove button on indicator removal                               |
//+------------------------------------------------------------------+

int deinit()
{
   ObjectDelete(BTN_NAME);
   return(0);
}

//+------------------------------------------------------------------+
//| Main calculation function                                        |
//+------------------------------------------------------------------+

int start()
{
   int counted_bars = IndicatorCounted();
   int shift, limit;

   if (counted_bars < 0) return(-1);
   if (counted_bars > 0) counted_bars--;
   limit = MathMin(Bars - counted_bars, Bars - 1);
   if (returnBars) { UpBuffer[0] = limit + 1; return(0); }

   //
   // Check button click - toggle ON/OFF
   //
   if (!calculateValue)
   {
      if (ObjectGet(BTN_NAME, OBJPROP_STATE) == 1)
      {
         indicatorEnabled = !indicatorEnabled;   // flip state
         ObjectSet(BTN_NAME, OBJPROP_STATE, 0);  // release button visually
         CreateButton();                         // refresh button colour/label

         if (!indicatorEnabled)
         {
            // Switched OFF: wipe all drawings and stop
            ClearBuffers();
            return(0);
         }
         else
         {
            // Switched back ON: force a full recalculation over all bars
            forceRecalc = true;
         }
      }

      // Still OFF: keep drawings cleared
      if (!indicatorEnabled)
      {
         ClearBuffers();
         return(0);
      }

      // Turned back ON: override limit so every bar is recalculated
      if (forceRecalc)
      {
         limit       = Bars - 1;
         forceRecalc = false;
      }
   }

   //
   //
   //
   //
   //

   if (calculateValue || timeFrame == Period())
   {
      for (shift = limit; shift >= 0; shift--)
      {
         double bprice = iMA(NULL, 0, MA_Length, 0, MA_Mode, MA_Price, shift);
         double sprice = iMA(NULL, 0, MA_Length, 0, MA_Mode, MA_Price, shift);
         smax[shift]   = bprice + Kv * iATR(NULL, 0, ATR_Length, shift);
         smin[shift]   = sprice - Kv * iATR(NULL, 0, ATR_Length, shift);

         DnBuffer[shift] = EMPTY_VALUE;
         DnSignal[shift] = EMPTY_VALUE;
         UpBuffer[shift] = EMPTY_VALUE;
         UpSignal[shift] = EMPTY_VALUE;
         trend[shift]    = trend[shift + 1];

         if (High[shift] > smax[shift + 1]) trend[shift] =  1;
         if (Low[shift]  < smin[shift + 1]) trend[shift] = -1;
         if (trend[shift] > 0 && smin[shift] < smin[shift + 1]) smin[shift] = smin[shift + 1];
         if (trend[shift] < 0 && smax[shift] > smax[shift + 1]) smax[shift] = smax[shift + 1];

         if (trend[shift] == 1)
         {
            UpBuffer[shift] = smin[shift] - (MoneyRisk - 1) * iATR(NULL, 0, ATR_Length, shift);
            if (trend[shift + 1] != 1) UpSignal[shift] = UpBuffer[shift];
         }
         if (trend[shift] == -1)
         {
            DnBuffer[shift] = smax[shift] + (MoneyRisk - 1) * iATR(NULL, 0, ATR_Length, shift);
            if (trend[shift + 1] != -1) DnSignal[shift] = DnBuffer[shift];
         }
      }
      manageAlerts();
      return(0);
   }

   //
   //
   //
   //
   //

   limit = MathMax(limit, MathMin(Bars, iCustom(NULL, timeFrame, indicatorFileName, "returnBars", 0, 0) * timeFrame / Period()));
   for (int i = limit; i >= 0; i--)
   {
      int y = iBarShift(NULL, timeFrame, Time[i]);
      UpBuffer[i] = iCustom(NULL, timeFrame, indicatorFileName, "calculateValue", MA_Price, MA_Length, MA_Mode, ATR_Length, Kv, MoneyRisk, 0, y);
      DnBuffer[i] = iCustom(NULL, timeFrame, indicatorFileName, "calculateValue", MA_Price, MA_Length, MA_Mode, ATR_Length, Kv, MoneyRisk, 1, y);
      trend[i]    = iCustom(NULL, timeFrame, indicatorFileName, "calculateValue", MA_Price, MA_Length, MA_Mode, ATR_Length, Kv, MoneyRisk, 6, y);
      UpSignal[i] = EMPTY_VALUE;
      DnSignal[i] = EMPTY_VALUE;
      if (UpBuffer[i] != EMPTY_VALUE && UpBuffer[i + 1] == EMPTY_VALUE) UpSignal[i] = UpBuffer[i];
      if (DnBuffer[i] != EMPTY_VALUE && DnBuffer[i + 1] == EMPTY_VALUE) DnSignal[i] = DnBuffer[i];
   }
   manageAlerts();
   return(0);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

int stringToTimeFrame(string tfs)
{
   tfs = stringUpperCase(tfs);
   for (int i = ArraySize(iTfTable) - 1; i >= 0; i--)
      if (tfs == sTfTable[i] || tfs == "" + iTfTable[i]) return(MathMax(iTfTable[i], Period()));
   return(Period());
}

string timeFrameToString(int tf)
{
   for (int i = ArraySize(iTfTable) - 1; i >= 0; i--)
      if (tf == iTfTable[i]) return(sTfTable[i]);
   return("");
}

string stringUpperCase(string str)
{
   string s = str;
   for (int length = StringLen(str) - 1; length >= 0; length--)
   {
      int tchar = StringGetChar(s, length);
      if ((tchar > 96 && tchar < 123) || (tchar > 223 && tchar < 256))
         s = StringSetChar(s, length, tchar - 32);
      else if (tchar > -33 && tchar < 0)
         s = StringSetChar(s, length, tchar + 224);
   }
   return(s);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------

void manageAlerts()
{
   if (!calculateValue && alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1; whichBar = iBarShift(NULL, 0, iTime(NULL, timeFrame, whichBar));
      if (trend[whichBar] != trend[whichBar + 1])
      {
         if (trend[whichBar] ==  1) doAlert(whichBar, "buy");
         if (trend[whichBar] == -1) doAlert(whichBar, "sell");
      }
   }
}

void doAlert(int forBar, string doWhat)
{
   static string   previousAlert = "nothing";
   static datetime previousTime;
   string message;

   if (previousAlert != doWhat || previousTime != Time[forBar])
   {
      previousAlert = doWhat;
      previousTime  = Time[forBar];

      message = StringConcatenate(Symbol(), " at ", TimeToStr(TimeLocal(), TIME_SECONDS), " - ", timeFrameToString(timeFrame) + " Fiji Trend ", doWhat);
      if (alertsMessage) Alert(message);
      if (alertsEmail)   SendMail(StringConcatenate(Symbol(), " Fiji Trend "), message);
      if (alertsSound)   PlaySound("alert2.wav");
   }
}
