

#include "formatsettingspopups.h"

// Tnz6 includes
#include "tapp.h"
#include "dvwidgets.h"

// TnzLib includes
#include "toonz/tscenehandle.h"
#include "toonz/sceneproperties.h"
#include "toonz/toonzscene.h"
#include "toonz/tcamera.h"
#include "toutputproperties.h"

#ifdef _WIN32
#include "avicodecrestrictions.h"
#endif

// TnzCore includes
#include "tlevel_io.h"
#include "tproperty.h"
#include "timageinfo.h"
#include "tfiletype.h"
#include "tiio.h"
#include "movsettings.h"

// Qt includes
#include <QComboBox>
#include <QLabel>
#include <QHBoxLayout>
#include <QPushButton>
#include <QMainWindow>
#include <QGroupBox>

namespace {
bool checkForSeqNum(QString type) {
  TFileType::Type typeInfo = TFileType::getInfoFromExtension(type);
  if ((typeInfo & TFileType::IMAGE) && !(typeInfo & TFileType::LEVEL))
    return true;
  else
    return false;
}
};  // namespace

//**********************************************************************************
//    FormatSettingsPopup  implementation
//**********************************************************************************

FormatSettingsPopup::FormatSettingsPopup(QWidget *parent,
                                         const std::string &format,
                                         TPropertyGroup *props,
                                         TFrameId *tmplFrameId, bool forInput)
    : Dialog(parent)
    , m_format(format)
    , m_props(props)
    , m_levelPath(TFilePath())
#ifdef _WIN32
    , m_codecRestriction(0)
    , m_codecComboBox(0)
    , m_configureCodec(0)
#endif
    , m_sepCharCB(nullptr)
    , m_paddingCB(nullptr)
    , m_tmplFId(tmplFrameId) {
  setWindowTitle(tr("File Settings"));

  setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint);

  m_mainLayout = new QGridLayout();
  m_mainLayout->setMargin(0);
  m_mainLayout->setVerticalSpacing(5);
  m_mainLayout->setHorizontalSpacing(5);
  m_mainLayout->setColumnStretch(0, 0);
  m_mainLayout->setColumnStretch(1, 1);

  if (m_props) {
    int i = 0;
    for (i = 0; i < m_props->getPropertyCount(); i++) {
      TProperty *prop = m_props->getProperty(i);
      if (prop && !prop->getVisible()) continue;
      if (dynamic_cast<TEnumProperty *>(prop))
        buildPropertyComboBox(i, m_props);
      else if (dynamic_cast<TIntProperty *>(prop))
        buildValueField(i, m_props);
      else if (dynamic_cast<TDoubleProperty *>(prop))
        buildDoubleField(i, m_props);
      else if (dynamic_cast<TBoolProperty *>(prop))
        buildPropertyCheckBox(i, m_props);
      else if (dynamic_cast<TStringProperty *>(prop))
        buildPropertyLineEdit(i, m_props);
      else
        assert(false);
    }
  }

#ifdef _WIN32
  if (format == "avi") {
    m_codecRestriction = new QLabel(this);
    m_codecRestriction->setMinimumHeight(70);
    m_codecRestriction->setStyleSheet("border: 1px solid rgba(0,0,0,0.5);");
    m_mainLayout->addWidget(m_codecRestriction, m_mainLayout->rowCount(), 0, 1,
                            2);
    m_configureCodec = new QPushButton(tr("Configure Codec"), this);
    m_configureCodec->setObjectName("PushButton_NoPadding");
    m_configureCodec->setFixedSize(100, DVGui::WidgetHeight);
    m_mainLayout->addWidget(m_configureCodec, m_mainLayout->rowCount(), 0, 1,
                            2);
    connect(m_configureCodec, SIGNAL(released()), this,
            SLOT(onAviCodecConfigure()));
  }
#endif

  if (checkForSeqNum(QString::fromStdString(format)) && tmplFrameId) {
    m_sepCharCB = new QComboBox(this);
    m_paddingCB = new QComboBox(this);

    m_sepCharCB->addItem(tr(". (period)"), QChar('.'));
    m_sepCharCB->addItem(tr("_ (underscore)"), QChar('_'));
    m_sepCharCB->setCurrentIndex(m_sepCharCB->findData(
        QChar::fromLatin1(tmplFrameId->getStartSeqInd())));

    m_paddingCB->addItem(tr("No padding"), 0);
    for (int p = 1; p <= 6; p++) m_paddingCB->addItem(QString::number(p), p);
    m_paddingCB->setCurrentIndex(
        m_paddingCB->findData(tmplFrameId->getZeroPadding()));

    int currentRow = m_mainLayout->rowCount();
    if (currentRow > 0)
      m_mainLayout->addItem(new QSpacerItem(15, 15), currentRow, 0);

    QGroupBox *frameFormatGB = new QGroupBox(tr("Frame Number Format"), this);

    frameFormatGB->setObjectName((forInput) ? "FrameFormatBoxInput"
                                            : "FrameFormatBoxOutput");

    QGridLayout *frameFormatLay = new QGridLayout();
    frameFormatLay->setColumnStretch(0, 0);
    frameFormatLay->setColumnStretch(1, 1);
    {
      frameFormatLay->addWidget(new QLabel(tr("Separate Character:"), this), 0,
                                0, Qt::AlignRight);
      frameFormatLay->addWidget(m_sepCharCB, 0, 1, Qt::AlignLeft);

      frameFormatLay->addWidget(new QLabel(tr("Padding:"), this), 1, 0,
                                Qt::AlignRight);
      frameFormatLay->addWidget(m_paddingCB, 1, 1, Qt::AlignLeft);
    }
    frameFormatGB->setLayout(frameFormatLay);

    m_mainLayout->addWidget(frameFormatGB, currentRow + 1, 0, 1, 2);

    connect(m_sepCharCB, SIGNAL(activated(int)), this,
            SLOT(onSepCharCBChanged()));
    connect(m_paddingCB, SIGNAL(activated(int)), this,
            SLOT(onPaddingCBChanged()));
  }

  QPushButton *closeButton = new QPushButton(tr("Close"));
  closeButton->setContentsMargins(4, 4, 4, 4);
  closeButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
  connect(closeButton, SIGNAL(released()), this, SLOT(close()));

  m_mainLayout->addWidget(closeButton, m_mainLayout->rowCount(), 0, 1, 2,
                          Qt::AlignCenter);

  m_topLayout->addLayout(m_mainLayout, 1);
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::setFormatProperties(TPropertyGroup *props) {
  if (props == m_props) return;

  m_props = props;

  for (int i = 0; i < m_props->getPropertyCount(); i++) {
    if (TProperty *prop = m_props->getProperty(i))
      m_widgets[prop->getName()]->setProperty(prop);
  }
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::buildPropertyComboBox(int index,
                                                TPropertyGroup *props) {
  TEnumProperty *prop = (TEnumProperty *)(props->getProperty(index));

  assert(prop);

  DVGui::PropertyComboBox *comboBox = new DVGui::PropertyComboBox(this, prop);
  m_widgets[prop->getName()]        = comboBox;

#ifdef _WIN32
  connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this,
          SLOT(onComboBoxIndexChanged(const QString &)));
#endif
  TEnumProperty::Range range = prop->getRange();
  TEnumProperty::Items items = prop->getItems();
  int currIndex              = -1;
  std::wstring defaultVal    = prop->getValue();

  for (int i = 0; i < (int)range.size(); i++) {
    std::wstring nameProp = range[i];

    if (nameProp.find(L"16(GREYTONES)") !=
        -1)  // pezza per il tif: il 16 lo scrive male, e il 48 lo legge male...
      continue;
    /* if (nameProp.find(L"ThunderScan")!=-1) //pezza epr il tif, molte
compressioni non vanno..scive male il file
break;*/

    if (nameProp == defaultVal) currIndex = comboBox->count();
    comboBox->addItem(items[i].UIName, QString::fromStdWString(nameProp));
  }
  if (currIndex >= 0) comboBox->setCurrentIndex(currIndex);

  int row = m_mainLayout->rowCount();
  m_mainLayout->addWidget(new QLabel(prop->getQStringName() + ":", this), row,
                          0, Qt::AlignRight | Qt::AlignVCenter);
  m_mainLayout->addWidget(comboBox, row, 1);

#ifdef _WIN32
  if (m_format == "avi") m_codecComboBox = comboBox;
#endif
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::buildValueField(int index, TPropertyGroup *props) {
  TIntProperty *prop = (TIntProperty *)(props->getProperty(index));
  assert(prop);

  DVGui::PropertyIntField *v = new DVGui::PropertyIntField(this, prop);
  m_widgets[prop->getName()] = v;

  int row = m_mainLayout->rowCount();
  m_mainLayout->addWidget(new QLabel(prop->getQStringName() + ":", this), row,
                          0, Qt::AlignRight | Qt::AlignVCenter);
  m_mainLayout->addWidget(v, row, 1);
  // get value here - bug loses value if the range doesn't start with 0
  double value = prop->getValue();
  v->setValues(prop->getValue(), prop->getRange().first,
               prop->getRange().second);
  if (prop->getValue() != value) {
    prop->setValue(value);
  }
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::buildDoubleField(int index, TPropertyGroup *props) {
  TDoubleProperty *prop = (TDoubleProperty *)(props->getProperty(index));
  assert(prop);

  DVGui::PropertyDoubleField *v = new DVGui::PropertyDoubleField(this, prop);
  m_widgets[prop->getName()]    = v;

  int row = m_mainLayout->rowCount();
  m_mainLayout->addWidget(new QLabel(prop->getQStringName() + ":", this), row,
                          0, Qt::AlignRight | Qt::AlignVCenter);
  m_mainLayout->addWidget(v, row, 1);
  // get value here - bug loses value if the range doesn't start with 0
  double value = prop->getValue();
  v->setValues(prop->getValue(), prop->getRange().first,
               prop->getRange().second);
  if (prop->getValue() != value) {
    prop->setValue(value);
  }
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::buildPropertyCheckBox(int index,
                                                TPropertyGroup *props) {
  TBoolProperty *prop = (TBoolProperty *)(props->getProperty(index));
  assert(prop);

  DVGui::PropertyCheckBox *v =
      new DVGui::PropertyCheckBox(prop->getQStringName(), this, prop);
  m_widgets[prop->getName()] = v;

  m_mainLayout->addWidget(v, m_mainLayout->rowCount(), 1);

  v->setChecked(prop->getValue());
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::buildPropertyLineEdit(int index,
                                                TPropertyGroup *props) {
  TStringProperty *prop = (TStringProperty *)(props->getProperty(index));
  assert(prop);

  DVGui::PropertyLineEdit *lineEdit = new DVGui::PropertyLineEdit(this, prop);
  m_widgets[prop->getName()]        = lineEdit;
  lineEdit->setText(tr(::to_string(prop->getValue()).c_str()));

  int row = m_mainLayout->rowCount();
  m_mainLayout->addWidget(new QLabel(prop->getQStringName() + ":", this), row,
                          0, Qt::AlignRight | Qt::AlignVCenter);
  m_mainLayout->addWidget(lineEdit, row, 1);
}

//-----------------------------------------------------------------------------

#ifdef _WIN32

void FormatSettingsPopup::onComboBoxIndexChanged(const QString &codecName) {
  if (!m_codecRestriction) return;
  QString msg;
  AviCodecRestrictions::getRestrictions(codecName.toStdWString(), msg);
  m_codecRestriction->setText(msg);
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::onAviCodecConfigure() {
  QString codecName       = m_codecComboBox->currentText();
  std::wstring wCodecName = codecName.toStdWString();
  if (AviCodecRestrictions::canBeConfigured(wCodecName))
    AviCodecRestrictions::openConfiguration(wCodecName, (HWND)winId());
}

#else

void FormatSettingsPopup::onComboBoxIndexChanged(const QString &codecName) {
  // do nothing
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::onAviCodecConfigure() {
  // do nothing
}

#endif

//-----------------------------------------------------------------------------

void FormatSettingsPopup::showEvent(QShowEvent *se) {
#ifdef _WIN32
  if (m_format == "avi") {
    assert(m_codecComboBox);
    m_codecComboBox->blockSignals(true);
    m_codecComboBox->clear();
    ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
    TEnumProperty *eProps =
        dynamic_cast<TEnumProperty *>(m_props->getProperty(0));
    assert(eProps);

    TDimension res(0, 0);
    if (m_levelPath.isEmpty())
      res = scene->getCurrentCamera()->getRes();
    else {
      TLevelReaderP lr(m_levelPath);
      TLevelP level          = lr->loadInfo();
      const TImageInfo *info = lr->getImageInfo(level->begin()->first);
      res.lx                 = info->m_lx;
      res.ly                 = info->m_ly;
    }

    TEnumProperty::Range range = eProps->getRange();
    int currIndex              = -1;
    std::wstring defaultVal    = eProps->getValue();

    QMap<std::wstring, bool> usableCodecs =
        AviCodecRestrictions::getUsableCodecs(res);
    for (int i = 0; i < (int)range.size(); i++) {
      std::wstring nameProp = range[i];
      if (nameProp == L"Uncompressed" ||
          (usableCodecs.contains(nameProp) && usableCodecs[nameProp])) {
        if (nameProp == defaultVal) currIndex = m_codecComboBox->count();
        m_codecComboBox->addItem(QString::fromStdWString(nameProp));
      }
    }
    m_codecComboBox->blockSignals(false);
    if (currIndex >= 0) m_codecComboBox->setCurrentIndex(currIndex);
  }

#endif

  Dialog::showEvent(se);
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::onSepCharCBChanged() {
  assert(m_tmplFId);
  m_tmplFId->setStartSeqInd(m_sepCharCB->currentData().toChar().toLatin1());
}

//-----------------------------------------------------------------------------

void FormatSettingsPopup::onPaddingCBChanged() {
  assert(m_tmplFId);
  m_tmplFId->setZeroPadding(m_paddingCB->currentData().toInt());
}

//**********************************************************************************
//    API  functions
//**********************************************************************************

bool openFormatSettingsPopup(QWidget *parent, const std::string &format,
                             TPropertyGroup *props, TFrameId *tmplFId,
                             bool forInput, const TFilePath &levelPath) {
  bool quicktime = (format == "mov" || format == "3gp") && Tiio::useQuicktime();
  if (quicktime)  // trattato diversamente; il format
                  // popup dei mov e' quello di
                  // quicktime
  {
    // gmt 26/9/07. con la penna capita spesso di premere ripetutamente il
    // bottone.
    // si aprono due popup uno sopra l'altro (brutto di per se e puo' causare
    // dei crash misteriosi)
    static bool popupIsOpen = false;
    if (popupIsOpen) return 0;

    popupIsOpen = true;
    openMovSettingsPopup(props);
    popupIsOpen = false;

    return true;
  }

  if ((!props || props->getPropertyCount() == 0) &&
      !(checkForSeqNum(QString::fromStdString(format)) && tmplFId))
    return false;

  FormatSettingsPopup *popup =
      new FormatSettingsPopup(parent, format, props, tmplFId, forInput);
  popup->setAttribute(Qt::WA_DeleteOnClose);
  popup->setModal(true);

  if (!levelPath.isEmpty()) popup->setLevelPath(levelPath);

  popup->exec();

  return true;
}
