//+------------------------------------------------------------------+
//|                         WeightLoader.mqh                         |
//|                       https://www.mql5.com                       |
//+------------------------------------------------------------------+
#property copyright "Olamide Adebayo"
#property link      "https://www.mql5.com"

#include "BenchmarkConfig.mqh"

//+------------------------------------------------------------------+
//| CWeightLoader                                                    |
//| Reads the tagged-section CSV written by train_export_model.py:   |
//|   #W1,8,16                                                       |
//|   v0,v1,...,v127                                                 |
//|   #b1,1,16                                                       |
//|   v0,...,v15                                                     |
//| and so on for W2/b2 and W3/b3. Each section header is checked    |
//| against the BENCH_* constants before any value is accepted, so a |
//| truncated or reshaped export fails here and not three layers on. |
//+------------------------------------------------------------------+
class CWeightLoader
  {
public:
   double            W1[]; double b1[];   // 8x16, 16
   double            W2[]; double b2[];   // 16x8, 8
   double            W3[]; double b3[];   // 8x1,  1
   bool              m_loaded;

                     CWeightLoader(void) : m_loaded(false) {}

//+------------------------------------------------------------------+
//| CWeightLoader::Load                                              |
//+------------------------------------------------------------------+
   bool              Load(const string filename)
     {
      int fh = FileOpen(filename, FILE_READ | FILE_CSV | FILE_ANSI, ',');
      if(fh == INVALID_HANDLE)
        {
         PrintFormat("[WeightLoader] failed to open %s, error %d", filename, GetLastError());
         return false;
        }

      bool ok = ReadSection(fh, "#W1", BENCH_INPUT_DIM,   BENCH_HIDDEN1_DIM, W1) &&
                ReadSection(fh, "#b1", 1,                 BENCH_HIDDEN1_DIM, b1) &&
                ReadSection(fh, "#W2", BENCH_HIDDEN1_DIM, BENCH_HIDDEN2_DIM, W2) &&
                ReadSection(fh, "#b2", 1,                 BENCH_HIDDEN2_DIM, b2) &&
                ReadSection(fh, "#W3", BENCH_HIDDEN2_DIM, BENCH_OUTPUT_DIM,  W3) &&
                ReadSection(fh, "#b3", 1,                 BENCH_OUTPUT_DIM,  b3);

      FileClose(fh);
      m_loaded = ok;
      if(ok)
         Print("[WeightLoader] all sections loaded and dimension-checked OK");
      return ok;
     }

private:
//+------------------------------------------------------------------+
//| CWeightLoader::ReadSection                                       |
//+------------------------------------------------------------------+
   bool              ReadSection(int fh, const string tag, const int rows, const int cols, double &dest[])
     {
      string header_tag = FileReadString(fh);
      int    header_rows = (int)FileReadNumber(fh);
      int    header_cols = (int)FileReadNumber(fh);

      if(header_tag != tag)
        {
         PrintFormat("[WeightLoader] expected tag %s, got %s", tag, header_tag);
         return false;
        }
      if(header_rows != rows || header_cols != cols)
        {
         PrintFormat("[WeightLoader] %s dimension mismatch: file says %dx%d, config expects %dx%d",
                     tag, header_rows, header_cols, rows, cols);
         return false;
        }

      int total = rows * cols;
      ArrayResize(dest, total);
      for(int i = 0; i < total; i++)
        {
         if(FileIsEnding(fh))
           {
            PrintFormat("[WeightLoader] %s truncated at element %d/%d", tag, i, total);
            return false;
           }
         dest[i] = FileReadNumber(fh);
        }
      return true;
     }
  };
