//+------------------------------------------------------------------+
//|                                            CurrencyExtractor.mqh |
//+------------------------------------------------------------------+
#ifndef CURRENCYEXTRACTOR_MQH
#define CURRENCYEXTRACTOR_MQH

//+------------------------------------------------------------------+
//| CCurrencyExtractor                                               |
//| Implements the currency filter primitives: extracts the base and |
//| quote currencies from a symbol name after stripping any broker   |
//| suffix, and matches an event currency against either side.       |
//+------------------------------------------------------------------+
class CCurrencyExtractor
  {
private:
   string            StripSuffix(const string symbol) const;

public:
                     CCurrencyExtractor(void);
                    ~CCurrencyExtractor(void);

   string            GetBaseCurrency(const string symbol) const;
   string            GetQuoteCurrency(const string symbol) const;
   bool              MatchesCurrency(const string symbol, const string currency) const;
  };

//+------------------------------------------------------------------+
//| Constructor: The class is stateless, so nothing to initialize.   |
//+------------------------------------------------------------------+
CCurrencyExtractor::CCurrencyExtractor(void)
  {
  }

//+------------------------------------------------------------------+
//| Destructor: No resources are owned, so nothing to release.       |
//+------------------------------------------------------------------+
CCurrencyExtractor::~CCurrencyExtractor(void)
  {
  }

//+------------------------------------------------------------------+
//| StripSuffix                                                      |
//| Returns the symbol reduced to its currency-pair core: keeps the  |
//| leading alphabetic run (dropping suffixes like ".c" or ".pro"),  |
//| truncates alphabetic suffixes like the "m" in "EURUSDm" down to  |
//| six characters, and uppercases the result.                       |
//+------------------------------------------------------------------+
string CCurrencyExtractor::StripSuffix(const string symbol) const
  {
//--- collect leading alphabetic characters only
   string clean  = "";
   int    length = ::StringLen(symbol);
   for(int i = 0; i < length; i++)
     {
      ushort ch = ::StringGetCharacter(symbol, i);
      //--- stop at the first non-alphabetic character
      bool is_alpha = (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
      if(!is_alpha)
         break;
      clean += ::ShortToString(ch);
     }
//--- truncate alphabetic suffixes such as the "m" in "EURUSDm"
   if(::StringLen(clean) > 6)
      clean = ::StringSubstr(clean, 0, 6);
//--- uppercase for comparison against CSV currency codes
   ::StringToUpper(clean);
   return(clean);
  }

//+------------------------------------------------------------------+
//| GetBaseCurrency                                                  |
//| Returns the base currency of a symbol by extracting the first    |
//| three characters after the suffix has been stripped.             |
//+------------------------------------------------------------------+
string CCurrencyExtractor::GetBaseCurrency(const string symbol) const
  {
//--- strip any broker suffix before extracting
   string clean = StripSuffix(symbol);
   if(::StringLen(clean) < 6)
      return("");
//--- the base currency is characters 0 through 2
   return(::StringSubstr(clean, 0, 3));
  }

//+------------------------------------------------------------------+
//| GetQuoteCurrency                                                 |
//| Returns the quote currency of a symbol by extracting characters  |
//| three through five after the suffix has been stripped.           |
//+------------------------------------------------------------------+
string CCurrencyExtractor::GetQuoteCurrency(const string symbol) const
  {
//--- strip any broker suffix before extracting
   string clean = StripSuffix(symbol);
   if(::StringLen(clean) < 6)
      return("");
//--- the quote currency is characters 3 through 5
   return(::StringSubstr(clean, 3, 3));
  }

//+------------------------------------------------------------------+
//| MatchesCurrency                                                  |
//| Returns true when the given currency code equals either the base |
//| or the quote currency of the symbol. This is the currency filter |
//| decision used by the checker and the drawer.                     |
//+------------------------------------------------------------------+
bool CCurrencyExtractor::MatchesCurrency(const string symbol, const string currency) const
  {
//--- normalize the event currency for comparison
   string wanted = currency;
   ::StringToUpper(wanted);
//--- match against either side of the pair
   if(GetBaseCurrency(symbol) == wanted)
      return(true);
   if(GetQuoteCurrency(symbol) == wanted)
      return(true);
   return(false);
  }

#endif // CURRENCYEXTRACTOR_MQH
//+------------------------------------------------------------------+