/***************************************************************************
**
**  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: 2017-02-03
**  Copyright: 2017-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "Font.h"

namespace SciFigs {

  /*!
    \class Font Font.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  const char * Font::_refText="The quick brown fox jumps over the lazy dog";

  /*!
    Description of constructor still missing
  */
  Font::Font()
    : QFont()
  {
    TRACE;
    _refWidth=0.0;
    setScreenScale();
  }

  /*!
    Description of constructor still missing
  */
  Font::Font(const Font& o)
    : QFont(o)
  {
    TRACE;
    _refWidth=o._refWidth;
    _screenScale=o._screenScale;
    _screenFont=o._screenFont;
  }

  /*!
    Description of destructor still missing
  */
  Font::~Font()
  {
    TRACE;
  }

  void Font::operator=(const QFont& f)
  {
    TRACE;
    QFont::operator=(f);
    _refWidth=0.0; // force re-initialization of reference width
    setScreenScale();
  }

  void Font::setScreenScale()
  {
    QFontMetricsF fm(*this);
    QRectF r=fm.boundingRect(QRectF(0.0, 0.0, INT_MAX, INT_MAX), Qt::AlignLeft | Qt::AlignTop, _refText);
    if(_refWidth==0.0) {
      _refWidth=r.width()/SciFigsGlobal::screenResolution();
      _screenScale=1.0;
    } else {
      _screenScale=_refWidth*SciFigsGlobal::screenResolution()/r.width();
    }
    _screenFont=*this;
    scale(_screenFont, _screenScale);
  }

  QRectF Font::boundingRect(const QString& text, int length, int flags) const
  {
    TRACE;
    QFontMetricsF fm(_screenFont);
    return fm.boundingRect(QRectF(0.0, 0.0, length, INT_MAX), flags, text);
  }

  void Font::setFont(QPainter& p, double dotpercm) const
  {
    TRACE;
    if(dotpercm==SciFigsGlobal::screenResolution()) {
      //qDebug() << "screenFont" << _screenFont.toString();
      p.setFont(_screenFont);
    } else {
      p.setFont(*this);
      bool changed=true;
      while(changed) {
        QRectF r=p.boundingRect(QRectF(0.0, 0.0, INT_MAX, INT_MAX), Qt::AlignLeft | Qt::AlignTop, _refText);
        double factor=(dotpercm*_refWidth)/r.width();
        //qDebug() << p.font().toString() << _refWidth << _screenScale << r.width() << dotpercm << factor;
        if(factor==1.0) {
          break; // No adjustment required
        } else {
          QFont f=p.font();
          scale(f, factor, &changed);
          p.setFont(f);
        }
      }
    }
  }

  /*!
    Scale the font, and replace familly if not scalable
    If \a changed is not null, it is set to true if family is changed.

    Return the original pointSize
  */
  double Font::scale(QFont& f, double scale, bool *changed)
  {
    TRACE;
    double originalSize=f.pointSizeF();
    double scaledSize=originalSize*scale;
    static QFontDatabase fdb;
    if(!fdb.isScalable(f.family())) {
      App::log(1, tr("WARNING font cannot be scaled: %1\n"
                     "        needed size=%2\n").arg(f.toString()).arg(scaledSize));
      QStringList subFonts=QFont::substitutes(f.family());
      QString subFamily="Sans Serif";
      for(QStringList::Iterator it=subFonts.begin();it!=subFonts.end();++it) {
        if(fdb.isScalable( *it) ) {
          subFamily=*it;
          break;
        }
      }
      App::log(1, tr("     --> replaced by %1\n").arg(subFamily));
      f.setFamily(subFamily);
      if(changed) {
        *changed=true;
      }
    } else if(changed) {
      *changed=false;
    }
    f.setPointSizeF(scaledSize);
    return originalSize;
  }

  /*!
    The standard description of QFont does not provide a constant-sized text across
    platforms. We add a cm size of the reference text to the font description.
  */
  void Font::fromString(QString s)
  {
    if(s.endsWith("cm")) {
      int i=s.lastIndexOf(",");
      _refWidth=s.mid(i+1).replace("cm", "").toDouble();
      QFont::fromString(s.left(i));
      setScreenScale();
    } else { // Kept for compatibility
      QFont::fromString(s);
      App::log(1, tr("WARNING font without reference width: font size may not be fine\n"));
      _refWidth=0.0;
      setScreenScale();
    }
  }

  /*!
    The standard description of QFont does not provide a constant-sized text across
    platforms. We add a cm size of the reference text to the font description.
  */
  QString Font::toString() const
  {
    return QFont::toString()+","+QString::number(_refWidth)+"cm";
  }

} // namespace SciFigs

