text: #include "Marques.hpp"
  
  #include <core/logger/event_logger.h>
  
  namespace
  {
      const char *DOMAIN = "marques";
  
      const util::graphics::Color WHITE(0xFFFFFFFF);
      const util::graphics::Color BLACK(0);
  
      uint8_t font8x8[95][8] = {
          {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // space
          {0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // !
          {0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // "
          {0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // #
          {0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // $
          {0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // %
          {0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // &
          {0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // '
          {0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // (
          {0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // )
          {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // *
          {0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // +
          {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // ,
          {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // -
          {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // .
          {0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // /
          {0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // 0
          {0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // 1
          {0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // 2
          {0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // 3
          {0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // 4
          {0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // 5
          {0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // 6
          {0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // 7
          {0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // 8
          {0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // 9
          {0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // :
          {0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // ,)
          {0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // <
          {0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // =
          {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // >
          {0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // ?
          {0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // @
          {0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // A
          {0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // B
          {0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // C
          {0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // D
          {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // E
          {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // F
          {0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // G
          {0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // H
          {0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // I
          {0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // J
          {0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // K
          {0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // L
          {0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // M
          {0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // N
          {0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // O
          {0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // P
          {0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // Q
          {0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // R
          {0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // S
          {0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // T
          {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U
          {0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // V
          {0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // W
          {0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // X
          {0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // Y
          {0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // Z
          {0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // [
          {0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // '\'
          {0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // ]
          {0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // ^
          {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // _
          {0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // `
          {0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // a
          {0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // b
          {0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // c
          {0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // d
          {0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // e
          {0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // f
          {0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // g
          {0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // h
          {0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // i
          {0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // j
          {0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // k
          {0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // l
          {0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // m
          {0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // n
          {0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // o
          {0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // p
          {0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // q
          {0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // r
          {0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // s
          {0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // t
          {0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // u
          {0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // v
          {0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // w
          {0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // x
          {0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // y
          {0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // z
          {0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // {
          {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // |
          {0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // }
          {0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}  // ~
      };
  }
  
  Marques Marques::_prototype;
  
  Marques::Marques() :
      m_currentIndex(0),
      m_currentIteration(0),
      m_updatePeriodMs(0),
      m_enabled(false),
      m_cubeData(8)
  {
      addPrototype(DOMAIN, this);
  }
  
  Marques *Marques::clone() const
  {
      return new Marques(*this);
  }
  
  void Marques::init(const boost::property_tree::ptree::value_type& component)
  {
      auto config = component.second;
  
      uint32_t cubeSize = m_cubeData.size();
  
      cubeSize = config.get<uint32_t>("cube-size", cubeSize);
      m_updatePeriodMs = config.get<uint32_t>("update-rate-ms", m_updatePeriodMs);
      m_enabled = config.get<bool>("enabled", m_enabled);
      m_text = config.get<std::string>("text");
  
      if (m_cubeData.size() != cubeSize)
      {
          m_cubeData.resize(cubeSize);
      }
  }
  
  void Marques::stop()
  {
      cancelTimer(m_timerId);
  }
  
  void Marques::start()
  {
      clearCube();
  
      if (m_enabled)
      {
          if (m_updatePeriodMs > 0)
          {
              m_timerId = setPeriodicTimer(
                  std::bind(&Marques::update, this, std::placeholders::_1),
                  std::chrono::milliseconds(m_updatePeriodMs));
          }
      }
  }
  
  void Marques::update(const boost::system::error_code &e)
  {
      if (m_currentIteration == 0)
      {
          if (m_currentIndex >= m_text.length())
          {
              clearCube();
              m_currentIteration = (m_cubeData.size() - 1) * 2;
          }
          else
          {
              char currentChar = m_text.at(m_currentIndex);
              LOG_INFO(DOMAIN, "Displaying character: %c", currentChar);
              
              if (currentChar >= 33 and currentChar <= 126)
              {
                  uint8_t* matrix = font8x8[currentChar - 32];
                  for (uint8_t i = 0; i < m_cubeData.size(); ++i)
                  {
                      for(uint8_t j = 0; j < m_cubeData.size(); ++j)
                      {
                          uint32_t bit = 1 << (m_cubeData.size() - i - 1);
                          uint8_t representation = matrix[m_cubeData.size() - j - 1];
  
                          if (bit & representation)
                          {
                              m_cubeData(i, j, 0) = WHITE;
                          }
                      }
                  }
              }
              else
              {
                  // Unknown char or space
                  clearCube();
                  m_currentIteration = (m_cubeData.size() - 1) * 2;
              }
          }
      }
      else if (m_currentIteration < m_cubeData.size())
      {
          for (uint8_t i = 0; i < m_cubeData.size(); ++i)
          {
              for(uint8_t j = 0; j < m_cubeData.size(); ++j)
              {
                  m_cubeData(i, j, m_currentIteration) = m_cubeData(i, j, m_currentIteration - 1);
              }
          }
      }
      else if (m_currentIteration < 2 * m_cubeData.size())
      {
          for (uint8_t i = 0; i < m_cubeData.size(); ++i)
          {
              for(uint8_t j = 0; j < m_cubeData.size(); ++j)
              {
                  m_cubeData(i, j, m_currentIteration - m_cubeData.size()) = BLACK;
              }
          }
      }
      else
      {
          m_currentIteration = -1;
          if (m_currentIndex >= m_text.length())
          {
              m_currentIndex = 0;
          }
          else
          {
              m_currentIndex++;
          }
      }
  
      m_currentIteration++;
  
      core::MessageData attr;
      attr.set("data", m_cubeData.toString());
      post("updateCube", attr);
  }
  
  void Marques::clearCube()
  {
      for (int i =0; i < m_cubeData.size(); ++i)
      {
          for(uint8_t j = 0; j < m_cubeData.size(); ++j)
          {
              for(uint8_t l = 0; l < m_cubeData.size(); ++l)
              {
                  m_cubeData(i, j, l) = BLACK;
              }
          }
      }
  }