///+------------------------------------------------------------------+ 
// PUX_3_Semafor              (2)
// Ways of the ancients      (rus)
//______________________o7o___(_)___o7o__
//___¦_____¦_____¦gold¦_____¦_____¦_____¦
//¦_5484_¦_____¦_____¦_____¦_____¦_____¦__
//___¦_____¦_____¦_____¦_kazan__¦_____¦
//¦____¦ihldiaf¦_____¦_____¦_____¦____¦__
//___¦_____¦_____¦_____¦Lou¦Master_¦____¦
//¦PUX_FX___¦_____¦_garri_¦_____¦_____¦__        APRIL, 2013
//+------------------------------------------------------------------+
#property indicator_chart_window
//+------------------------------------------------------------------+ 
#property indicator_buffers 6

#property indicator_color1 Black 
#property indicator_color2 Black 
#property indicator_color3 DarkViolet
#property indicator_color4 DarkViolet
#property indicator_color5 Green
#property indicator_color6 Red
 
#property indicator_width1 3
#property indicator_width2 3
#property indicator_width3 3
#property indicator_width4 3
#property indicator_width5 5
#property indicator_width6 5

#import "user32.dll"
   int MessageBeep(int wType); 
#import

enum SoundConst
{
    SND0, SND1, SND2, SND3, NO  
}; 

/*
 MB_ICONASTERISK        = 0x40, 
 MB_ICONEXCLAMATION     = 0x30,
 MB_ICONHAND            = 0x10,
 MB_ICONQUESTION        = 0x20,
 NO                     =-1,
*/


//---- input parameters 
extern double              Period1        = 5; 
extern double              Period2        = 12; 
extern double              Period3        = 34; 
extern string              _______Параметры_сигнальщика___ = "";
extern int                 CCI_Period     = 20;
extern int                 BarsCount      = 1000;  // Общее количество анализируемых
extern int                 WatchDepth     = 30;    // Глубина поиса от СФБ влево для поиска дивергенции
extern SoundConst          SelectSound;
extern string              Dev_Step_1     = "1";
extern string              Dev_Step_2     = "1";
extern string              Dev_Step_3     = "1";
extern int                 Symbol_1_Kod   = 158;
extern int                 Symbol_2_Kod   = 159;
extern int                 Symbol_3_Kod   = 178;

//+----    mod of  TRO MODIFICATION ------------------------+ 
 string _____           ="";
 bool   Box_Alerts      = false ;
 bool   Email_Alerts    = false ;

 bool   Alert_Lv1    = false ;
 bool   Alert_Lv2    = false ;
 bool   Alert_Lv3    = false ;

//---- buffers 
double FP_BuferUp[];
double FP_BuferDn[]; 
double NP_BuferUp[];
double NP_BuferDn[]; 
double HP_BuferUp[];
double HP_BuferDn[]; 

int F_Period;
int N_Period;
int H_Period;
int Dev1;
int Stp1;
int Dev2;
int Stp2;
int Dev3;
int Stp3;

string symbol, tChartPeriod,  tShortName ;  
int    digits, period  ; 
bool Trigger1,  Trigger2,  Trigger3 ;
int OldBars = -1 ;
color tColor = Yellow ;

string MyName = "ZigSignal_";
int UninitR;
datetime LastSndTime;
string SndName;
int SoundType;
//+------------------------------------------------------------------+ 
int init() 
  { 
//+------------------------------------------------------------------+   
   period       = Period() ;     
   tChartPeriod =  TimeFrameToString(period) ;
   symbol       =  Symbol() ;
   digits       =  Digits ;   

   tShortName = "tbb"+ symbol + tChartPeriod  ;
 
 
   switch(SelectSound)
   {
      case 0: SoundType = 0x40; break;
      case 1: SoundType = 0x30; break;
      case 2: SoundType = 0x10; break;
      case 3: SoundType = 0x20; break;
      case 4: SoundType = -1; break;
      default:SoundType = 0x40; break;

   }
//+------------------------------------------------------------------+   
   if (Period1>0) F_Period=MathCeil(Period1*Period()); else F_Period=0; 
   if (Period2>0) N_Period=MathCeil(Period2*Period()); else N_Period=0; 
   if (Period3>0) H_Period=MathCeil(Period3*Period()); else H_Period=0;    
//---- 
   if (Period1>0)
   {
   SetIndexStyle(0,DRAW_ARROW); 
   SetIndexArrow(0,Symbol_1_Kod); 
   SetIndexBuffer(0,FP_BuferUp); 
   SetIndexEmptyValue(0,0.0); 
   
   SetIndexStyle(1,DRAW_ARROW); 
   SetIndexArrow(1,Symbol_1_Kod); 
   SetIndexBuffer(1,FP_BuferDn); 
   SetIndexEmptyValue(1,0.0); 
   }   
//---- 
   if (Period2>0)
   {
   SetIndexStyle(2,DRAW_ARROW); 
   SetIndexArrow(2,Symbol_2_Kod); 
   SetIndexBuffer(2,NP_BuferUp); 
   SetIndexEmptyValue(2,0.0); 
   
   SetIndexStyle(3,DRAW_ARROW); 
   SetIndexArrow(3,Symbol_2_Kod); 
   SetIndexBuffer(3,NP_BuferDn); 
   SetIndexEmptyValue(3,0.0); 
   }
//---- 
   if (Period3>0)
   {
   SetIndexStyle(4,DRAW_ARROW); 
   SetIndexArrow(4,Symbol_3_Kod); 
   SetIndexBuffer(4,HP_BuferUp); 
   SetIndexEmptyValue(4,0.0); 

   SetIndexStyle(5,DRAW_ARROW); 
   SetIndexArrow(5,Symbol_3_Kod); 
   SetIndexBuffer(5,HP_BuferDn); 
   SetIndexEmptyValue(5,0.0); 
   }
//----
   int CDev=0;
   int CSt=0;
   int Mass[]; 
   int C=0;  
   if (IntFromStr(Dev_Step_1,C, Mass)==1) 
      {
        Stp1=Mass[1];
        Dev1=Mass[0];
      }
   
   if (IntFromStr(Dev_Step_2,C, Mass)==1)
      {
        Stp2=Mass[1];
        Dev2=Mass[0];
      }      
   
   
   if (IntFromStr(Dev_Step_3,C, Mass)==1)
      {
        Stp3=Mass[1];
        Dev3=Mass[0];
      } 
      DelMyObj(MyName);     
   return(0); 
  } 
//+------------------------------------------------------------------+ 
int deinit() 
  { 
     UninitR = UninitializeReason() ;
    DelMyObj(MyName); 
   return(0); 
  } 

//int start() 
//  { 
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
{  
   
   int i, limit;  
   if (Period1>0) CountZZ(FP_BuferUp,FP_BuferDn,Period1,Dev1,Stp1);
   if (Period2>0) CountZZ(NP_BuferUp,NP_BuferDn,Period2,Dev2,Stp2);
   if (Period3>0) CountZZ(HP_BuferUp,HP_BuferDn,Period3,Dev3,Stp3);
   
   //PlaySound(SndName);
   
            //datetime tim = StrToTime("2014.06.20 15:15");
            // if(Time[0] == tim)
           // Print("== Debug == ");
   OldBars = Bars ;   
   
   limit = 3000;
   for(i = limit; i>=0; i--)
   GetSignals(i);
   
   
   return(0);
}
/*
 FP_BuferUp[]; мал зиг снизу
 FP_BuferDn[]; мал зиг сверху
 NP_BuferUp[];
 NP_BuferDn[]; 
 HP_BuferUp[]; биг зиг снизу
 HP_BuferDn[]; биг зиг сверху
*/
//==============================================================================================
//       GetSignals
//==============================================================================================
void GetSignals(int j)
{
     double bigHi, midHi, smlHi, bigLo, midLo, smlLo;
     double CCI1, CCI2, HI1, HI2, LO1, LO2;
     int ibig, imid, isml, i1, i2;
     bool flag, okMid, okSml;
     int i, iCCI1, iCCI2;
     int iMax = j + WatchDepth; // Ограничение на глубину анализа назад
     //bool ps;
     //-------------------------------- Анализ паттерна вниз ---------------------
     // инициализация
     flag = true; okMid = false; okSml = false;
     ibig = -1; imid = -1; isml = -1;
     iCCI1 = -1; iCCI2 = -1;
     i1 = -1; i2 = -1;
     //if(HP_BuferDn[j] != 0)   {ibig = j;  bigHi = HP_BuferDn[j];}
     if(HP_BuferDn[j+1] != 0) {ibig = j+1;  bigHi = HP_BuferDn[j+1];}
     if(ibig != -1)                 // Есть солнце на 0 или 1 баре
     {
       // ----- ищем СФМ
       i = ibig + 1;
       while(flag)
       {
         if(NP_BuferDn[i] != 0) {midHi = NP_BuferDn[i]; imid = i;} 
         if(midHi != 0 ) // нашли ближайшие слева СФМ и СФММ
         {
              flag = false;
              okMid = true;
              break;
         }
         i++;
         if(i >= iMax) break;
       }
       // ----- ищем СФММ
       i = ibig + 1;
       flag = true;
        while(flag)
       {
         if(FP_BuferDn[i] != 0) {smlHi = FP_BuferDn[i]; isml = i;}
         if(smlHi != 0) // нашли ближайши1 слева  СФММ
         {
              flag = false;
              okSml = true;
              break;
         }
         i++;
         if(i >= iMax) break;
       }
         //datetime tim = StrToTime("2014.06.20 15:15");
         //if(Time[j] == tim)
         //Print("== Debug == ", " ibig = ", ibig , " imid = ", imid, " isml = ", isml);
         
       if(okMid && okSml)
       {
          if(midHi > smlHi && midHi < bigHi)  {iCCI1 = ibig; iCCI2 = imid; HI1 = High[ibig]; HI2 = High[imid]; i1 = ibig; i2 = imid;} // это выбрали СФМ  в качестве точки, ближайшей к СФБ
          if(midHi < smlHi && smlHi < bigHi)  {iCCI1 = ibig; iCCI2 = isml; HI1 = High[ibig]; HI2 = High[isml]; i1 = ibig; i2 = isml;} // это выбрали СФММ в качестве точки, ближайшей к СФБ
          if(iCCI1 != -1 && iCCI2 != -1)
          {
             CCI1 = iCCI(Symbol(),0,CCI_Period,PRICE_TYPICAL,iCCI1);
             CCI2 = iCCI(Symbol(),0,CCI_Period,PRICE_TYPICAL,iCCI2);
             if(HI1 > HI2 && CCI1 < CCI2) //поймали дивер
             {
             
             DrawStopLine(i1, i2, High[i2], Red);
             
             if(i1 == 0 || i1 == 1)
              // Print("++++ ", "i1 = ", i1);
                  if(Time[0] > LastSndTime && SoundType != -1 )
                  {
                     //PlaySound(SndName);
                     MessageBeep(SoundType);
                     LastSndTime = Time[0];
                  }
             }
          }
       } 
     }
     
     
     
     
     //-------------------------------- Анализ паттерна вверх ---------------------
     // инициализация
     flag = true; okMid = false; okSml = false;
     ibig = -1; imid = -1; isml = -1;
     iCCI1 = -1; iCCI2 = -1;
     i1 = -1; i2 = -1;
     //if(HP_BuferUp[j] != 0)   {ibig = j;    bigLo = HP_BuferUp[j];}
     if(HP_BuferUp[j+1] != 0) {ibig = j+1;  bigLo = HP_BuferUp[j+1];}
     
     if(ibig != -1)                 // Есть солнце на 0 или 1 баре
     {
       // ----- ищем СФМ
       i = ibig + 1;
       while(flag)
       {
         if(NP_BuferUp[i] != 0) {midLo = NP_BuferUp[i]; imid = i;} 
         if(midHi != 0 ) // нашли ближайший слева СФМ 
         {
              flag = false;
              okMid = true;
              break;
         }
         i++;
         if(i >= iMax) break;
       }
       // ----- ищем СФММ
       i = ibig + 1;
       flag = true;
        while(flag)
       {
         if(FP_BuferUp[i] != 0) {smlLo = FP_BuferUp[i]; isml = i;}
         if(smlLo != 0) // нашли ближайши1 слева  СФММ
         {
              flag = false;
              okSml = true;
              break;
         }
         i++;
         if(i >= iMax) break;
       }
          
         
         
         
       if(okMid && okSml) // Найдены обе точки СФМ и СФММ
       {
          if(midLo < smlLo && midLo > bigLo)  {iCCI1 = ibig; iCCI2 = imid; LO1 = Low[ibig]; LO2 = Low[imid]; i1 = ibig; i2 = imid;}
          if(midLo > smlLo && smlLo > bigLo)  {iCCI1 = ibig; iCCI2 = isml; LO1 = Low[ibig]; LO2 = Low[isml]; i1 = ibig; i2 = isml;}
       }
       if(okMid && !okSml) // Найдена только СФМ 
          {iCCI1 = ibig; iCCI2 = imid; LO1 = Low[ibig]; LO2 = Low[imid]; i1 = ibig; i2 = imid;}
       if(!okMid && okSml) // Найдена только СФММ 
          {iCCI1 = ibig; iCCI2 = isml; LO1 = Low[ibig]; LO2 = Low[isml]; i1 = ibig; i2 = isml;}
       
                     datetime tim = StrToTime("2014.06.20 03:30");
                     
                     if(Time[j] == tim )
                     {
                     Print("== Debug == ", " ibig = ", ibig , " imid = ", imid, " isml = ", isml, " i1 = ", i1);
                     Print("== Debug == ", " LastSndTime = ", TimeToString(LastSndTime, TIME_DATE|TIME_MINUTES), " == ", LastSndTime,  " Time[0] = ", Time[0]);
                     }
         
          if(iCCI1 != -1 && iCCI2 != -1)
          {
             CCI1 = iCCI(Symbol(),0,CCI_Period,PRICE_TYPICAL,iCCI1);
             CCI2 = iCCI(Symbol(),0,CCI_Period,PRICE_TYPICAL,iCCI2);
             if(LO1 < LO2 && CCI1 > CCI2) //поймали дивер
             {
               DrawStopLine(i1, i2, Low[i2],Lime);
               if(i1 == 0 || i1 == 1)
                  if(Time[0] > LastSndTime && SoundType != -1 )
                  {
                     //PlaySound(SndName);
                    
                     
                     
                     MessageBeep(SoundType);
                     LastSndTime = Time[0];
                  }
             }
          }
       
     }
     
}
//==============================================================================================
//       DrawStopLine
//==============================================================================================
void DrawStopLine(int i1, int i2, double price, color clr)
{
     datetime t1, t2;
     string lineName;
     long current_chart_id=ChartID();
     //double price; 
     
     //price = High[i2];
     t1 = Time[i1];
     t2 = Time[i2];
     lineName = MyName + TimeToString(t2, TIME_DATE|TIME_MINUTES);  // t2 - начало линии при прорисовке слева направо
     
     ObjectDelete(lineName);
     ObjectCreate(current_chart_id,lineName, OBJ_TREND, 0, t2,price, t1, price);
     ObjectSet(lineName, OBJPROP_RAY, false);
     ObjectSet(lineName,OBJPROP_COLOR, clr);
     ObjectSet(lineName,OBJPROP_WIDTH, 2); 
}


string TimeFrameToString(int tf)
{
   string tfs;
   switch(tf) {
      case PERIOD_M1:  tfs="M1"  ; break;
      case PERIOD_M5:  tfs="M5"  ; break;
      case PERIOD_M15: tfs="M15" ; break;
      case PERIOD_M30: tfs="M30" ; break;
      case PERIOD_H1:  tfs="H1"  ; break;
      case PERIOD_H4:  tfs="H4"  ; break;
      case PERIOD_D1:  tfs="D1"  ; break;
      case PERIOD_W1:  tfs="W1"  ; break;
      case PERIOD_MN1: tfs="MN";
   }
   return(tfs);
}
//+------------------------------------------------------------------+ 
void CountZZ( double& ExtMapBuffer[], double& ExtMapBuffer2[], int ExtDepth, int ExtDeviation, int ExtBackstep )
  {
   int    shift, back,lasthighpos,lastlowpos;
   double val,res;
   double curlow,curhigh,lasthigh,lastlow;
  
   int limit;
   
   if(BarsCount == 0)
      limit = Bars-ExtDepth;
   else
      limit = BarsCount;
   
   
   for(shift = limit; shift>=0; shift--)
     {
      val=Low[Lowest(NULL,0,MODE_LOW,ExtDepth,shift)];
      if(val==lastlow) val=0.0;
      else 
        { 
         lastlow=val; 
         if((Low[shift]-val)>(ExtDeviation*Point)) val=0.0;
         else
           {
            for(back=1; back<=ExtBackstep; back++)
              {
               res=ExtMapBuffer[shift+back];
               if((res!=0)&&(res>val)) ExtMapBuffer[shift+back]=0.0; 
              }
           }
        } 
        
          ExtMapBuffer[shift]=val;
      //--- high
      val=High[Highest(NULL,0,MODE_HIGH,ExtDepth,shift)];
      if(val==lasthigh) val=0.0;
      else 
        {
         lasthigh=val;
         if((val-High[shift])>(ExtDeviation*Point)) val=0.0;
         else
           {
            for(back=1; back<=ExtBackstep; back++)
              {
               res=ExtMapBuffer2[shift+back];
               if((res!=0)&&(res<val)) ExtMapBuffer2[shift+back]=0.0; 
              } 
           }
        }
      ExtMapBuffer2[shift]=val;
     }
   // final cutting 
   lasthigh=-1; lasthighpos=-1;
   lastlow=-1;  lastlowpos=-1;

   for(shift=Bars-ExtDepth; shift>=0; shift--)
     {
      curlow=ExtMapBuffer[shift];
      curhigh=ExtMapBuffer2[shift];
      if((curlow==0)&&(curhigh==0)) continue;
      //---
      if(curhigh!=0)
        {
         if(lasthigh>0) 
           {
            if(lasthigh<curhigh) ExtMapBuffer2[lasthighpos]=0;
            else ExtMapBuffer2[shift]=0;
           }
         //---
         if(lasthigh<curhigh || lasthigh<0)
           {
            lasthigh=curhigh;
            lasthighpos=shift;
           }
         lastlow=-1;
        }
      //----
      if(curlow!=0)
        {
         if(lastlow>0)
           {
            if(lastlow>curlow) ExtMapBuffer[lastlowpos]=0;
            else ExtMapBuffer[shift]=0;
           }
         //---
         if((curlow<lastlow)||(lastlow<0))
           {
            lastlow=curlow;
            lastlowpos=shift;
           } 
         lasthigh=-1;
        }
     }
  
   for(shift=Bars-1; shift>=0; shift--)
     {
      if(shift>=Bars-ExtDepth) ExtMapBuffer[shift]=0.0;
      else
        {
         res=ExtMapBuffer2[shift];
         if(res!=0.0) ExtMapBuffer2[shift]=res;
        }
     }
 }
//+------------------------------------------------------------------+   
int Str2Massive(string VStr, int& M_Count, int& VMass[])
  {
    int val=StrToInteger( VStr);
    if (val>0)
       {
         M_Count++;
         int mc=ArrayResize(VMass,M_Count);
         if (mc==0)return(-1);
          VMass[M_Count-1]=val;
         return(1);
       }
    else return(0);    
  } 
//+------------------------------------------------------------------+   
int IntFromStr(string ValStr,int& M_Count, int& VMass[])
  {
    
    if (StringLen(ValStr)==0) return(-1);
    string SS=ValStr;
    int NP=0; 
    string CS;
    M_Count=0;
    ArrayResize(VMass,M_Count);
    while (StringLen(SS)>0)
      {
            NP=StringFind(SS,",");
            if (NP>0)
               {
                 CS=StringSubstr(SS,0,NP);
                 SS=StringSubstr(SS,NP+1,StringLen(SS));  
               }
               else
               {
                 if (StringLen(SS)>0)
                    {
                      CS=SS;
                      SS="";
                    }
               }
            if (Str2Massive(CS,M_Count,VMass)==0) 
               {
                 return(-2);
               }
      }
    return(1);    
  }
//===============================================================================
//   Функция удаляет объекты, созданные в этом индюке
//   аргумент- начало имени
//===============================================================================
void DelMyObj(string myName)
{
int pos, pos2;
string objName;
int    obj_total=ObjectsTotal();
         
      for(int i=obj_total-1;i>=0; i--)
      {
         objName = ObjectName(i);
         pos = StringFind(objName, myName, 0);
         if(pos!=-1) 
         {
            //UninitR
            pos2 = StringFind(objName, "MedianMain", 0);
            if(pos2 == -1 || UninitR == REASON_REMOVE) 
            ObjectDelete(objName);
         }
      }
//return(0);
}