//+------------------------------------------------------------------+
//|                                                MarketBookOrd.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Класс абстрактной заявки стакана цен                             |
//+------------------------------------------------------------------+
class CMarketBookOrd : public CBaseObj
  {
private:
   int               m_digits;                                       // Количество знаков после запятой
   long              m_long_prop[MBOOK_ORD_PROP_INTEGER_TOTAL];      // Целочисленные свойства
   double            m_double_prop[MBOOK_ORD_PROP_DOUBLE_TOTAL];     // Вещественные свойства
   string            m_string_prop[MBOOK_ORD_PROP_STRING_TOTAL];     // Строковые свойства

//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство
   int               IndexProp(ENUM_MBOOK_ORD_PROP_DOUBLE property)  const { return(int)property-MBOOK_ORD_PROP_INTEGER_TOTAL;                              }
   int               IndexProp(ENUM_MBOOK_ORD_PROP_STRING property)  const { return(int)property-MBOOK_ORD_PROP_INTEGER_TOTAL-MBOOK_ORD_PROP_DOUBLE_TOTAL;  }

public:
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство объекта
   void              SetProperty(ENUM_MBOOK_ORD_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                      }
   void              SetProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;    }
   void              SetProperty(ENUM_MBOOK_ORD_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;    }
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство объекта
   long              GetProperty(ENUM_MBOOK_ORD_PROP_INTEGER property)        const { return this.m_long_prop[property];                     }
   double            GetProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];   }
   string            GetProperty(ENUM_MBOOK_ORD_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];   }
//--- Возвращает себя
   CMarketBookOrd   *GetObject(void)                                                { return &this;}

//--- Возвращает флаг поддержания объектом данного свойства
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property)          { return true; }
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property)           { return true; }
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_STRING property)           { return true; }

//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства
   string            GetPropertyDescription(ENUM_MBOOK_ORD_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_MBOOK_ORD_PROP_STRING property);

//--- Выводит в журнал описание свойств объекта (full_prop=true - все свойства, false - только поддерживаемые - реализуется в наследниках класса)
   virtual void      Print(const bool full_prop=false,const bool dash=false);
//--- Выводит в журнал краткое описание объекта
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);
//--- Возвращает краткое наименование объекта
   virtual string    Header(const bool symbol=false);
   
//--- Сравнивает объекты CMarketBookOrd между собой по указанному свойству (для сортировки списка по свойству объекта-запроса)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Сравнивает объекты CMarketBookOrd между собой по всем свойствам (для поиска равных объектов-запросов)
   bool              IsEqual(CMarketBookOrd* compared_req) const;
   
//--- Конструктор по умолчанию
                     CMarketBookOrd(){ this.m_type=OBJECT_DE_TYPE_BOOK_ORDER; }
protected:
//--- Защищённый параметрический конструктор
                     CMarketBookOrd(const ENUM_MBOOK_ORD_STATUS status,const MqlBookInfo &book_info,const string symbol);
                     
public:
//+------------------------------------------------------------------+ 
//|Методы упрощённого доступа к свойствам объекта-запроса стакана цен|
//+------------------------------------------------------------------+
//--- Устанавливает время снимка - все заявки одного снимка стакана цен имеют одинаковое время
   void              SetTime(const long time_msc)  { this.SetProperty(MBOOK_ORD_PROP_TIME_MSC,time_msc);                      }
   
//--- Возвращает (1) статус, (2) тип, (3) объём заявки
   ENUM_MBOOK_ORD_STATUS Status(void)        const { return (ENUM_MBOOK_ORD_STATUS)this.GetProperty(MBOOK_ORD_PROP_STATUS);   }
   ENUM_BOOK_TYPE    TypeOrd(void)           const { return (ENUM_BOOK_TYPE)this.GetProperty(MBOOK_ORD_PROP_TYPE);            }
   long              Volume(void)            const { return this.GetProperty(MBOOK_ORD_PROP_VOLUME);                          }
//--- Возвращает (1) цену, (2) объём заявки с повышенной точностью
   double            Price(void)             const { return this.GetProperty(MBOOK_ORD_PROP_PRICE);                           }
   double            VolumeReal(void)        const { return this.GetProperty(MBOOK_ORD_PROP_VOLUME_REAL);                     }
//--- Возвращает (1) символ заявки, (2) Digits символа
   string            Symbol(void)            const { return this.GetProperty(MBOOK_ORD_PROP_SYMBOL);                          }
   int               Digits()                const { return this.m_digits;                                                    }
   
//--- Возвращает описание (1) типа (ENUM_BOOK_TYPE), (2) статуса (ENUM_MBOOK_ORD_STATUS) заявки
   virtual string    TypeDescription(void)   const { return this.StatusDescription();                                         }
   string            StatusDescription(void) const;

  };
//+------------------------------------------------------------------+
//| Защищённый параметрический конструктор                           |
//+------------------------------------------------------------------+
CMarketBookOrd::CMarketBookOrd(const ENUM_MBOOK_ORD_STATUS status,const MqlBookInfo &book_info,const string symbol)
  {
   this.m_type=OBJECT_DE_TYPE_BOOK_ORDER;
//--- Сохраняем Digits символа
   this.m_digits=(int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS);
//--- Сохраняем целочисленные свойства объекта
   this.SetProperty(MBOOK_ORD_PROP_STATUS,status);
   this.SetProperty(MBOOK_ORD_PROP_TYPE,book_info.type);
   this.SetProperty(MBOOK_ORD_PROP_VOLUME,book_info.volume);
//--- Сохраняем вещественные свойства объекта
   this.SetProperty(MBOOK_ORD_PROP_PRICE,book_info.price);
   this.SetProperty(MBOOK_ORD_PROP_VOLUME_REAL,book_info.volume_real);
//--- Сохраняем дополнительные свойства объекта
   this.SetProperty(MBOOK_ORD_PROP_SYMBOL,(symbol==NULL || symbol=="" ? ::Symbol() : symbol));
//--- Время заявки отсутствует в параметрах, и оно учитывается в классе снимка стакана цен. Обнуляем время
   this.SetProperty(MBOOK_ORD_PROP_TIME_MSC,0);
  }
//+------------------------------------------------------------------+
//| Сравнивает объекты CMarketBookOrd                                |
//| между собой по указанному свойству                               |
//+------------------------------------------------------------------+
int CMarketBookOrd::Compare(const CObject *node,const int mode=0) const
  {
   const CMarketBookOrd *obj_compared=node;
//--- сравнение целочисленных свойств двух объектов
   if(mode<MBOOK_ORD_PROP_INTEGER_TOTAL)
     {
      long value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- сравнение вещественных свойств двух объектов
   else if(mode<MBOOK_ORD_PROP_DOUBLE_TOTAL+MBOOK_ORD_PROP_INTEGER_TOTAL)
     {
      double value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- сравнение строковых свойств двух объектов
   else if(mode<MBOOK_ORD_PROP_DOUBLE_TOTAL+MBOOK_ORD_PROP_INTEGER_TOTAL+MBOOK_ORD_PROP_STRING_TOTAL)
     {
      string value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+
//| Сравнивает объекты CMarketBookOrd между собой по всем свойствам  |
//+------------------------------------------------------------------+
bool CMarketBookOrd::IsEqual(CMarketBookOrd *compared_obj) const
  {
   int beg=0, end=MBOOK_ORD_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_INTEGER prop=(ENUM_MBOOK_ORD_PROP_INTEGER)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=MBOOK_ORD_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_DOUBLE prop=(ENUM_MBOOK_ORD_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=MBOOK_ORD_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_STRING prop=(ENUM_MBOOK_ORD_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+
//| Выводит в журнал свойства объекта                                |
//+------------------------------------------------------------------+
void CMarketBookOrd::Print(const bool full_prop=false,const bool dash=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int beg=0, end=MBOOK_ORD_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_INTEGER prop=(ENUM_MBOOK_ORD_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=MBOOK_ORD_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_DOUBLE prop=(ENUM_MBOOK_ORD_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=MBOOK_ORD_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_STRING prop=(ENUM_MBOOK_ORD_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n");
  }
//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства объекта              |
//+------------------------------------------------------------------+
string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_INTEGER property)
  {
   return
     (
      property==MBOOK_ORD_PROP_STATUS        ?  CMessage::Text(MSG_ORD_STATUS)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.StatusDescription()
         )  :
      property==MBOOK_ORD_PROP_TYPE          ?  CMessage::Text(MSG_ORD_TYPE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.TypeDescription()
         )  :
      property==MBOOK_ORD_PROP_VOLUME        ?  CMessage::Text(MSG_MBOOK_ORD_VOLUME)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание вещественного свойства объекта               |
//+------------------------------------------------------------------+
string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_DOUBLE property)
  {
   int dg=(this.m_digits>0 ? this.m_digits : 1);
   return
     (
      property==MBOOK_ORD_PROP_PRICE         ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==MBOOK_ORD_PROP_VOLUME_REAL   ?  CMessage::Text(MSG_MBOOK_ORD_VOLUME_REAL)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание строкового свойства объекта                  |
//+------------------------------------------------------------------+
string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_STRING property)
  {
   return(property==MBOOK_ORD_PROP_SYMBOL ? CMessage::Text(MSG_LIB_PROP_SYMBOL)+": \""+this.GetProperty(property)+"\"" : "");
  }
//+------------------------------------------------------------------+
//| Возвращает краткое наименование объекта                          |
//+------------------------------------------------------------------+
string CMarketBookOrd::Header(const bool symbol=false)
  {
   return this.TypeDescription()+(symbol ? " \""+this.Symbol()+"\"" : "");
  }
//+------------------------------------------------------------------+
//| Выводит в журнал краткое описание объекта                        |
//+------------------------------------------------------------------+
void CMarketBookOrd::PrintShort(const bool dash=false,const bool symbol=false)
  {
   ::Print(this.Header(symbol));
  }
//+------------------------------------------------------------------+
//| Возвращает описание статуса заявки в стакане цен                 |
//+------------------------------------------------------------------+
string CMarketBookOrd::StatusDescription(void) const
  {
   return
     (
      Status()==MBOOK_ORD_STATUS_SELL  ?  CMessage::Text(MSG_MBOOK_ORD_STATUS_SELL) :
      Status()==MBOOK_ORD_STATUS_BUY   ?  CMessage::Text(MSG_MBOOK_ORD_STATUS_BUY)  :
      ""
     );
  }
//+------------------------------------------------------------------+
