//+------------------------------------------------------------------+
//|                                                    P4L Clock.mq4 |
//|                                       Original version:   Jerome |
//|                                                4xCoder@gmail.com |
//|                                                                  |
//| Revised: By Pips4life, a user at forexfactory.com                |
//| 2008-09-24 v2.0 P4L Clock.mq4                                         |
//| Previous names: Clock_v1_3.mq4, Clock.mq4, ...                   |
//+------------------------------------------------------------------+
//
// Version History:
// 2008-09-24 "P4L Clock.mq4" by pips4life @ forexfactory.com 
//    Different highlight color(s) used for Market Open hours (Assuming 8AM - 5PM local market hours)
//    Added seconds display, and used method such that single digits look better (":09" not ":9")
//    Added "Broker_Time_Is_Gold_Standard" to adjust (by a few seconds or minutes) the market hours, because
//      as if often the case, the local computer clock may be off by a small amount.
//    Two extern variables to control display of seconds: bool Display_Time_With_Seconds, int Display_Bar_With_Seconds.
//    When Display_Bar_With_Seconds=2 (Auto mode), seconds display when < 2min, OR, if Display_Time_With_Seconds=True.
//    "Bar:" changed to "Bar Left:" (remaining time). Also, it will say "wait4bar" (rather than to display
//      a negative number as would have occurred) during periods of low activity until a new bar is formed.
//    "Suppress_Bar_HH_Below_H1" displays only [MM:SS] for H1 and below since HH in [HH:MM:SS] is always "00" 
//    Adjusted pixel distance between labels depending on options.
//    "Bar Left:" time does not display above D1 charts.  A future enhancement (not planned) could report DD_HH:MM[:SS]
//    Added Show_DIBS_London clock with user-setable start/stop hour relative to London (6AM and 7PM at present).
//
// 2008-??   v1_4  Was NOT an indicator, rather a script; however, it didn't handle new bars (Time[0] stuck), nor could
//    one change timeframes without having to "Disable" and re-add the script. May have been more CPU intensive??
// 2008-??   v1_3 and earlier.  Details can be found on the web.

//#property copyright "Jerome" //previous author
//#property link      "4xCoder@gmail.com"
#property copyright "pips4life" //P4L Clock.mq4 derivative
#property link      "pips4life, a user at forexfactory.com"

#import "kernel32.dll"
void GetLocalTime(int& TimeArray[]);
void GetSystemTime(int& TimeArray[]);
int  GetTimeZoneInformation(int& TZInfoArray[]);
#import

//------------------------------------------------------------------
// Instructions
//    Copy this file to:  C:\Program Files\--your-MT4-directory-here---\experts\indicators
//    Review the "extern" variable settings below. Change as desired, then restart MT4 or do "Compile" in MetaEditor.
//    
//    Open a chart and add this indicator. Assuming you compiled with the "extern" defaults you prefer,
//    you shouldn't need to change any of the defaults, *except* one:
//    This Version requires "Allow DLL Imports" be set in Common Tab when you add this to a chart!
//    FYI, the DLLs retrieve the local CPU clock time and timezone info as well as world timezone info.
//
//    NOTE! The world timezone times are only as accurate as your LOCAL CPU CLOCK! Verify and set it accurately!
//    NOTE! Your Broker time is independent.
// DISCLAIMER: Use completely at your own risk!! Author(s) accept no liabilities whatsoever!

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red


//---- input parameters
extern string   _INFO_Set_your_computer_clock = "Accuracy depends on YOUR CPU CLOCK!!";
extern string   _INFO_Verify_times_with_URL   = "http://www.worldtimezone.net/index24.php";
extern string   _INFO_Re_labelCorner          = "0=Top-left, 1=TR, 2=BL, 3=BR";
extern int      labelCorner                   = 1;          // 1 & 3 work best:  0=top-left; 1=top-right; 2=bottom-left; 3=bottom-right
extern int      topOffsetPixels               = 120;        // pixels from top to show the clock
extern color    labelColor                    = DarkGreen;  // Color of label, off-hours
extern color    clockColor                    = MediumBlue; // Color of clock, off-hours
extern color    labelMktOpenColor             = Red;        // Color of label, market-open
extern color    clockMktOpenColor             = Red;        // Color of clock, market-open
extern bool     Highlight_Market_Open         = true ;      // When true, the above market-open colors are used between 8AM - 5PM (market local)
extern bool     Display_Times_With_AMPM       = false;      //true=show 12 hour AM/PM time, false=show 24 hour time
extern bool     Broker_Time_Is_Gold_Standard  = true ;      //If true, make a correction up to a few seconds/minutes vs. your local CPU clock. FYI, we don't know Broker TZ/DST info but don't care.
extern bool 	 Display_Time_With_Seconds     = false;      // Turn on seconds.
extern string   __INFO_Re_Bar_With_Seconds    = "0=No; 1=Yes; 2=Auto"; // Auto is: if < 120 seconds or if Display_Time_With_Seconds is true.
extern int  	 Display_Bar_With_Seconds      = 1;     // Control "Bar Left:" to display ":SS" independently from other times.
extern bool     Suppress_Bar_HH_Below_H1      = true ;  // For "Bar Left:" on H1 and below, display [MM:SS] since HH in [HH:MM:SS] is always "00"
extern bool     ShowTokyo                     = true ;
extern bool 	 ShowLondon                    = true ;
extern bool 	 ShowNewYork                   = true ;
extern bool 	 ShowGMT                       = true ; // FYI, GMT does not change with Daylight Savings Time. In winter, London=GMT; in summer, London=GMT+1
extern bool     ShowLocal                     = true ; // FYI, this is your local computer clock.  Your clock must be accurate for all other timezones to be accurate!!
extern bool     Show_DIBS_London              = false; // FYI, for DIBS method, see http://www.forexfactory.com/showthread.php?t=86766
extern int      DIBS_LondonOpenHour           = 6;     // DIBS relative to London local time. 6 ~= 2 hours before London ~= Chicago midnight. (Follows London DST)
extern int      DIBS_LondonCloseHour          = 15;    // MAX is 23!! Subjective choice. Change as desired. 9 hours length??


//---- buffers
double ExtMapBuffer1[];
int LondonTZ = 0;
int TokyoTZ = 9;
int NewYorkTZ = -5;


// All local markets assumed 8AM to 5PM
int localOpenHour = 8;
int localCloseHour = 17;

string TimeToString( datetime when ) {
   string timeStr;
   int hour = TimeHour( when );
   if ( !Display_Times_With_AMPM ) 
     {
      if (Display_Time_With_Seconds) timeStr = (TimeToStr( when, TIME_MINUTES|TIME_SECONDS));
      else timeStr = (TimeToStr( when, TIME_MINUTES));
     }
   else
     {
      // User wants 12HourTime format with "AM" or "PM".   
      // FYI, if >12:00, subtract 12 hours in seconds which is 12*60*60=43200
      if (Display_Time_With_Seconds)
        {
         if ( hour >  12 || hour == 0) timeStr = TimeToStr( (when - 43200), TIME_MINUTES|TIME_SECONDS);
         else timeStr = TimeToStr( when, TIME_MINUTES|TIME_SECONDS);
         if ( hour >= 12) timeStr = StringConcatenate(timeStr, " PM");
         else timeStr = StringConcatenate(timeStr, " AM");
        }
      else
        {
         if ( hour >  12 || hour == 0) timeStr = TimeToStr( (when - 43200), TIME_MINUTES);
         else timeStr = TimeToStr( when, TIME_MINUTES);
         if ( hour >= 12) timeStr = StringConcatenate(timeStr, " PM");
         else timeStr = StringConcatenate(timeStr, " AM");
        }
     }
   return (timeStr);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   static datetime last_timecurrent;
   if ( !IsDllsAllowed() ) 
   {
      if (TimeCurrent() - last_timecurrent < 7) return; // With a lot of fast ticks, this would be annoying if not delayed a bit
      last_timecurrent = TimeCurrent();
      Alert( WindowExpertName(),": ERROR. DLLs are disabled. To enable, select 'Allow DLL Imports' in the Common Tab of indicator" );
      return;
   }
     
   if (TimeCurrent() - last_timecurrent == 0) return; // No point in processing more than 1 tick per second.
   last_timecurrent = TimeCurrent();
   
   int    TimeArray[4];
   int    TZInfoArray[43];
   int    nYear,nMonth,nDay,nHour,nMin,nSec,nMilliSec;
   string sMilliSec;
   
   GetLocalTime(TimeArray);
//---- parse date and time from array
   nYear=TimeArray[0]&0x0000FFFF;
   nMonth=TimeArray[0]>>16;
   nDay=TimeArray[1]>>16;
   nHour=TimeArray[2]&0x0000FFFF;
   nMin=TimeArray[2]>>16;
   nSec=TimeArray[3]&0x0000FFFF;
   nMilliSec=TimeArray[3]>>16;
   string LocalTimeS = FormatDateTime(nYear,nMonth,nDay,nHour,nMin,nSec);
   datetime localTime = StrToTime( LocalTimeS );
   

   int gmt_shift=0;
   int dst=GetTimeZoneInformation(TZInfoArray);
   //if(dst!=0) gmt_shift=TZInfoArray[0];
   //Print("Difference between your local time and GMT is: ",gmt_shift," minutes");
   //if(dst==2) gmt_shift+=TZInfoArray[42];
   if (dst == 1) gmt_shift = 3600;

   datetime brokerTime = TimeCurrent();
   datetime brokerCorrection = 0;
   
   if (Broker_Time_Is_Gold_Standard) 
   {
      brokerCorrection = TimeMinute(brokerTime)*60 + TimeSeconds(brokerTime) - TimeMinute(localTime)*60 - TimeSeconds(localTime);
      if (brokerCorrection > 1800) brokerCorrection = brokerCorrection - 3600;
      else if (brokerCorrection < -1800) brokerCorrection = brokerCorrection + 3600;
      //Alert("brokerCorrection seconds: ", brokerCorrection);
   }
   //else GMT = localTime + gmt_shift * 60;
   
   datetime GMT = TimeLocal()+gmt_shift+brokerCorrection+(TZInfoArray[0]+TZInfoArray[42])*60;
   
   datetime london = GMT + (LondonTZ + (dst - 1)) * 3600;
   datetime tokyo = GMT + (TokyoTZ) * 3600;
   datetime newyork = GMT + (NewYorkTZ + (dst - 1)) * 3600;
   
   //Print( brokerTime, " ", GMT, " ", local, " ", london, " ", tokyo, " ", newyork  );
   string GMTs = TimeToString( GMT );
   string locals = TimeToString( localTime  );
   string londons = TimeToString( london  );
   string tokyos = TimeToString( tokyo  );
   string newyorks = TimeToString( newyork  );
   string brokers = TimeToString( TimeCurrent() );
   
   int secondsleft = Period()*60 + Time[0] - TimeCurrent(); // FYI, this CAN go negative if a new bar hasn't formed yet!
   string bars;
   if (secondsleft >= 0) 
   {
      if (Display_Bar_With_Seconds != 0 && (Display_Bar_With_Seconds == 1 || Display_Time_With_Seconds || (Display_Bar_With_Seconds == 2 && secondsleft < 120))) bars = TimeToStr( Period()*60 + Time[0] - TimeCurrent(), TIME_MINUTES|TIME_SECONDS );
      else bars = TimeToStr( Period()*60 + Time[0] - TimeCurrent(), TIME_MINUTES );
      
      if (Suppress_Bar_HH_Below_H1 && Period() <= PERIOD_H1 && StringLen(bars) > 6) bars = StringSubstr(bars,3);
   }
   else // negative means no new bar yet formed
     {
      if (Display_Bar_With_Seconds == 0) bars = "wait"; // or "--:--"
      else bars = "wait4bar"; // or "--:--:--"; 
     }
   
   if(Show_DIBS_London)
   {
   	if (Highlight_Market_Open && TimeHour(london) >= DIBS_LondonOpenHour && TimeHour(london) < DIBS_LondonCloseHour)
   	{
   	   ObjectSetText( "dibsl", "* DIBS UK:", 10, "Arial", labelMktOpenColor );
      	ObjectSetText( "dibst", londons, 10, "Arial",clockMktOpenColor );
   	}
   	else
   	{
   	   ObjectSetText( "dibsl", "DIBS UK:", 10, "Arial", labelColor );
      	ObjectSetText( "dibst", londons, 10, "Arial",clockColor );
      }
   }
   if ( ShowLocal ) {
      ObjectSetText( "locl", "Local:", 10, "Arial", labelColor );
      ObjectSetText( "loct", locals, 10, "Arial",clockColor );
   }
   if(ShowGMT)
   {
   	ObjectSetText( "gmtl", "GMT:", 10, "Arial", labelColor );
   	ObjectSetText( "gmtt", GMTs, 10, "Arial",clockColor );
   }
   if(ShowNewYork)
   {
   	if (Highlight_Market_Open && TimeHour(newyork) >= localOpenHour && TimeHour(newyork) < localCloseHour)
   	{
   	   ObjectSetText( "nyl", "* New York:", 10, "Arial", labelMktOpenColor );
      	ObjectSetText( "nyt", newyorks, 10, "Arial",clockMktOpenColor );
   	}
   	else
   	{
   	   ObjectSetText( "nyl", "New York:", 10, "Arial", labelColor );
      	ObjectSetText( "nyt", newyorks, 10, "Arial",clockColor );
      }
   }
   if(ShowLondon)
   {
   	if (Highlight_Market_Open && TimeHour(london) >= localOpenHour && TimeHour(london) < localCloseHour)
   	{
      	ObjectSetText( "lonl", "* London:", 10, "Arial", labelMktOpenColor );
      	ObjectSetText( "lont", londons, 10, "Arial",clockMktOpenColor );
   	}
   	else
   	{
   	   ObjectSetText( "lonl", "London:", 10, "Arial", labelColor );
   	   ObjectSetText( "lont", londons, 10, "Arial",clockColor );
   	}
   }
   if(ShowTokyo)
   {
   	if (Highlight_Market_Open && TimeHour(tokyo) >= localOpenHour && TimeHour(tokyo) < localCloseHour)
   	{
   	   ObjectSetText( "tokl", "* Tokyo:", 10, "Arial", labelMktOpenColor );
   	   ObjectSetText( "tokt", tokyos, 10, "Arial",clockMktOpenColor );
   	}
   	else
   	{
   	   ObjectSetText( "tokl", "Tokyo:", 10, "Arial", labelColor );
   	   ObjectSetText( "tokt", tokyos, 10, "Arial",clockColor );
   	}
   }
   
   // Always display Broker Time
   ObjectSetText( "brol", "Broker:", 10, "Arial", labelColor );
   ObjectSetText( "brot", brokers, 10, "Arial",clockColor );
   
   if(Period() <= PERIOD_D1)
   {
      ObjectSetText( "barl", "Bar Left:", 10, "Arial", labelColor );
      ObjectSetText( "bart", StringConcatenate("[ ",bars," ]"), 10, "Arial",clockColor );
   }
//----
   return(0);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int ObjectMakeLabel( string n, int xoff, int yoff ) {
   ObjectCreate( n, OBJ_LABEL, 0, 0, 0 );
   ObjectSet( n, OBJPROP_CORNER, labelCorner );
   ObjectSet( n, OBJPROP_XDISTANCE, xoff );
   ObjectSet( n, OBJPROP_YDISTANCE, yoff );
   ObjectSet( n, OBJPROP_BACK, true );
}

string FormatDateTime(int nYear,int nMonth,int nDay,int nHour,int nMin,int nSec)
  {
   string sMonth,sDay,sHour,sMin,sSec;
//----
   sMonth=100+nMonth;
   sMonth=StringSubstr(sMonth,1);
   sDay=100+nDay;
   sDay=StringSubstr(sDay,1);
   sHour=100+nHour;
   sHour=StringSubstr(sHour,1);
   sMin=100+nMin;
   sMin=StringSubstr(sMin,1);
   sSec=100+nSec;
   sSec=StringSubstr(sSec,1);
//----
   return(StringConcatenate(nYear,".",sMonth,".",sDay," ",sHour,":",sMin,":",sSec));
  }

int init()
  {
//---- indicators
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtMapBuffer1);
   
   int top=topOffsetPixels;
   int left = 90;
   int right = 22;
   if (!Display_Times_With_AMPM && !Display_Time_With_Seconds && Display_Bar_With_Seconds == 0) right = 42;
   else if (Display_Times_With_AMPM && !Display_Time_With_Seconds) right = 32;
   
   if ( Display_Times_With_AMPM )
      left = 102;
   if ( ShowLocal ) {
      ObjectMakeLabel( "locl", left, top );
      ObjectMakeLabel( "loct", right, top );
   }
   int offset=15;
   if ( Show_DIBS_London ) {
      ObjectMakeLabel( "dibsl", left, top-offset );
      ObjectMakeLabel( "dibst", right, top-offset );
      offset+=15;
   }
   if(ShowGMT)
   {
   	ObjectMakeLabel( "gmtl", left, top-offset );
   	ObjectMakeLabel( "gmtt", right, top-offset );
   	offset+=15;
   }
   if(ShowNewYork)
   {
	   ObjectMakeLabel( "nyl", left, top-offset );
   	ObjectMakeLabel( "nyt", right, top-offset );
   	offset+=15;
   }
   if(ShowLondon)
   {
	   ObjectMakeLabel( "lonl", left, top-offset );
   	ObjectMakeLabel( "lont", right, top-offset );
   	offset+=15;
   }
   if(ShowTokyo)
   {
   	ObjectMakeLabel( "tokl", left, top-offset );
   	ObjectMakeLabel( "tokt", right, top-offset );
   	offset+=15;
   }
   ObjectMakeLabel( "brol", left, top-offset );
   ObjectMakeLabel( "brot", right, top-offset );
  	offset+=15;
   if(Period() <= PERIOD_D1)
   {
      ObjectMakeLabel( "barl", left, top-offset );
      ObjectMakeLabel( "bart", right, top-offset );
      //offset+=15;
   }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   ObjectDelete( "locl" );
   ObjectDelete( "loct" );
   if(ShowNewYork)
   {
   	ObjectDelete( "nyl" );
   	ObjectDelete( "nyt" );
   }
   if(ShowGMT)
   {
	   ObjectDelete( "gmtl" );
   	ObjectDelete( "gmtt" );
   }
   if(ShowLondon)
   {
   	ObjectDelete( "lonl" );
   	ObjectDelete( "lont" );
   }
   if(ShowTokyo)
   {
	   ObjectDelete( "tokl" );
   	ObjectDelete( "tokt" );
   }
   ObjectDelete( "brol" );
   ObjectDelete( "brot" );
   ObjectDelete( "barl" );
   ObjectDelete( "bart" );
   if(Show_DIBS_London)
   {
   	ObjectDelete( "dibsl" );
   	ObjectDelete( "dibst" );
   }

//----
   return(0);
  }

