#property show_inputs
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 White
#property indicator_color2 Yellow
#define READURL_BUFFER_SIZE 100
#define TITLE		0
#define COUNTRY 1
#define DATE		2
#define TIME		3
#define IMPACT		4
#define FORECAST	5
#define PREVIOUS	6

#import "Wininet.dll"
int InternetOpenW(string,int,string,string,int);
int InternetConnectW(int,string,int,string,string,int,int,int);
int HttpOpenRequestW(int,string,string,int,string,int,string,int);
int InternetOpenUrlW(int,string,string,int,int,int);
int InternetReadFile(int,uchar &arr[],int,int &arr[]);
int InternetCloseHandle(int);
#import
extern bool Low_Impact_News_On = true;
extern bool Medium_Impact_News_On = true;
extern bool Bank_Holiday_On = false;
extern bool Show_USD_News=true; //"true" = USD news on non-USD pair charts 
extern bool Show_EUR_News = true;
extern bool Show_GBP_News = true;
extern bool Show_NZD_News = true;
extern bool Show_JPY_News = true;
extern bool Show_AUD_News = true;
extern bool Show_CAD_News = true;
extern bool Show_CHF_News = true;
extern bool Show_CNY_News = true;

//global buffers and variables---------------------------------------------------------------------
bool skip;
datetime newsTime,calendardate; //sundaydate calendar
int newuntilminutes[200]; // Contains (minutes until) each news event
int xmlHandle,BoEvent,finalend,end,begin,minsTillNews,tmpMinspast,tmpMinsfuture,idxOfpast=-1,idxOffuture=-1,
newsIdx,next,Days,Hours,Mins;
int dayStart,monthStart,F1,F2,i,j,k,W;
int WebUpdateFreq = 240; // 240 Minutes between web updates to not overload FF server
string xmlFileName;
string xmlSearchName;
static int UpdateRateSec=10;
string sUrl="http://www.forexfactory.com/ffcal_week_this.xml"; //original
 //string sUrl = "http://www.forexfactory.com/ffcal_week_this.xml"; // new 12Feb2015
string myEvent,mainData[100][7],sData;
string sTags[7]={"<title>","<country>","<date><![CDATA[","<time><![CDATA[","<impact><![CDATA[","<forecast><![CDATA[","<previous><![CDATA["};
string eTags[7]={"</title>","</country>","]]></date>","]]></time>","]]></impact>","]]></forecast>","]]></previous>"};
double buf0[];
double buf1[];
//+-----------------------------------------------------------------------------------------------+
//| Indicator Initialization |
//+-----------------------------------------------------------------------------------------------+
int init() {
  SetIndexBuffer(0,buf0);
  SetIndexStyle(0,DRAW_LINE,STYLE_SOLID);
  SetIndexBuffer(1,buf1);
  SetIndexStyle(1,DRAW_LINE,STYLE_SOLID);
//Get current time frame
//Make sure we are connected. Otherwise exit. 
//With the first DLL call below, the program will exit (and stop) automatically after one alert. 
if(!IsDllsAllowed())  Alert(Symbol()," ",Period(),", FFCal: Allow DLL Imports"); 
//deVries: Management of FFCal.xml Files involves setting up a search to find and delete files
//that are not of this Sunday date. This search is limited to 10 weeks back (604800 seconds). 
//Files with Sunday dates that are older will not be purged by this search and will have to be
//manually deleted by the user.
  xmlFileName=GetXmlFileName();
  for(k=calendardate;k>=calendardate-6048000;k=k-604800) {
    xmlSearchName=(StringConcatenate(TimeYear(k),"-",
    PadString(DoubleToStr(TimeMonth(k),0),"0",2),"-",
    PadString(DoubleToStr(TimeDay(k),0),"0",2),"-FFCal-News",".xml"));
    xmlHandle=FileOpen(xmlSearchName,FILE_BIN|FILE_READ);
    if(xmlHandle>=0){ //file exists. A return of -1 means file does not exist.
      FileClose(xmlHandle);
      if(xmlSearchName!=xmlFileName)FileDelete(xmlSearchName);
      }
    }
  IndicatorShortName("FFCal");
  return(0);
  }
//+-----------------------------------------------------------------------------------------------+
//| Indicator Start |
//+-----------------------------------------------------------------------------------------------+ 
int start(){
  int limit=Bars-IndicatorCounted();
//If Indicator is "Off" or chart is out of range deinitialize only once, not every tick.
  InitNews(sUrl);
//Perform remaining checks once per UpdateRateSec (Refreshing News from XML file)
//Init the buffer array to zero just in case
  ArrayInitialize(newuntilminutes,0);
//New xml file handling coding and revised parsing coding
  xmlHandle=FileOpen(xmlFileName,FILE_BIN|FILE_READ);
  if(xmlHandle>=0) {
    int size=FileSize(xmlHandle);
    sData=FileReadString(xmlHandle,size);
    FileClose(xmlHandle);
    }
//Parse the XML file looking for an event to report		
  newsIdx=0;
  tmpMinspast=10080; // (a week)
  tmpMinsfuture=10080; // (a week)
  BoEvent= 0;
  while(true)  {
    BoEvent=StringFind(sData,"<event>",BoEvent);
    if(BoEvent==-1) break;
    BoEvent+=7;
    next=StringFind(sData,"</event>",BoEvent);
    if(next == -1) break;
    myEvent = StringSubstr(sData, BoEvent, next - BoEvent);
    BoEvent = next;
    begin= 0;
    skip = false;
    for(i=0; i < 7; i++){
      mainData[newsIdx][i]="";
      next=StringFind(myEvent,sTags[i],begin);
      // Within this event, if tag not found, then it must be missing; skip it
      if(next==-1) continue;
      else  {
        // We must have found the sTag okay...
        begin= next+StringLen(sTags[i]); // Advance past the start tag
        end = StringFind(myEvent,eTags[i],begin); // Find start of end tag
        //Get data between start and end tag
        if(end>begin && end!=-1)
        {mainData[newsIdx][i]=StringSubstr(myEvent,begin,end-begin);}
        }
      }//End "for" loop
 
   //Test against filters that define whether we want to skip this particular announcement
   if(!IsNewsCurrency(Symbol(),mainData[newsIdx][COUNTRY]))    {skip=true;}
   else if((!Medium_Impact_News_On) &&   (mainData[newsIdx][IMPACT]=="Medium"))   {skip=true;}
   else if((!Low_Impact_News_On) &&    (mainData[newsIdx][IMPACT]=="Low"))     {skip=true;}
   else if((!Bank_Holiday_On) && (StringSubstr(mainData[newsIdx][TITLE],0,4)=="Bank"))      {skip=true;}
   else if(!StringSubstr(mainData[newsIdx][TITLE],0,8)=="Daylight")  {skip=true;}
   else if((mainData[newsIdx][TIME]=="All Day" && mainData[newsIdx][TIME]=="") ||    (mainData[newsIdx][TIME] == "Tentative" && mainData[newsIdx][TIME] == "") ||   (mainData[newsIdx][TIME] == ""))      {skip=true;}
   //If not skipping this event, then log time to event it into newuntilminutes
   if(!skip)     {
     //If we got this far then we need to calc the minutes until this event
     //First, convert the announcement time to seconds (in GMT)
     newsTime=MakeDateTime(mainData[newsIdx][DATE],mainData[newsIdx][TIME]);
     // Now calculate the minutes until this announcement (may be negative)
     minsTillNews=(newsTime-TimeGMT())/60;
     //If this is a Bank Holiday current or past event, 
     //then skip it by changing time to 2 days back
     if((StringFind(mainData[newsIdx][TITLE],"Bank Holiday",   StringLen(mainData[newsIdx][TITLE])-12)!=-1) && (minsTillNews<=0))     {
       minsTillNews=minsTillNews-2880;
       }
     
     if(minsTillNews<=0 && tmpMinspast>-minsTillNews) {idxOfpast=newsIdx; tmpMinspast=-minsTillNews;}
     if(minsTillNews>0 && tmpMinsfuture>minsTillNews) {idxOffuture=newsIdx; tmpMinsfuture=minsTillNews;}
     newuntilminutes[newsIdx]=minsTillNews;
     newsIdx++;
     }//End "skip" routine
   }//End "while" routine
 
  for(i=0; i<limit; i++) {
    if(idxOfpast!=-1) buf0[i]=newuntilminutes[idxOfpast];
    if(idxOfpast==-1) buf0[i]=-1440;
    if(idxOffuture!=-1) buf1[i]=newuntilminutes[idxOffuture];
    if(idxOffuture==-1) buf1[i]=1440;
    }
  return (0);
  }
 //+-----------------------------------------------------------------------------------------------+
 //| Subroutines: recoded creation and maintenance of single xml file |
 //+-----------------------------------------------------------------------------------------------+ 
 //deVries: void InitNews(string& mainData[][], string newsUrl)
void InitNews(string newsUrl) {
  if(DoFileDownLoad()) {//Added to check if the CSV file already exists
    DownLoadWebPageToFile(newsUrl); //downloading the xml file
    }
  }
//+------------------------------------------------------------------+
 //deVries: If we have recent file don't download again
bool DoFileDownLoad() {
  xmlHandle=0;
  int size;
  datetime time=TimeCurrent();
  //datetime time = TimeLocal();
 
  if(GlobalVariableCheck("Update.FF_Cal") == false)return(true);
  if((time - GlobalVariableGet("Update.FF_Cal")) > WebUpdateFreq*60)return(true);
 
  xmlFileName=GetXmlFileName();
  xmlHandle=FileOpen(xmlFileName,FILE_BIN|FILE_READ); //check if file exist 
  if(xmlHandle>=0){//when the file exists we read data
    size=FileSize(xmlHandle);
    sData=FileReadString(xmlHandle,size);
    FileClose(xmlHandle);//close it again check is done
    return(false);//file exists no need to download again
    }
  //File does not exist if FileOpen return -1 or if GetLastError = ERR_CANNOT_OPEN_FILE (4103)
  return(true); //commando true to download xml file 
  }
//+-----------------------------------------------------------------------------------------------+
//| Subroutine: getting the name of the ForexFactory .xml file |
//+-----------------------------------------------------------------------------------------------+ 
//deVries: one file for all charts! 
string GetXmlFileName() {
  calendardate=TimeLocal() -(TimeDayOfWeek(TimeLocal()) *86400);
  string fileName=(StringConcatenate(TimeYear(calendardate),"-", PadString(DoubleToStr(TimeMonth(calendardate),0),"0",2),"-", PadString(DoubleToStr(TimeDay(calendardate),0),"0",2),"-FFCal-News",".xml"));
  return(fileName); //Always a Sunday date 		
  }
//+-----------------------------------------------------------------------------------------------+
//| Subroutine: downloading the ForexFactory .xml file |
//+-----------------------------------------------------------------------------------------------+ 
//deVries: new coding replacing old "GrabWeb" coding
void DownLoadWebPageToFile(string url="http://www.forexfactory.com/ff_calendar_thisweek.xml") {
  int HttpOpen=InternetOpenW(" ",0," "," ",0);
  int HttpConnect = InternetConnectW(HttpOpen, "", 80, "", "", 3, 0, 1);
  int HttpRequest = InternetOpenUrlW(HttpOpen, url, NULL, 0, 0, 0);
  
  int read[1];
  uchar Buffer[];
  ArrayResize(Buffer,READURL_BUFFER_SIZE+1);
  string NEWS="";
  
  xmlFileName=GetXmlFileName();
  xmlHandle=FileOpen(xmlFileName,FILE_BIN|FILE_READ|FILE_WRITE);
  //File exists if FileOpen return >=0. 
  if(xmlHandle>=0) {FileClose(xmlHandle); FileDelete(xmlFileName);}
  
  //Open new XML. Write the ForexFactory page contents to a .htm file. Close new XML.
  xmlHandle=FileOpen(xmlFileName,FILE_BIN|FILE_WRITE);
  
  while(true) {
    InternetReadFile(HttpRequest,Buffer,READURL_BUFFER_SIZE,read);
    string strThisRead = CharArrayToString(Buffer,0,read[0],CP_UTF8);
    if(read[0]> 0)NEWS = NEWS + strThisRead;
    else {
      FileWriteString(xmlHandle,NEWS);
      FileClose(xmlHandle);
      //Find the XML end tag to ensure a complete page was downloaded.
      end=StringFind(NEWS,"</weeklyevents>",0);
      //If the end of file tag is not found, a return -1 (or, "end <=0" in this case), 
      //then return (false).
      if(end==-1) {Alert(Symbol()," ",Period(),", FFCal Error: File download incomplete!");}
      //Else, set global to time of last update
      else {GlobalVariableSet("Update.FF_Cal",TimeCurrent());}
      break;
      }
    }
  if(HttpRequest>0) InternetCloseHandle(HttpRequest);
  if(HttpConnect>0) InternetCloseHandle(HttpConnect);
  if(HttpOpen>0) InternetCloseHandle(HttpOpen);
  }
 //+-----------------------------------------------------------------------------------------------+
 //| Subroutine: to pad string |
 //+-----------------------------------------------------------------------------------------------+ 
string PadString(string toBePadded,string paddingChar,int paddingLength) {
  while(StringLen(toBePadded)<paddingLength)   {
    toBePadded=StringConcatenate(paddingChar,toBePadded);
    }
  return (toBePadded);
  }
 //+-----------------------------------------------------------------------------------------------+
 //| Subroutine: to ID currency even if broker has added a prefix to the symbol, and is used to |
 //| determine the news to show, based on the users external inputs selections |
 //+-----------------------------------------------------------------------------------------------+ 
 //deVries: works even when broker has attached prefix (or suffix) to the Currency, so that the
 //symbol format does not look like the standard example EURUSD or USDJPY.
 //atstrader: adds option to ignore the chart symbol pair and re-select other(s). 
bool IsNewsCurrency(string cSymbol,string fSymbol) {
  if(Show_USD_News && fSymbol == "USD"){return(true);}
  if(Show_GBP_News && fSymbol == "GBP"){return(true);}
  if(Show_EUR_News && fSymbol == "EUR"){return(true);}
  if(Show_CAD_News && fSymbol == "CAD"){return(true);}
  if(Show_AUD_News && fSymbol == "AUD"){return(true);}
  if(Show_CHF_News && fSymbol == "CHF"){return(true);}
  if(Show_JPY_News && fSymbol == "JPY"){return(true);}
  if(Show_NZD_News && fSymbol == "NZD"){return(true);}
  if(Show_CNY_News && fSymbol == "CNY"){return(true);}
  return(false);
  }
//+-----------------------------------------------------------------------------------------------+
//| Indicator Subroutine For Date/Time changed by deVries |
//+-----------------------------------------------------------------------------------------------+ 
datetime MakeDateTime(string strDate,string strTime){ //not string now datetime
  int n1stDash = StringFind(strDate, "-");
  int n2ndDash = StringFind(strDate, "-", n1stDash+1);
  
  string strMonth=StringSubstr(strDate,0,2);
  string strDay=StringSubstr(strDate,3,2);
  string strYear=StringSubstr(strDate,6,4);
  
  int nTimeColonPos=StringFind(strTime,":");
  string strHour=StringSubstr(strTime,0,nTimeColonPos);
  string strMinute= StringSubstr(strTime,nTimeColonPos+1,2);
  string strAM_PM = StringSubstr(strTime,StringLen(strTime)-2);
  
  int nHour24=StrToInteger(strHour);
  if((strAM_PM == "pm" || strAM_PM == "PM") && nHour24 != 12) {nHour24 += 12;}
  if((strAM_PM == "am" || strAM_PM == "AM") && nHour24 == 12) {nHour24 = 0;}
  
  datetime newsevent=StringToTime(strYear+"."+strMonth+"."+
  strDay)+nHour24*3600+(StringToInteger(strMinute)*60);
  return(newsevent);
  }
//+------------------------------------------------------------------+
 