/** \file
 * \brief Progress bar Control - Qt implementation
 *
 * See Copyright Notice in "iup.h"
 */

#include <QProgressBar>
#include <QWidget>

extern "C" {
#include "iup.h"
#include "iup_object.h"
#include "iup_attrib.h"
#include "iup_str.h"
#include "iup_progressbar.h"
}

#include "iupqt_drv.h"


/****************************************************************************
 * Min Size Calculation
 ****************************************************************************/

extern "C" IUP_SDK_API void iupdrvProgressBarGetMinSize(Ihandle* ih, int *w, int *h)
{
  static int horiz_min_w = -1, horiz_min_h = -1;
  static int vert_min_w = -1, vert_min_h = -1;

  if (horiz_min_w < 0)
  {
    QProgressBar temp_horiz(nullptr);
    QProgressBar temp_vert(nullptr);

    temp_horiz.setOrientation(Qt::Horizontal);
    temp_vert.setOrientation(Qt::Vertical);

    QSize horiz_hint = temp_horiz.minimumSizeHint();
    QSize vert_hint = temp_vert.minimumSizeHint();

    horiz_min_w = horiz_hint.width();
    horiz_min_h = horiz_hint.height();
    vert_min_w = vert_hint.width();
    vert_min_h = vert_hint.height();

    if (horiz_min_w < 1) horiz_min_w = 100;
    if (horiz_min_h < 1) horiz_min_h = 20;
    if (vert_min_w < 1) vert_min_w = 20;
    if (vert_min_h < 1) vert_min_h = 100;
  }

  if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL"))
  {
    *w = vert_min_w;
    *h = vert_min_h;
  }
  else
  {
    *w = horiz_min_w;
    *h = horiz_min_h;
  }
}

/****************************************************************************
 * Attribute Setters
 ****************************************************************************/

static int qtProgressBarSetMarqueeAttrib(Ihandle* ih, const char* value)
{
  if (!ih->data->marquee)
    return 0;

  QProgressBar* pbar = (QProgressBar*)ih->handle;
  if (!pbar)
    return 0;

  if (iupStrBoolean(value))
    pbar->setRange(0, 0);
  else
  {
    pbar->setRange(0, 1000);
    pbar->setValue(0);
  }

  return 1;
}

static int qtProgressBarSetValueAttrib(Ihandle* ih, const char* value)
{
  QProgressBar* pbar = (QProgressBar*)ih->handle;

  if (ih->data->marquee)
    return 0;

  if (!value)
    ih->data->value = 0;
  else
    iupStrToDouble(value, &(ih->data->value));

  iProgressBarCropValue(ih);

  if (pbar)
  {
    /* Map value from [vmin, vmax] to [0, 1000] for precision */
    double range = ih->data->vmax - ih->data->vmin;
    if (range != 0)
    {
      double fraction = (ih->data->value - ih->data->vmin) / range;
      int int_value = (int)(fraction * 1000.0);
      pbar->setValue(int_value);
    }
    else
      pbar->setValue(0);
  }

  return 0;
}

static int qtProgressBarSetMinAttrib(Ihandle* ih, const char* value)
{
  if (iupStrToDouble(value, &(ih->data->vmin)))
  {
    qtProgressBarSetValueAttrib(ih, nullptr);
  }
  return 0;
}

static int qtProgressBarSetMaxAttrib(Ihandle* ih, const char* value)
{
  if (iupStrToDouble(value, &(ih->data->vmax)))
  {
    qtProgressBarSetValueAttrib(ih, nullptr);
  }
  return 0;
}

static char* qtProgressBarGetMinAttrib(Ihandle* ih)
{
  return iupStrReturnDouble(ih->data->vmin);
}

static char* qtProgressBarGetMaxAttrib(Ihandle* ih)
{
  return iupStrReturnDouble(ih->data->vmax);
}

static void qtProgressBarApplyChunkStyle(Ihandle* ih)
{
  QProgressBar* pbar = (QProgressBar*)ih->handle;
  if (!pbar)
    return;

  QString rules;
  unsigned char r, g, b;
  char* fg = iupAttribGet(ih, "FGCOLOR");
  int has_fg = fg && iupStrToRGB(fg, &r, &g, &b);
  if (has_fg)
    rules += QString("background-color: rgb(%1,%2,%3); ").arg(r).arg(g).arg(b);
  if (ih->data->dashed)
  {
    /* QStyleSheetStyle skips chunked drawing unless ::chunk has hasDrawable() true */
    if (!has_fg)
    {
      QColor hl = pbar->palette().color(QPalette::Highlight);
      rules += QString("background-color: rgb(%1,%2,%3); ").arg(hl.red()).arg(hl.green()).arg(hl.blue());
    }
    rules += QString("width: 10px; margin: 1px; ");
  }

  if (rules.isEmpty())
    pbar->setStyleSheet(QString());
  else
    pbar->setStyleSheet(QString("QProgressBar::chunk { %1}").arg(rules));
}

static int qtProgressBarSetDashedAttrib(Ihandle* ih, const char* value)
{
  if (ih->data->marquee)
    return 0;

  ih->data->dashed = iupStrBoolean(value) ? 1 : 0;
  qtProgressBarApplyChunkStyle(ih);
  return 0;
}

static int qtProgressBarSetShowTextAttrib(Ihandle* ih, const char* value)
{
  QProgressBar* pbar = (QProgressBar*)ih->handle;

  if (ih->data->marquee)
    return 0;

  if (pbar)
  {
    if (iupStrBoolean(value))
    {
      pbar->setTextVisible(true);

      /* Use custom text if available, otherwise percentage */
      const char* text = iupAttribGet(ih, "TEXT");
      if (text)
        pbar->setFormat(QString::fromUtf8(text));
      else
        pbar->setFormat("%p%");
    }
    else
    {
      pbar->setTextVisible(false);
    }
  }

  return 1;
}

static int qtProgressBarSetTextAttrib(Ihandle* ih, const char* value)
{
  QProgressBar* pbar = (QProgressBar*)ih->handle;

  if (ih->data->marquee)
    return 0;

  if (pbar && pbar->isTextVisible())
  {
    if (value)
      pbar->setFormat(QString::fromUtf8(value));
    else
      pbar->setFormat("%p%");  /* Default to percentage */
  }

  return 1;
}

static char* qtProgressBarGetTextAttrib(Ihandle* ih)
{
  QProgressBar* pbar = (QProgressBar*)ih->handle;

  if (!pbar || ih->data->marquee)
    return nullptr;

  QString format = pbar->format();
  if (format == "%p%" || format.isEmpty())
    return nullptr;

  return iupStrReturnStr(format.toUtf8().constData());
}

static int qtProgressBarSetBgColorAttrib(Ihandle* ih, const char* value)
{
  unsigned char r, g, b;

  if (!iupStrToRGB(value, &r, &g, &b))
    return 0;

  QProgressBar* pbar = (QProgressBar*)ih->handle;

  if (pbar)
  {
    QPalette palette = pbar->palette();
    palette.setColor(QPalette::Window, QColor(r, g, b));
    pbar->setPalette(palette);
    pbar->setAutoFillBackground(true);
    return 1;
  }

  return 0;
}

static int qtProgressBarSetFgColorAttrib(Ihandle* ih, const char* value)
{
  unsigned char r, g, b;

  if (!iupStrToRGB(value, &r, &g, &b))
    return 0;

  if (!ih->handle)
    return 1;

  iupAttribSetStr(ih, "FGCOLOR", value);
  qtProgressBarApplyChunkStyle(ih);
  return 1;
}

/****************************************************************************
 * Map Method
 ****************************************************************************/

static int qtProgressBarMapMethod(Ihandle* ih)
{
  QProgressBar* pbar = new QProgressBar();

  ih->handle = (InativeHandle*)pbar;

  /* Set range [0, 1000] for better precision with double values */
  pbar->setRange(0, 1000);
  pbar->setValue(0);

  if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL"))
  {
    pbar->setOrientation(Qt::Vertical);

    /* Swap width/height if needed */
    if (ih->userheight < ih->userwidth)
    {
      int tmp = ih->userheight;
      ih->userheight = ih->userwidth;
      ih->userwidth = tmp;
    }

    /* Vertical progress bars typically don't expand horizontally */
    ih->expand = ih->expand & ~IUP_EXPAND_WIDTH;
  }
  else
  {
    pbar->setOrientation(Qt::Horizontal);

    /* Horizontal progress bars typically don't expand vertically */
    ih->expand = ih->expand & ~IUP_EXPAND_HEIGHT;
  }

  if (iupAttribGetBoolean(ih, "MARQUEE"))
  {
    ih->data->marquee = 1;
    pbar->setRange(0, 0);
    pbar->setTextVisible(false);
  }
  else
  {
    ih->data->marquee = 0;
  }

  /* Progress bars should not accept focus */
  pbar->setFocusPolicy(Qt::NoFocus);

  iupqtAddToParent(ih);

  if (!ih->data->marquee)
  {
    if (iupAttribGetBoolean(ih, "SHOWTEXT"))
    {
      pbar->setTextVisible(true);

      const char* text = iupAttribGet(ih, "TEXT");
      if (text)
        pbar->setFormat(QString::fromUtf8(text));
      else
        pbar->setFormat("%p%");
    }
    else
    {
      pbar->setTextVisible(false);
    }

    if (iupAttribGetBoolean(ih, "DASHED"))
      ih->data->dashed = 1;
    qtProgressBarApplyChunkStyle(ih);
  }

  return IUP_NOERROR;
}

/****************************************************************************
 * UnMap Method
 ****************************************************************************/

static void qtProgressBarUnMapMethod(Ihandle* ih)
{
  if (ih->handle)
  {
    QProgressBar* pbar = (QProgressBar*)ih->handle;
    iupqtTipsDestroy(ih);
    delete pbar;
    ih->handle = nullptr;
  }
}

/****************************************************************************
 * Class Initialization
 ****************************************************************************/

extern "C" IUP_SDK_API void iupdrvProgressBarInitClass(Iclass* ic)
{
  /* Driver Dependent Class functions */
  ic->Map = qtProgressBarMapMethod;
  ic->UnMap = qtProgressBarUnMapMethod;

  /* Driver Dependent Attribute functions */

  /* Visual */
  iupClassRegisterAttribute(ic, "BGCOLOR", NULL, qtProgressBarSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);

  /* Special */
  iupClassRegisterAttribute(ic, "FGCOLOR", NULL, qtProgressBarSetFgColorAttrib, NULL, NULL, IUPAF_DEFAULT);

  /* IupProgressBar only */
  iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, qtProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "MIN", qtProgressBarGetMinAttrib, qtProgressBarSetMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "MAX", qtProgressBarGetMaxAttrib, qtProgressBarSetMaxAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "DASHED", iProgressBarGetDashedAttrib, qtProgressBarSetDashedAttrib, NULL, NULL, IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "MARQUEE", NULL, qtProgressBarSetMarqueeAttrib, NULL, NULL, IUPAF_NO_INHERIT);

  /* Text display */
  iupClassRegisterAttribute(ic, "SHOWTEXT", NULL, qtProgressBarSetShowTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "TEXT", qtProgressBarGetTextAttrib, qtProgressBarSetTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
}
