/***************************************************************************
**
**  This file is part of SciFigs.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file is distributed in the hope that it will be useful, but WITHOUT
**  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
**  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2007-04-27
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "SciFigsGlobal.h"
#include "LegendWidget.h"
#include "GraphicObjectFactory.h"
#include "LegendProperties.h"
#include "LegendFormatProperties.h"
#include "XMLSciFigs.h"

namespace SciFigs {

/*!
  \class LegendWidget LegendWidget.h
  \brief Draw a legend in a GraphicSheet

  This is graphical legend that lets you map pen and symbols to a string expression
*/

const QString LegendWidget::xmlLegendWidgetTag="LegendWidget";

REGISTER_GRAPHICOBJECT(LegendWidget, LegendWidget::xmlLegendWidgetTag,
                       QApplication::translate("LegendWidget", "Legend"),
                       QApplication::translate("LegendWidget", "&Legend"),
                       QApplication::translate("LegendWidget", "CTRL+L"),
                       QApplication::translate("LegendWidget", "A pen and symbol legend"))

/*!
  Description of constructor still missing
*/
LegendWidget::LegendWidget(QWidget *parent, Qt::WindowFlags f)
    : GraphicObject(parent, f)
{
  TRACE;
  setTitle(tr( "Title" ));
  _lineSize=1.5;
  _adjustBox=true;
  adjustSize();
}

LegendWidget::~LegendWidget()
{
  TRACE;
}

LegendWidget& LegendWidget::operator=(const LegendWidget& o)
{
  TRACE;
  _legend=o._legend;
  GraphicObject::operator=(o);
  _title=o._title;
  _lineSize=o._lineSize;
  _adjustBox=o._adjustBox;
  return *this;
}

void LegendWidget::setAdjustBox(bool t)
{
  TRACE;
  _adjustBox=t;
  adjustSize();
}

void LegendWidget::setFont(const QFont& f)
{
  TRACE;
  _font=f;
  adjustSize();
}

void LegendWidget::setFont(const QString& f)
{
  TRACE;
  _font.fromString(f);
  adjustSize();
}

void LegendWidget::setTitle(const QString& t)
{
  TRACE;
  _title=t;
  adjustSize();
}

void LegendWidget::setLineSize(double ls)
{
  TRACE;
  _lineSize=ls;
  adjustSize();
}

void LegendWidget::setPrintSize(double dotpercm)
{
  TRACE;
  if(_adjustBox) {
    int w, h;
    adjustSize(dotpercm, w, h);
    setPrintWidth((w+1)/dotpercm);
    setPrintHeight((h+1)/dotpercm);
  }
}

void LegendWidget::paint(QPainter& p, double dotpercm, int w, int, bool)
{
  TRACE;
  //qDebug() << w << dotpercm;
  p.save();
  _font.setFont(p, dotpercm);
  int y=0;
  int spacing=qRound(0.2*dotpercm);
  int lineSize=qRound(_lineSize*dotpercm);
  QRect r;
  // Draw title
  if(!_title.isEmpty()) {
    r=p.boundingRect(0, 0, w, INT_MAX, Qt::AlignHCenter | Qt::AlignTop, _title);
    p.drawText(0, y, w, r.height(), Qt::AlignHCenter | Qt::AlignTop, _title);
    y+=r.height()+spacing;
  }
  // Draw items
  for(int i=0; i<_legend.count(); i++) {
    int lineHeight=qRound(_legend.pen(i).width()*0.1*dotpercm);
    int symHeight=qRound((_legend.symbol(i).size()+_legend.symbol(i).pen().width())*0.1*dotpercm);
    int h=lineHeight<symHeight ? symHeight : lineHeight;
    if(_legend.text(i).isEmpty()) {
      r=p.boundingRect(0, 0, INT_MAX, INT_MAX, Qt::AlignLeft | Qt::AlignTop, _legend.text(i));
      if(r.height()>h) h=r.height();
    } else {
      r=p.boundingRect(0, 0, INT_MAX, INT_MAX, Qt::AlignLeft | Qt::AlignTop, Font::referenceText());
      if(r.height()>h) h=r.height();
      r.translate(lineSize+spacing, y+((h-r.height()) >> 1));
      p.setPen(_legend.textColor(i));
      p.drawText(QRect(r.topLeft(), QSize(INT_MAX, INT_MAX)), Qt::AlignLeft | Qt::AlignTop, _legend.text(i));
    }
    int yc=y+(h >> 1);
    y+=h+spacing;
    p.save();
    p.setPen(_legend.pen(i).qpen(dotpercm));
    p.drawLine(0, yc, lineSize, yc);
    _legend.symbol(i).paint(p, QPointF(lineSize >> 1, yc), dotpercm);
    p.restore();
  }
  p.restore();
}


void LegendWidget::adjustSize(double dotpercm, int& width, int& height)
{
  TRACE;
  QFontMetrics f(font());
  int spacing=qRound(0.2* dotpercm);
  int lineSize=qRound(_lineSize*dotpercm);
  width=0;
  height=0;
  QRect r;
  // Title size
  if(!_title.isEmpty()) {
    r=f.boundingRect(0, 0, INT_MAX, INT_MAX, Qt::AlignLeft | Qt::AlignTop, _title);
    width+=r.width();
    height+=r.height()+spacing;
  }
  // Items size
  if(lineSize>width) {
    width=lineSize;
  }
  for(int i=0; i<_legend.count(); i++) {
    int lineHeight=(int)round(_legend.pen(i).width()*0.1*dotpercm);
    int symHeight=(int)round((_legend.symbol(i).size()+_legend.symbol(i).pen().width())*0.1*dotpercm);
    int h=lineHeight<symHeight ? symHeight : lineHeight;
    if(!_legend.text(i).isEmpty()) {
      r=f.boundingRect(0, 0, INT_MAX, INT_MAX, Qt::AlignLeft | Qt::AlignTop, _legend.text(i));
      int w=r.width()+spacing+lineSize;
      if(w>width) width=w;
      if(r.height()>h) {
        h=r.height();
      }
    } else {
      if(f.height()>h) {
        h=f.height();
      }
    }
    height+=h+spacing;
  }
  if(width<10) width=10;  // Avoid minuscule size
  if(height<10) height=10;
}

void LegendWidget::adjustSize()
{
  TRACE;
  if(_adjustBox) {
    int w, h;
    adjustSize(SciFigsGlobal::screenResolution(), w, h);
    if(w!=width() || h!=height()) {
      setPrintWidth((w+1)/SciFigsGlobal::screenResolution());
      setPrintHeight((h+1)/SciFigsGlobal::screenResolution());
      emit positionChanged();
      emit sizeChanged();
    }
  }
}

uint LegendWidget::_category=PropertyProxy::uniqueId();
uint LegendWidget::_tabLegend=PropertyProxy::uniqueId();
uint LegendWidget::_tabFormat=PropertyProxy::uniqueId();

/*!
  Setup property editor
*/
void LegendWidget::addProperties(PropertyProxy * pp)
{
  TRACE;
  GraphicObject::addProperties(pp);
  if(!pp->setCurrentCategory(_category) ) {
    pp->addCategory(_category, tr("Legend"), QIcon( ":LegendWidget.png"));
  }
  if(pp->setCurrentTab(_tabLegend)) {
    pp->addReference(this);
  } else {
    LegendProperties * w=new LegendProperties;
    w->setPropertySections(LegendTable::All);
    pp->addTab(_tabLegend, tr("Legend"), w, this);
  }
  if(pp->setCurrentTab(_tabFormat)) {
    pp->addReference(this);
  } else {
    LegendFormatProperties * w=new LegendFormatProperties;
    pp->addTab(_tabFormat, tr("Format"), w, this);
  }
}

/*!
  Cleanup property editor
*/
void LegendWidget::removeProperties(PropertyProxy * pp)
{
  TRACE;
  GraphicObject::removeProperties(pp);
  if(pp->setCurrentCategory(_category) ) {
    pp->removeTab(_tabLegend, this);
    pp->removeTab(_tabFormat, this);
  }
}

void LegendWidget::properties(PropertyWidget * w) const
{
  TRACE;
  if(w->id()==_tabLegend) {
    w->setValue(LegendProperties::Legend, QVariant::fromValue(legend()));
  } else if(w->id()==_tabFormat) {
    w->setValue(LegendFormatProperties::Title, title());
    w->setValue(LegendFormatProperties::Font, _font.screenFont().toString());
    w->setValue(LegendFormatProperties::LineSize, lineSize());
    w->setValue(LegendFormatProperties::AdjustBox, adjustBox());
  } else {
    GraphicObject::properties(w);
  }
}

/*!
  Set value \a val to property \a id, after a user action in property editor
*/
void LegendWidget::setProperty(uint wid, int pid, QVariant val)
{
  TRACE;
  if(wid==_tabLegend) {
    legend()= val.value<Legend>();
    adjustSize();
    update();
    emit changed(legend());
  } else if(wid==_tabFormat) {
    switch(pid) {
    case LegendFormatProperties::Title:
      setTitle(val.toString());
      break;
    case LegendFormatProperties::Font: {
        QFont f;
        if(f.fromString(val.toString()) ) {
          setFont(f);
        }
      }
      break;
    case LegendFormatProperties::LineSize:
      setLineSize(val.toDouble());
      break;
    case LegendFormatProperties::AdjustBox:
      setAdjustBox(val.toBool());
      break;
    default:
      break;
    }
    update();
  } else {
    GraphicObject::setProperty(wid, pid, val);
  }
}

void LegendWidget::load(QString fileName)
{
  TRACE;
  if(fileName.length()>0) {
    XMLErrorReport xmler(XMLErrorReport::Read);
    xmler.setTitle(tr("Load legend"));
    xmler.setFileName(fileName);
    XMLSciFigs s;
    xmler.exec(s.restoreFile(fileName,&_legend,XMLSciFigs::Data));
    emit changed(legend());
  }
}

void LegendWidget::save(QString fileName)
{
  TRACE;
  if(fileName.length()>0) {
    XMLErrorReport xmler(XMLErrorReport::Write);
    xmler.setTitle(tr("Save legend"));
    xmler.setFileName(fileName);
    XMLSciFigs s;
    xmler.exec(s.saveFile(fileName,&_legend,XMLSciFigs::Data));
  }
}

void LegendWidget::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
{
  TRACE;
  XMLSciFigs * scifigsContext=static_cast<XMLSciFigs *>(context);
  if(scifigsContext->data()) _legend.xml_save(s, context);
}

XMLMember LegendWidget::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  XMLSciFigs * scifigsContext=static_cast<XMLSciFigs *>(context);
  if(scifigsContext->data()) {
    if(tag=="Legend") return XMLMember(&_legend);
  }
  if(tag=="font") return XMLMember(0);
  else if(tag=="title") return XMLMember(1);
  else if(tag=="lineSize") return XMLMember(2);
  else if(tag=="adjustBox") return XMLMember(3);
  else return GraphicObject::xml_member(tag, attributes, context)+4;
}

bool LegendWidget::xml_setProperty(XML_SETPROPERTY_ARGS)
{
  switch(memberID) {
  case 0:
    _font.fromString(content.toString());
    return true;
  case 1:
    _title=content.toString();
    return true;
  case 2:
    _lineSize=content.toDouble();
    return true;
  case 3:
    _adjustBox=content.toBool();
    return true;
  default:
    return GraphicObject::xml_setProperty(memberID-4, tag, attributes, content, context);
  }
}
} // namespace SciFigs
