//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-tsd.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers    2
#property indicator_color1     clrDarkGreen
#property indicator_color2     clrMaroon
#property indicator_width1     2
#property indicator_width2     2
#property indicator_level1     0

extern string TimeFrame       = "current time frame";
extern int    AtrPeriod       = 14;
extern bool   alertsOn        = false;
extern bool   alertsOnCurrent = true;
extern bool   alertsMessage   = true;
extern bool   alertsSound     = false;
extern bool   alertsEmail     = false;

double Hi[];
double Lo[];
double no[];
double kr[];
double trend[];
string indicatorFileName;
bool   calculateValue;
bool   returnBars;
int    timeFrame;

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------

int init()
{
   IndicatorDigits(0);      
   IndicatorBuffers(5);   
      SetIndexBuffer(0,kr); SetIndexStyle(0,DRAW_HISTOGRAM); SetIndexLabel(0,"XO Up");
      SetIndexBuffer(1,no); SetIndexStyle(1,DRAW_HISTOGRAM); SetIndexLabel(1,"XO Down");
      SetIndexBuffer(2,Hi);
      SetIndexBuffer(3,Lo);
      SetIndexBuffer(4,trend);
   SetIndexEmptyValue(0,0.00);
   SetIndexEmptyValue(1,0.00);
   SetIndexEmptyValue(2,0.00);
   SetIndexEmptyValue(3,0.00);
      indicatorFileName = WindowExpertName();
      calculateValue    = (TimeFrame=="CalculateValue"); if (calculateValue) return(0);
      returnBars        = (TimeFrame=="returnBars");     if (returnBars)     return(0);
      timeFrame         = stringToTimeFrame(TimeFrame);
   
   IndicatorShortName(timeFrameToString(timeFrame)+" XO ("+DoubleToStr(AtrPeriod,2)+")");
   return(0);
}

int start()
{
   int counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
           int limit=MathMin(Bars-counted_bars,Bars-1);
           if (returnBars) { kr[0] = limit+1; return(0); }
  
   if (calculateValue || timeFrame == Period())
   {
      for(int i=limit; i>=0; i--)
      {         
         if (i>=(Bars-2)) 
         {
           Hi[i+1]=Close[i]; 
           Lo[i+1]=Close[i]; 
           continue; 
           }
         double BoxPeriod = iATR(NULL,0,AtrPeriod,i);
         double cur      = Close[i];
                Hi[i]    = Hi[i+1];
                Lo[i]    = Lo[i+1];
                no[i]    = no[i+1];
                kr[i]    = kr[i+1];
                trend[i] = trend[i+1];

                if (cur > (Hi[i]+BoxPeriod)) 
                {
                     Hi[i]    = cur;
                     Lo[i]    = cur-BoxPeriod;
                     kr[i]    = kr[i+1]+1;
                     no[i]    = 0;
                     trend[i] = 1;
                }
                if (cur < (Lo[i]-BoxPeriod)) 
                {
                     Lo[i]    = cur;
                     Hi[i]    = cur+BoxPeriod;
                     no[i]    = no[i+1]-1;
                     kr[i]    = 0;
                     trend[i] = -1;
                }
      }
      manageAlerts();
      return(0);
   }

      limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
      for(i=limit; i>=0; i--)
      {
         int y = iBarShift(NULL,timeFrame,Time[i]);
            kr[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",AtrPeriod,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,0,y);
            no[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",AtrPeriod,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,1,y); 
      }
      return(0);     
}

void manageAlerts()
{
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1;
      if (trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar] ==  1) doAlert(whichBar,"up");
         if (trend[whichBar] == -1) doAlert(whichBar,"down");
      }
   }
}

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 = timeFrameToString(Period())+" "+Symbol()+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" XO trend changed to "+doWhat;
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol()," XO"),message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}

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 Char=StringGetChar(s, length);
         if((Char > 96 && Char < 123) || (Char > 223 && Char < 256))
               s = StringSetChar(s, length, Char - 32);
         else if(Char > -33 && Char < 0)
               s = StringSetChar(s, length, Char + 224);
   }
   return(s);
}

