//---------------------------------------------------------------------
// Ipe preference settings
//---------------------------------------------------------------------
/*

    This file is part of the extensible drawing editor Ipe.
    Copyright (C) 1993-2004  Otfried Cheong

    Ipe is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    As a special exception, you have permission to link Ipe with the
    CGAL library and distribute executables, as long as you follow the
    requirements of the Gnu General Public License in regard to all of
    the software in the executable aside from CGAL.

    Ipe 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 General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Ipe; if not, you can find it at
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "ipexml.h"

#include "ipeq.h"
#include "ipeprefs.h"

#if defined(WIN32)
#include <windows.h>
#endif
#include <stdlib.h>

#include <qdir.h>
#include <qfile.h>

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

/*! \class IpePreferences
  \brief The configurable settings of the Ipe program.

  There are compile-time defaults, which can be overridden by
  environment variables.  The compression levels are saved to
  <tt>$HOME/.iperc</tt> (on Unix) or <tt>$HOME/_ipecfg</tt> (on
  Windows).

  The interesting data members are all public.

*/

#ifdef WIN32
#define SEP ';'
#else
#define SEP ':'
#endif

const char * const stdFontMap[] = {
  "Times-Roman",
  "Times-Italic",
  "Times-Bold",
  "Times-BoldItalic",
  "Helvetica",
  "Helvetica-Oblique",
  "Helvetica-Bold",
  "Helvetica-BoldOblique",
  "Courier",
  "Courier-Oblique",
  "Courier-Bold",
  "Courier-BoldOblique",
  "Symbol",
  "ZapfDingbats",
};

const int ConfigFileRevisionLevel = 18;

IpePreferences *IpePreferences::This = 0;

//! Return a pointer to the unique IpePreferences instance.
IpePreferences *IpePreferences::Static()
{
  if (!This) {
    This = new IpePreferences;
  }
  return This;
}

//! Constructor sets up preferences.
/*! Preferences are read from the preferences file
  (<tt>$HOME/.iperc</tt> on Unix, <tt>$HOME/_ipecfg</tt> on Windows).
  If the file doesn't exist or is not readable, built-in defaults are
  used.

  The directory settings are computed from the location of the
  executable on Windows, and taken from compile-time settings on Unix.
  In both cases, environment variables override these settings.
*/

IpePreferences::IpePreferences()
{
  // First set compile-time defaults
  iCompressLevel = 9;
  iSelectDistance = 36;
  iSnapDistance = 16;
  iRightMouseSelects = true;
  iWhitePaper = false;
  iBigToolButtons = false;
  iTransformable = true;
  iAntiAlias = true;
  iGridVisible = true;
  iMaximize = false;
  iMedia = IpeVector(595, 842); // A4
  iGridSize = 16;
  iStyleSheet = QString::null;
  iStyleSheet2 = QString::null;
  iLanguage = QString::null;
  iMikTeX = false;
  QDir home = QDir::home();
#ifdef WIN32
  char exename[OFS_MAXPATHNAME];
  GetModuleFileNameA(0, exename, OFS_MAXPATHNAME);
  QFileInfo finfo = QFileInfo(QString(exename));
  QDir ipedir = finfo.dir(true);
  iBinDir = ipedir.path();
  ipedir.cdUp();
  iDocDir = ipedir.filePath("doc");
  iFontmap = ipedir.filePath("data/fontmap.xml");
  iLangDir = ipedir.filePath("languages");
  iIpeletPath = ipedir.filePath("ipelets");
  iLatexDir = ipedir.filePath("latexrun");
#else
  iBinDir = IPEBINDIR;
  QDir ipedir = home.filePath(".ipe");
  if (!ipedir.exists())
    home.mkdir(".ipe");
  iLatexDir = ipedir.filePath("latexrun");
  iDocDir = IPEDOCDIR;
  iFontmap = IPEFONTMAP;
  iBrowser = IPEBROWSER;
  iIpeletPath.append(IPELETPATH);
  iLangDir = IPELANGDIR;

#endif
  iPdfLatex = "pdflatex";
  const char *p;
  p = getenv("IPELATEXDIR");
  if (p) iLatexDir = p;
  p = getenv("IPEPDFLATEX");
  if (p) iPdfLatex = p;
  p = getenv("IPEBINDIR");
  if (p) iBinDir = p;
  p = getenv("IPEDOCDIR");
  if (p) iDocDir = p;
  p = getenv("IPELANGDIR");
  if (p) iLangDir = p;
  p = getenv("IPEFONTMAP");
  if (p) iFontmap = p;
  p = getenv("IPEBROWSER");
  if (p) iBrowser = p;
  p = getenv("IPELETPATH");
  if (p)
    iIpeletPath = QStringList::split(QChar(SEP), p);
  p = getenv("TEXINPUTS");
  if (p)
    iTexInputs = p;

#ifdef WIN32
  iPrefsFileName = home.filePath("_ipecfg");
  iKeysFileName = home.filePath("_ipekeys.qm");
#else
  iPrefsFileName = ipedir.filePath("iperc");
  iKeysFileName = ipedir.filePath("ipekeys.qm");
#endif
  iDialogDir = QDir::current().path();
  QFile file(iPrefsFileName);
  if (!file.open(IO_ReadOnly))
    return;
  QDataStream ds(&file);
  int revLevel;
  ds >> revLevel;
  if (revLevel != ConfigFileRevisionLevel)
    return;
  Q_INT8 flag;
  ds >> iCompressLevel;
  ds >> iSelectDistance;
  ds >> iSnapDistance;
  ds >> flag; iWhitePaper = !!flag;
  ds >> flag; iBigToolButtons = !!flag;
  ds >> flag; iTransformable = !!flag;
  ds >> flag; iAntiAlias = !!flag;
  ds >> flag; iGridVisible = !!flag;
  ds >> flag; iMaximize = !!flag;
  ds >> iMedia.iX >> iMedia.iY;
  ds >> iGridSize;
  ds >> iStyleSheet;
  ds >> iFont;
  ds >> iTextFont;
  ds >> iLanguage;
  ds >> flag; iMikTeX = !!flag;
  FindStandardFonts();
}

//! Save preferences to preferences file.
bool IpePreferences::Save()
{
  QFile file(iPrefsFileName);
  if (!file.open(IO_WriteOnly))
    return false;
  QDataStream ds(&file);
  ds << ConfigFileRevisionLevel
     << iCompressLevel
     << iSelectDistance
     << iSnapDistance
     << Q_INT8(iWhitePaper)
     << Q_INT8(iBigToolButtons)
     << Q_INT8(iTransformable)
     << Q_INT8(iAntiAlias)
     << Q_INT8(iGridVisible)
     << Q_INT8(iMaximize)
     << iMedia.iX << iMedia.iY
     << iGridSize
     << iStyleSheet
     << iFont
     << iTextFont
     << iLanguage
     << Q_INT8(iMikTeX);
  file.close();
  emit Changed();
  return true;
}

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

class FontmapParser : public IpeXmlParser {
public:
  explicit FontmapParser(IpeDataSource &source) :
    IpeXmlParser(source) { /* nothing */ }
  bool ParseFontmap();

  QString iGlyphs[14];
};

// Parse a fontmap.
bool FontmapParser::ParseFontmap()
{
  IpeXmlAttributes att;
  IpeString tag = ParseToTag();

  if (tag == "?xml") {
    if (!ParseAttributes(att, true))
      return false;
    tag = ParseToTag();
  }

  if (tag != "fontmap")
    return false;
  if (!ParseAttributes(att))
    return false;
  tag = ParseToTag();

  while (tag == "font") {
    if (!ParseAttributes(att))
      return false;
    if (att["format"] == "type1") {
      IpeString name = att["name"];
      IpeString glyphs = att["glyphs"];
      int i = 0;
      while (i < 14 && name != IpeString(stdFontMap[i]))
	++i;
      if (i < 14)
	iGlyphs[i] = QIpe(glyphs);
    }
    tag = ParseToTag();
  }

  if (tag != "/fontmap")
    return false;
  return true;
}


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

//! Parse the fontmap and store absolute paths for standard fonts.
void IpePreferences::FindStandardFonts()
{
  QFile file(iFontmap);
  QDir dir = QFileInfo(file).dir();

  if (!file.open(IO_ReadOnly)) {
    qDebug("Could not open fontmap '%s'", iFontmap.latin1());
    return;
  }

  XmlQSource source(&file);
  FontmapParser parser(source);
  if (parser.ParseFontmap()) {
    for (int i = 0; i < 14; ++i) {
      if (parser.iGlyphs[i] != QString::null) {
	QString fname = dir.absFilePath(parser.iGlyphs[i]);
	if (QFile::exists(fname))
	  iStandardFont[i] = fname;
      }
    }
  }
  file.close();

  for (int i = 0; i < 14; ++i) {
    if (iStandardFont[i] == QString::null) {
      qDebug("No font file found for '%s'", stdFontMap[i]);
    } else {
      ipeDebug("Standard font '%s' uses font file '%s",
	       stdFontMap[i], iStandardFont[i].latin1());
    }
  }
}

//! Return contents of font file for standard font \a name.
IpeBuffer IpePreferences::StandardFont(IpeString name)
{
  for (int i = 0; i < 14; ++i) {
    if (name == stdFontMap[i]) {
      // if it's known and not yet loaded, load it
      if (iStandardFont[i] != QString::null
	  && iStandardFontBuffer[i].size() == 0) {
	QFile file(iStandardFont[i]);
	if (file.open(IO_ReadOnly)) {
	  QByteArray a = file.readAll();
	  file.close();
	  iStandardFontBuffer[i] = IpeBuffer(a.data(), a.size());
	}
      }
      return iStandardFontBuffer[i];
    }
  }
  return IpeBuffer();
}

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