//+------------------------------------------------------------------+
//|                                               PositionRecord.mqh |
//+------------------------------------------------------------------+
#ifndef POSITIONRECORD_MQH
#define POSITIONRECORD_MQH

#include "LadderLevel.mqh"

#define PCE_MAX_LADDER_LEVELS 8

//+------------------------------------------------------------------+
//| CPositionRecord                                                  |
//| Stores everything the engine needs to remember about a single    |
//| registered position. All values that must stay fixed across the  |
//| life of the trade (original volume, original entry, original SL, |
//| original R) are captured once at registration time and are never |
//| re-read from the live position on subsequent ticks. This is what |
//| protects the engine from the compounding error that occurs when  |
//| later ladder levels are computed off a volume or SL that has     |
//| already been changed by an earlier partial close.                |
//+------------------------------------------------------------------+
class CPositionRecord
  {
private:
   ulong             m_ticket;
   string            m_symbol;
   long              m_type;
   double            m_original_volume;
   double            m_original_entry_price;
   double            m_original_sl;
   double            m_original_r;
   CLadderLevel      m_levels[PCE_MAX_LADDER_LEVELS];
   int               m_level_count;
   string            m_object_names[PCE_MAX_LADDER_LEVELS];
   int               m_object_count;

public:
                     CPositionRecord(void);
                    ~CPositionRecord(void);

   void              Init(const ulong ticket,
                          const string symbol,
                          const long type,
                          const double original_volume,
                          const double original_entry_price,
                          const double original_sl,
                          const double original_r);

   ulong             Ticket(void) const { return(m_ticket); }
   string            Symbol(void) const { return(m_symbol); }
   long              Type(void) const { return(m_type); }
   double            OriginalVolume(void) const { return(m_original_volume); }
   double            OriginalEntryPrice(void) const { return(m_original_entry_price); }
   double            OriginalSl(void) const { return(m_original_sl); }
   double            OriginalR(void) const { return(m_original_r); }

   void              AddLevel(const CLadderLevel &level);
   int               LevelCount(void) const { return(m_level_count); }
   CLadderLevel      *Level(const int index);

   void              AddObjectName(const string name);
   int               ObjectCount(void) const { return(m_object_count); }
   string            ObjectName(const int index) const;
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CPositionRecord::CPositionRecord(void)
  {
   m_ticket               = 0;
   m_symbol               = "";
   m_type                 = 0;
   m_original_volume      = 0.0;
   m_original_entry_price = 0.0;
   m_original_sl          = 0.0;
   m_original_r           = 0.0;
   m_level_count          = 0;
   m_object_count         = 0;
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CPositionRecord::~CPositionRecord(void)
  {
  }

//+------------------------------------------------------------------+
//| Init                                                             |
//| Captures the immutable state of a position at registration time. |
//+------------------------------------------------------------------+
void CPositionRecord::Init(const ulong ticket,
                           const string symbol,
                           const long type,
                           const double original_volume,
                           const double original_entry_price,
                           const double original_sl,
                           const double original_r)
  {
   m_ticket               = ticket;
   m_symbol               = symbol;
   m_type                 = type;
   m_original_volume      = original_volume;
   m_original_entry_price = original_entry_price;
   m_original_sl          = original_sl;
   m_original_r           = original_r;
   m_level_count          = 0;
   m_object_count         = 0;
  }

//+------------------------------------------------------------------+
//| AddLevel                                                         |
//| Appends a ladder level to this position's rung array.            |
//+------------------------------------------------------------------+
void CPositionRecord::AddLevel(const CLadderLevel &level)
  {
   if(m_level_count >= PCE_MAX_LADDER_LEVELS)
     {
      //--- ladder array is full, refuse silently rather than overrun
      return;
     }
   m_levels[m_level_count] = level;
   m_level_count++;
  }

//+------------------------------------------------------------------+
//| Level                                                            |
//| Returns a pointer to the ladder level at the given index.        |
//+------------------------------------------------------------------+
CLadderLevel *CPositionRecord::Level(const int index)
  {
   if(index < 0 || index >= m_level_count)
      return(NULL);
   return(GetPointer(m_levels[index]));
  }

//+------------------------------------------------------------------+
//| AddObjectName                                                    |
//| Records the name of a chart object created for this position so  |
//| it can be cleaned up later during Deregister().                  |
//+------------------------------------------------------------------+
void CPositionRecord::AddObjectName(const string name)
  {
   if(m_object_count >= PCE_MAX_LADDER_LEVELS)
     {
      //--- object name array is full, refuse silently rather than overrun
      return;
     }
   m_object_names[m_object_count] = name;
   m_object_count++;
  }

//+------------------------------------------------------------------+
//| ObjectName                                                       |
//| Returns the chart object name at the given index.                |
//+------------------------------------------------------------------+
string CPositionRecord::ObjectName(const int index) const
  {
   if(index < 0 || index >= m_object_count)
      return("");
   return(m_object_names[index]);
  }

#endif // POSITIONRECORD_MQH
//+------------------------------------------------------------------+