/* Blinker
   Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
   a blinkenarea.org project */

#include <string>

#include <BlinkenLib/BlinkenFrame.h>

#include "Canvas.h"
#include "CanvasInput.h"
#include "Directory.h"
#include "File.h"
#include "InStreamFile.h"
#include "Position.h"
#include "PositionFile.h"
#include "Size.h"
#include "SizeFile.h"
#include "StreamMgr.h"
#include "StreamRecv.h"

namespace Blinker {

/**
 * @brief constructor
 * @param[in] canvas owning canvas
 * @param[in] name name of input
 * @param[in] dirBase base directory
 */
Canvas::Input::Input(Canvas &canvas, const std::string &name,
                     const Directory &dirBase):
  m_canvas(canvas),
  m_name(name),
  m_fileInStream(dirBase.getFile("instream"), canvas.m_mgrs.m_streamMgr),
  m_fileSrcPos(dirBase.getFile("srcpos")),
  m_fileSize(dirBase.getFile("size")),
  m_fileDestPos(dirBase.getFile("destpos"))
{
  // set up
  getSrcPos();
  getSize();
  getDestPos();
  m_fileInStream.setStreamRecv(this);
}

/// virtual destructor
Canvas::Input::~Input()
{
  // clean up
  m_fileInStream.setStreamRecv(NULL);
}

/// check for update of configuration
void Canvas::Input::updateConfig()
{
  // input stream name file was modified -> re-get input stream
  if (m_fileInStream.checkModified()) {
    m_fileInStream.update();
    m_canvas.redraw(); // notify canvas to redraw
  }

  // position/size files were modified -> re-get position/size
  if (m_fileSrcPos.checkModified())
    getSrcPos();
  if (m_fileSize.checkModified())
    getSize();
  if (m_fileDestPos.checkModified())
    getDestPos();
}

/**
 * @brief set current frame
 * @param[in] stream stream name
 * @param[in] pFrame current frame (NULL for none)
 */
void Canvas::Input::setFrame(const std::string &stream, stBlinkenFrame *pFrame)
{
  // notify canvas to redraw
  m_canvas.redraw();

  (void)pFrame; // unused (frame fetched from stream when requested to draw)
  (void)stream; // unused
}

/**
 * @brief draw current frame to canvas
 * @return if a frame was available and it was drawn
 */
bool Canvas::Input::draw()
{
  stBlinkenFrame *pFrame;
  int destx, desty, srcx, srcy, width, height;

  // no destination position or no canvas -> leave
  if (!m_fileDestPos.m_valid || !m_canvas.m_pCanvas)
    return false;
  destx = m_fileDestPos.m_obj.m_x;
  desty = m_fileDestPos.m_obj.m_y;

  // get current frame from stream (leave if no stream or no frame)
  pFrame = m_fileInStream.getCurFrame();
  if (!pFrame)
    return false;

  // no source position -> use top left
  if (m_fileSrcPos.m_valid) {
    srcx = m_fileSrcPos.m_obj.m_x;
    srcy = m_fileSrcPos.m_obj.m_y;
  } else {
    srcx = 0;
    srcy = 0;
  }

  // no size -> use entire source frame
  //            (BlinkenLib will clip this if too large)
  if (m_fileSize.m_valid) {
    width = m_fileSize.m_obj.m_width;
    height = m_fileSize.m_obj.m_height;
  } else {
    width = BlinkenFrameGetWidth(pFrame);
    height = BlinkenFrameGetHeight(pFrame);
  }

  // draw rectangular area to canvas
  BlinkenFrameCopyRect(m_canvas.m_pCanvas, desty, destx,
                       pFrame, srcy, srcx, height, width);

  return true;
}

/// (re-)get position of area to copy from stream
void Canvas::Input::getSrcPos()
{
  // read source position from file
  m_fileSrcPos.update();

  // notify canvas to redraw
  m_canvas.redraw();
}

/// (re-)get size of area to copy from stream
void Canvas::Input::getSize()
{
  // read size from file
  m_fileSize.update();

  // notify canvas to redraw
  m_canvas.redraw();
}

/// (re-)get destination position on canvas
void Canvas::Input::getDestPos()
{
  // read destination position from file
  m_fileDestPos.update();

  // notify canvas to redraw
  m_canvas.redraw();
}

} // namespace Blinker

