/***************************************************************************
                      kstiface_impl.cpp  -  Part of KST
                             -------------------
    begin                : Thu Jun 19 2003
    copyright            : (C) 2003 The University of Toronto
    email                :
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <assert.h>

// include files for Qt
#include <qfileinfo.h>
#include <qregexp.h>

// include files for KDE

// application specific includes
#include "kst.h"
#include "kstcolorsequence.h"
#include "kstdoc.h"
#include "kstequation.h"
#include "ksthistogram.h"
#include "kstiface_impl.h"
#include "kstplugin.h"
#include "kstpsd.h"
#include "kstrvector.h"
#include "kstvcurve.h"
#include "kstviewwindow.h"
#include "plugincollection.h"

KstIfaceImpl::KstIfaceImpl(KstDoc *doc, KstApp *app)
: DCOPObject("KstIface"), _doc(doc), _app(app) {
  assert(doc);
}


KstIfaceImpl::~KstIfaceImpl() {
}


void KstIfaceImpl::showDataManager() {
  _app->showDataManager();
}


QStringList KstIfaceImpl::stringList() {
  KstReadLocker ml(&KST::stringList.lock());
  return KST::stringList.tagNames();
}


QStringList KstIfaceImpl::scalarList() {
  KstReadLocker ml(&KST::scalarList.lock());
  return KST::scalarList.tagNames();
}


QStringList KstIfaceImpl::vectorList() {
  KstReadLocker ml(&KST::vectorList.lock());
  return KST::vectorList.tagNames();
}


QStringList KstIfaceImpl::objectList() {
  KstReadLocker ml(&KST::dataObjectList.lock());
  return KST::dataObjectList.tagNames();
}


QStringList KstIfaceImpl::curveList() {
  QStringList rc;

  KstBaseCurveList bcl = kstObjectSubList<KstDataObject,KstBaseCurve>(KST::dataObjectList);

  for (KstBaseCurveList::Iterator it = bcl.begin(); it != bcl.end(); ++it) {
    (*it)->readLock();
    rc += (*it)->tagName();
    (*it)->readUnlock();
  }

  return rc;
}


QString KstIfaceImpl::activeWindow() {
  KstApp *app = KstApp::inst();
  KMdiChildView *view = app->activeWindow();
  if (view) {
    return view->caption();
  }
  return QString::null;
}


QStringList KstIfaceImpl::windowList() {
  QStringList rc;
  KstApp *app = KstApp::inst();
  KMdiIterator<KMdiChildView*> *it = app->createIterator();
  while (it->currentItem()) {
    rc += it->currentItem()->caption();
    it->next();
  }
  app->deleteIterator(it);
  return rc;
}


QStringList KstIfaceImpl::plotList() {
  QStringList rc;
  KstApp *app = KstApp::inst();
  KMdiIterator<KMdiChildView*> *it = app->createIterator();
  while (it->currentItem()) {
    rc += plotList(it->currentItem()->caption());
    it->next();
  }
  app->deleteIterator(it);
  return rc;
}


QStringList KstIfaceImpl::plotList(const QString& window) {
  QStringList rc;
  KstApp *app = KstApp::inst();
  KMdiChildView *c = app->findWindow(window);
  KstViewWindow *v = dynamic_cast<KstViewWindow*>(c);
  if (v) {
    Kst2DPlotList l = v->view()->findChildrenType<Kst2DPlot>(false);
    for (Kst2DPlotList::Iterator i = l.begin(); i != l.end(); ++i) {
      rc += (*i)->tagName();
    }
  }
  return rc;
}


QStringList KstIfaceImpl::pluginList() {
  QStringList rc;
  PluginCollection *pc = PluginCollection::self();
  const QMap<QString,Plugin::Data>& pluginList = pc->pluginList();
  QMap<QString,Plugin::Data>::ConstIterator it;

  for (it = pluginList.begin(); it != pluginList.end(); ++it) {
    if (it.data()._isFilter == false) {
      rc += it.data()._name;
    }
  }

  return rc;
}


QStringList KstIfaceImpl::filterList() {
  QStringList rc;
  PluginCollection *pc = PluginCollection::self();
  const QMap<QString,Plugin::Data>& pluginList = pc->pluginList();
  QMap<QString,Plugin::Data>::ConstIterator it;

  for (it = pluginList.begin(); it != pluginList.end(); ++it) {
    if (it.data()._isFilter) {
      rc += it.data()._name;
    }
  }

  return rc;
}


bool KstIfaceImpl::plotEquation(double start, double end, int numSamples, const QString& equation, const QString& plotName, const QColor& color) {
  Kst2DPlotPtr plot;
  QString etag, ptag;
  KstApp *app = KstApp::inst();

  if (equation.isEmpty()) {
    return false;
  }

  etag = "Eq-" + QString(equation).replace(QRegExp("[\\[\\]\\s]"), "_");
  ptag = "P-" + plotName;

  if (!plotName.isEmpty()) {
    //find the plot, or P-plotName
    KMdiIterator<KMdiChildView*> *iter = app->createIterator();
    bool found = false;
    while ((iter->currentItem()) && !found) {
      KMdiChildView *childview = iter->currentItem();
      KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(childview);
      if (viewwindow && !found) {
        Kst2DPlotList plotlist = viewwindow->view()->findChildrenType<Kst2DPlot>(false);
        Kst2DPlotList::Iterator plot_iter = plotlist.findTag(plotName);
        if (plot_iter != plotlist.end()) {
          plot = *plot_iter;
          found = true;
        } else {
          Kst2DPlotList::Iterator plot_iter = plotlist.findTag(ptag);
          if (plot_iter != plotlist.end()) {
            plot = *plot_iter;
            found = true;
          }
        }
      }
      iter->next();
    }
    app->deleteIterator(iter);
  }

  //if the plot does not exist, create it
  if (!plot) {
    //put the plot in the active window
    KMdiChildView *activewin = app->activeWindow();
    if (!activewin) {
      QString windowname = app->newWindow("W1");
      activewin = app->findWindow(windowname);
    }
    KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(activewin);
    if (viewwindow) {
      KstTopLevelViewPtr pTLV = viewwindow->view();
      plot = pTLV->createPlot<Kst2DPlot>(ptag);
    }
  }

  while (KST::dataTagNameNotUnique(etag, false)) {
    etag += '\'';
  }

  KstEquationPtr eq = new KstEquation(etag, equation, start, end, numSamples);

  if (!eq->isValid()) {
    return false;
  }

  KstVCurvePtr vc = new KstVCurve(etag + "-curve", eq->vX(), eq->vY(), 0L, 0L, color.isValid() ? color : KstColorSequence::next(plot->Curves,plot->backgroundColor()));
  KST::dataObjectList.lock().writeLock();
  KST::dataObjectList.append(KstDataObjectPtr(eq));
  KST::dataObjectList.append(KstDataObjectPtr(vc));
  KST::dataObjectList.lock().writeUnlock();

  plot->Curves.append(KstBaseCurvePtr(vc));

  _doc->forceUpdate();
  _doc->setModified();

  return true;
}


bool KstIfaceImpl::plotEquation(double start, double end, int numSamples, const QString& equation, const QString& plotName) {
  return plotEquation(start, end, numSamples, equation, plotName, QColor());
}


bool KstIfaceImpl::plotEquation(const QString& xvector, const QString& equation, const QString& plotName) {
  return plotEquation(xvector, equation, plotName, QColor());
}


bool KstIfaceImpl::plotEquation(const QString& xvector, const QString& equation, const QString& plotName, const QColor& color) {
  KstVectorPtr v;
  Kst2DPlotPtr plot;
  QString etag, ptag;
  KST::vectorList.lock().readLock();
  KstVectorList::Iterator it = KST::vectorList.findTag(xvector);
  KST::vectorList.lock().readUnlock();
  KstApp *app = KstApp::inst();

  if (equation.isEmpty() || it == KST::vectorList.end()) {
    return false;
  }

  v = *it;

  etag = "Eq-" + QString(equation).replace(QRegExp("[\\[\\]\\s]"), "_");
  ptag = "P-" + plotName;

  if (!plotName.isEmpty()) {
    //find the plot, or P-plotName
    KMdiIterator<KMdiChildView*> *iter = app->createIterator();
    bool found = false;
    while (iter->currentItem() && !found) {
      KMdiChildView *childview = iter->currentItem();
      KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(childview);
      if (viewwindow && !found) {
        Kst2DPlotList plotlist = viewwindow->view()->findChildrenType<Kst2DPlot>(false);
        Kst2DPlotList::Iterator plot_iter = plotlist.findTag(plotName);
        if (plot_iter != plotlist.end()) {
          plot = *plot_iter;
          found = true;
        }
        else {
          Kst2DPlotList::Iterator plot_iter = plotlist.findTag(ptag);
          if (plot_iter != plotlist.end()) {
            plot = *plot_iter;
            found = true;
          }
        }
      }
      iter->next();
    }
    app->deleteIterator(iter);
  }

  //if the plot does not exist, create it
  if (!plot) {
    //put the plot in the active window
    KMdiChildView *activewin = app->activeWindow();
    if (!activewin) {
      QString windowname = app->newWindow("W1");
      activewin = app->findWindow(windowname);
    }
    KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(activewin);
    if (viewwindow) {
      KstTopLevelViewPtr pTLV = viewwindow->view();
      plot = pTLV->createPlot<Kst2DPlot>(ptag);
    }
  }

  while (KST::dataTagNameNotUnique(etag, false)) {
    etag += '\'';
  }

  KstEquationPtr eq = new KstEquation(etag, equation, v, true);

  if (!eq->isValid()) {
    return false;
  }

  KstVCurvePtr vc = new KstVCurve(etag + "-curve", eq->vX(), eq->vY(), 0L, 0L, color.isValid() ? color : KstColorSequence::next(plot->Curves,plot->backgroundColor()));
  KST::dataObjectList.lock().writeLock();
  KST::dataObjectList.append(KstDataObjectPtr(eq));
  KST::dataObjectList.append(KstDataObjectPtr(vc));
  KST::dataObjectList.lock().writeUnlock();

  plot->Curves.append(KstBaseCurvePtr(vc));
  
  _doc->forceUpdate();
  _doc->setModified();

  return true;
}

const QString& KstIfaceImpl::generateScalar(const QString& name, double value) {
  KstScalarPtr s = new KstScalar(name, value);
  KstReadLocker rl(s);
  s->setOrphan(true);
  return s->tagName();
}


const QString& KstIfaceImpl::generateVector(const QString& name, double from, double to, int points) {
  KstVectorPtr v = KstVector::generateVector(from, to, points, name);
  KstReadLocker rl(v);
  return v->tagName();
}


bool KstIfaceImpl::saveVector(const QString& vector, const QString& filename) {
  KstReadLocker ml(&KST::vectorList.lock());
  KstVectorList::Iterator it = KST::vectorList.findTag(vector);

  if (it == KST::vectorList.end() || filename.isEmpty()) {
    return false;
  }

  QFile f(filename);
  if (!f.open(IO_WriteOnly)) {
    return false;
  }

  return 0 == KST::vectorToFile(*it, &f);
}


QStringList KstIfaceImpl::inputVectors(const QString& objectName) {
  KstReadLocker ml(&KST::dataObjectList.lock());
  KstDataObjectList::Iterator oi = KST::dataObjectList.findTag(objectName);
  QStringList rc;

  if (oi != KST::dataObjectList.end()) {
    (*oi)->readLock();
    rc = (*oi)->inputVectors().tagNames();
    (*oi)->readUnlock();
  }

  return rc;
}


QStringList KstIfaceImpl::inputScalars(const QString& objectName) {
  KstReadLocker ml(&KST::dataObjectList.lock());
  KstDataObjectList::Iterator oi = KST::dataObjectList.findTag(objectName);
  QStringList rc;

  if (oi != KST::dataObjectList.end()) {
    (*oi)->readLock();
    rc = (*oi)->inputScalars().tagNames();
    (*oi)->readUnlock();
  }

  return rc;
}


QStringList KstIfaceImpl::outputVectors(const QString& objectName) {
  KstReadLocker ml(&KST::dataObjectList.lock());
  KstDataObjectList::Iterator oi = KST::dataObjectList.findTag(objectName);
  QStringList rc;

  if (oi != KST::dataObjectList.end()) {
    (*oi)->readLock();
    rc = (*oi)->outputVectors().tagNames();
    (*oi)->readUnlock();
  }

  return rc;
}


QStringList KstIfaceImpl::outputScalars(const QString& objectName) {
  KstReadLocker ml(&KST::dataObjectList.lock());
  KstDataObjectList::Iterator oi = KST::dataObjectList.findTag(objectName);
  QStringList rc;

  if (oi != KST::dataObjectList.end()) {
    (*oi)->readLock();
    rc = (*oi)->outputScalars().tagNames();
    (*oi)->readUnlock();
  }

  return rc;
}


double KstIfaceImpl::scalar(const QString& name) {
  KstReadLocker ml(&KST::scalarList.lock());
  KstScalarList::Iterator it = KST::scalarList.findTag(name);

  if (it == KST::scalarList.end()) {
    return 0.0;
  }

  KstReadLocker l2(*it);

  return (*it)->value();
}


bool KstIfaceImpl::setScalar(const QString& name, double value) {
  KstReadLocker ml(&KST::scalarList.lock());
  KstScalarList::Iterator it = KST::scalarList.findTag(name);

  if (it == KST::scalarList.end()) {
    return false;
  }

  KstWriteLocker l2(*it);
  *(*it) = value;
  return true;
}


int KstIfaceImpl::vectorSize(const QString& name) {
  KstReadLocker ml(&KST::vectorList.lock());
  KstVectorList::Iterator it = KST::vectorList.findTag(name);
  int rc = 0;

  if (it != KST::vectorList.end()) {
    (*it)->readLock();
    rc = (*it)->length();
    (*it)->readUnlock();
  }

  return rc;
}


bool KstIfaceImpl::setString(const QString& name, const QString& value) {
  KstReadLocker ml(&KST::stringList.lock());
  KstStringList::Iterator it = KST::stringList.findTag(name);

  if (it == KST::stringList.end()) {
    return false;
  }

  KstWriteLocker l2(*it);
  *(*it) = value;
  return true;
}


const QString& KstIfaceImpl::string(const QString& name) {
  KstReadLocker ml(&KST::stringList.lock());
  KstStringList::Iterator it = KST::stringList.findTag(name);

  if (it != KST::stringList.end()) {
    KstReadLocker ml2(*it);
    return (*it)->value();
  }

  return QString::null;
}


double KstIfaceImpl::vector(const QString& name, int index) {
  KstReadLocker ml(&KST::vectorList.lock());
  KstVectorList::Iterator it = KST::vectorList.findTag(name);
  double rc = 0.0;

  if (it != KST::vectorList.end() && index >= 0) {
    (*it)->readLock();
    if (index < (*it)->length()) {
      rc = (*it)->value(index);
    }
    (*it)->readUnlock();
  }

  return rc;
}


bool KstIfaceImpl::setVector(const QString& name, int index, double value) {
  KstReadLocker ml(&KST::vectorList.lock());
  KstVectorList::Iterator it = KST::vectorList.findTag(name);

  if (it != KST::vectorList.end() && index >= 0) {
    (*it)->writeLock();
    if (index < (*it)->length()) {
      (*it)->value()[index] = value;
      (*it)->writeUnlock();
      return true;
    }
    (*it)->writeUnlock();
  }

  return false;
}


bool KstIfaceImpl::resizeVector(const QString& name, int newSize) {
  KstReadLocker ml(&KST::vectorList.lock());
  KstVectorList::Iterator it = KST::vectorList.findTag(name);

  if (it != KST::vectorList.end()) {
    (*it)->writeLock();
    bool rc = (*it)->resize(newSize);
    if (rc) {
      rc = (*it)->length() == newSize;
    }
    (*it)->writeUnlock();
    return rc;
  }

  return false;
}


bool KstIfaceImpl::clearVector(const QString& name) {
  KstReadLocker ml(&KST::vectorList.lock());
  KstVectorList::Iterator it = KST::vectorList.findTag(name);

  if (it != KST::vectorList.end()) {
    (*it)->writeLock();
    (*it)->zero();
    (*it)->writeUnlock();
    return true;
  }

  return false;
}


QString KstIfaceImpl::createWindow(const QString& name) {
  return KstApp::inst()->newWindow(name);
}


QString KstIfaceImpl::createPlot(const QString& name) {
  QString window = activeWindow();

  //if no window exists, create one
  if (window.isEmpty()) {
    window = KstApp::inst()->newWindow(false);
  }

  return createPlot(window, name);
}


QString KstIfaceImpl::createPlot(const QString& window, const QString& name) {
  KMdiChildView*    pWindow;
  KstViewWindow*    pView;
  KstTopLevelViewPtr pTLV;
  KstApp*           pApp = KstApp::inst();
  Kst2DPlotPtr      p;
  QString           plotName;
  
  pWindow = pApp->findWindow(window);
  if (pWindow) {
    pView = dynamic_cast<KstViewWindow*>(pWindow);
    if (pView) {
      plotName = pView->createPlot<Kst2DPlot>(name, false);
      _doc->forceUpdate();
      _doc->setModified();
    }
  }

  return plotName;
}


bool KstIfaceImpl::deletePlot(const QString& name) {
   QString window = activeWindow();
   if (!window.isEmpty()) {
     return deletePlot(window, name);
   }

   return false;
}


bool KstIfaceImpl::deletePlot(const QString& window, const QString& name) {
  KMdiChildView*    pWindow;
  KstViewWindow*    pView;
  KstTopLevelViewPtr pTLV;
  KstApp*           pApp = KstApp::inst();

  pWindow = pApp->findWindow(window);
  pView = dynamic_cast<KstViewWindow*>(pWindow);
  if (pView) {
    pTLV = pView->view();
    KstViewObjectList::Iterator it;
    KstViewObjectList objects = pTLV->findChildrenType<KstViewObject>(true);

    for (it = objects.begin(); it != objects.end(); ++it) {
      KstViewObjectPtr object = kst_cast<KstViewObject>(*it);
      if (object && object->tagName() == name) {
        pTLV->removeChild(object, true);

        _doc->forceUpdate();
        _doc->setModified();
        return true;
      }
    }
  }

  return false;
}

QStringList KstIfaceImpl::plotContents(const QString& name) {
  //iterate through the windows until plot is found
  KstApp *app = KstApp::inst();
  KMdiIterator<KMdiChildView*> *iter = app->createIterator();
  while (iter->currentItem()) {
    KMdiChildView *childview = iter->currentItem();
    KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(childview);
    if (viewwindow) {
      Kst2DPlotList plotlist = viewwindow->view()->findChildrenType<Kst2DPlot>(false);
      Kst2DPlotList::Iterator plot_iter=plotlist.findTag(name);
      if (plot_iter != plotlist.end()) {
        app->deleteIterator(iter);
        return (*plot_iter)->Curves.tagNames();
      }
    }
    iter->next();
  }
  app->deleteIterator(iter);
  return QStringList();
}

bool KstIfaceImpl::addCurveToPlot(KMdiChildView *win, const QString& plot, const QString& curve) {
  KstViewWindow *w = dynamic_cast<KstViewWindow*>(win);

  if (w) {
    KstTopLevelViewPtr view = kst_cast<KstTopLevelView>(w->view());
    if (view) {
      Kst2DPlotList plots = view->findChildrenType<Kst2DPlot>(true);
      if (plots.findTag(plot) != plots.end()) {
        KstBaseCurveList bcl = kstObjectSubList<KstDataObject,KstBaseCurve>(KST::dataObjectList);
        KstBaseCurveList::Iterator ci = bcl.findTag(curve);
        Kst2DPlotPtr p = *(plots.findTag(plot));
        if (p && ci != bcl.end()) {
          (*ci)->writeLock();
          p->addCurve(*ci);
          (*ci)->writeUnlock();

          _doc->forceUpdate();
          _doc->setModified();

          return true;
        }
      }
    }
  }

  return false;
}


bool KstIfaceImpl::addCurveToPlot(const QString& window, const QString& plot, const QString& curve) {
  KstApp *app = KstApp::inst();
  KMdiChildView *activewin = app->findWindow(window);

  return addCurveToPlot(activewin, plot, curve);
}


bool KstIfaceImpl::addCurveToPlot(const QString& plot, const QString& curve) {
  KstApp *app = KstApp::inst();
  KMdiChildView *activewin = app->activeWindow();

  return addCurveToPlot(activewin, plot, curve);
}


bool KstIfaceImpl::removeCurveFromPlot(KMdiChildView *win, const QString& plot, const QString& curve) {
  KstViewWindow *w = dynamic_cast<KstViewWindow*>(win);

  if (w) {
    KstTopLevelViewPtr view = kst_cast<KstTopLevelView>(w->view());
    if (view) {
      Kst2DPlotList plots = view->findChildrenType<Kst2DPlot>(true);
      if (plots.findTag(plot) != plots.end()) {
        Kst2DPlotPtr p = *(plots.findTag(plot));
        KstBaseCurveList bcl = kstObjectSubList<KstDataObject,KstBaseCurve>(KST::dataObjectList);
        KstBaseCurveList::Iterator ci = bcl.findTag(curve);
        if (p && ci != bcl.end()) {
          (*ci)->readLock();
          p->Curves.remove(*ci);
          (*ci)->readUnlock();

          _doc->forceUpdate();
          _doc->setModified();

          return true;
        }
      }
    }
  }

  return false;
}

bool KstIfaceImpl::removeCurveFromPlot(const QString& window, const QString& plot, const QString& curve) {
  KstApp *app = KstApp::inst();
  KMdiChildView *activewin = app->findWindow(window);

  return removeCurveFromPlot(activewin, plot, curve);
}


bool KstIfaceImpl::removeCurveFromPlot(const QString& plot, const QString& curve) {
  KstApp *app = KstApp::inst();
  KMdiChildView *activewin = app->activeWindow();
  
  return removeCurveFromPlot(activewin, plot, curve);
}


const QString& KstIfaceImpl::createCurve(const QString& name, const QString& xVector, const QString& yVector, const QString& xErrorVector, const QString& yErrorVector) {
  return createCurve(name, xVector, yVector, xErrorVector, yErrorVector, KstColorSequence::next());
}


const QString& KstIfaceImpl::createCurve(const QString& name, const QString& xVector, const QString& yVector, const QString& xErrorVector, const QString& yErrorVector, const QColor& color) {
  QString n = name;
  KST::vectorList.lock().readLock();
  KstVectorPtr vx = *KST::vectorList.findTag(xVector);
  KstVectorPtr vy = *KST::vectorList.findTag(yVector);
  KstVectorPtr ex = *KST::vectorList.findTag(xErrorVector);
  KstVectorPtr ey = *KST::vectorList.findTag(yErrorVector);
  KST::vectorList.lock().readUnlock();

  KST::dataObjectList.lock().writeLock();
  while (KST::dataObjectList.findTag(n) != KST::dataObjectList.end()) {
    n += "'";
  }

  KstVCurvePtr c = new KstVCurve(n, vx, vy, ex, ey, color);
  KST::dataObjectList.append(KstDataObjectPtr(c));
  KST::dataObjectList.lock().writeUnlock();
  _doc->forceUpdate();
  _doc->setModified();

  return c->tagName();
}


bool KstIfaceImpl::printImage(const QString& windowname, const QString& url) {
  KstApp *app = KstApp::inst();
  KMdiChildView *win = app->findWindow(windowname);
  bool bRetVal = false;

  if (!url.isEmpty() && win) {
    app->immediatePrintWindowToPng(win, url);
    bRetVal = true;
  }

  return bRetVal;
}


bool KstIfaceImpl::printImage(const QString& url) {
  KstApp *app = KstApp::inst();
  bool bRetVal = false;

  if (!url.isEmpty()) {
    app->immediatePrintActiveWindowToPng( url );
    bRetVal = true;
  }

  return bRetVal;
}


bool KstIfaceImpl::printPostScript(const QString& windowname, const QString& url) {
  KstApp *app = KstApp::inst();
  KMdiChildView *win = app->findWindow(windowname);
  bool bRetVal = false;

  if (!url.isEmpty() && win) {
    app->immediatePrintWindowToFile(win, url);
    bRetVal = true;
  }

  return bRetVal;
}


bool KstIfaceImpl::printPostScript(const QString& url) {
  KstApp *app = KstApp::inst();
  bool bRetVal = false;

  if (!url.isEmpty()) {
    app->immediatePrintActiveWindowToFile(url);
    bRetVal = true;
  }
  
  return bRetVal;
}


void KstIfaceImpl::reloadVectors() {
  _app->reload();
}


void KstIfaceImpl::reloadVector(const QString& vector) {
  KstReadLocker ml(&KST::vectorList.lock());
  KstVectorList::Iterator v = KST::vectorList.findTag(vector);
  if (v != KST::vectorList.end()) {
    (*v)->writeLock();
    KstRVectorPtr r = kst_cast<KstRVector>(*v);
    if (r) {
      r->reload();
    }
    (*v)->writeUnlock();
  }
}


const QString& KstIfaceImpl::loadVector(const QString& file, const QString& field) {
  KstDataSourcePtr src;
  /* generate or find the kstfile */
  KST::dataSourceList.lock().writeLock();
  KstDataSourceList::Iterator it = KST::dataSourceList.findFileName(file);

  if (it == KST::dataSourceList.end()) {
    src = KstDataSource::loadSource(file);
    if (!src || !src->isValid()) {
      KST::dataSourceList.lock().writeUnlock();
      return QString::null;
    }
    if (src->isEmpty()) {
      KST::dataSourceList.lock().writeUnlock();
      return QString::null;
    }
    KST::dataSourceList.append(src);
  } else {
    src = *it;
  }
  src->writeLock();
  KST::dataSourceList.lock().writeUnlock();

  KST::vectorList.lock().readLock();
  QString vname = "V" + QString::number(KST::vectorList.count() + 1);

  while (KST::vectorTagNameNotUnique(vname, false)) {
    vname = "V" + QString::number(KST::vectorList.count() + 1);
  }
  KST::vectorList.lock().readUnlock();

  KstVectorPtr p = new KstRVector(src, field, vname, 0, -1, 0, false, false);
  KST::addVectorToList(p);

  src->writeUnlock();

  if (p) {
    _doc->forceUpdate();
    _doc->setModified();
    return p->tagName();
  }

  return QString::null;
}


const QString& KstIfaceImpl::fileName() {
  return _doc->absFilePath();
}


bool KstIfaceImpl::save() {
  if (_doc->title() != "Untitled") {
    return _doc->saveDocument(_doc->absFilePath());
  }
  return false;
}


bool KstIfaceImpl::saveAs(const QString& fileName) {
  bool rc = _doc->saveDocument(fileName);
  if (rc) {
    QFileInfo saveAsInfo(fileName);
    _doc->setTitle(saveAsInfo.fileName());
    _doc->setAbsFilePath(saveAsInfo.absFilePath());

    _app->setCaption(kapp->caption() + ": " + _doc->title());
  }
  return rc;
}


void KstIfaceImpl::newFile() {
  _doc->newDocument();
}


bool KstIfaceImpl::open(const QString& fileName) {
  return _app->openDocumentFile(fileName);
}


bool KstIfaceImpl::setMDIMode(int mode){
  KstApp *app = KstApp::inst();
  bool returnval = true;

  switch (mode) {
    case KMdi::ToplevelMode:
      app->switchToToplevelMode();
    break;
    case KMdi::ChildframeMode:
      app->switchToChildframeMode();
    break;
    case KMdi::TabPageMode:
      app->switchToTabPageMode();
    break;
    case KMdi::IDEAlMode:
      app->switchToIDEAlMode();
    break;
    default:
      returnval = false;
    break;
  }

  return returnval;
}

bool KstIfaceImpl::setTileMode(int mode) {
  KstApp *app = KstApp::inst();
  bool returnval = false;

  if (app->mdiMode() == KMdi::ChildframeMode) {
    KMdiChildView *activewin = app->activeWindow();
    if (activewin) {
      returnval = true;
      switch (mode) {
        case 1:
          app->cascadeWindows();
        break;
        case 2:
          app->cascadeMaximized();
        break;
        case 3:
          app->expandVertical();
        break;
        case 4:
          app->expandHorizontal();
        break;
        case 5:
          app->tilePragma();
        break;
        case 6:
          app->tileAnodine();
        break;
        case 7:
          app->tileVertically();
        break;
        default:
          returnval = false;
        break;
      }
    }
  }

  return returnval;
}

bool KstIfaceImpl::closeWindow(const QString& windowname) {
  KstApp *app = KstApp::inst();
  KMdiChildView *win = app->findWindow(windowname);
  
  if (win) {
    app->closeWindow(win, true);
    return true;
  }

  return false;
}


bool KstIfaceImpl::activateWindow(const QString& windowname) {
  KstApp *app = KstApp::inst();
  KMdiChildView *win = app->findWindow(windowname);

  if (win) {
    win->activate();
    return true;
  }

  return false;
}

bool KstIfaceImpl::positionWindow(int topleftX, int topleftY, int width, int height) {
  KstApp *app = KstApp::inst();
  KMdiChildView *win = app->activeWindow();
  
  if (win) {
    if (topleftX >= 0 && topleftY >= 0 && width >= 0 && height >= 0){
      QRect rectangle(topleftX, topleftY, width, height);
      win->setExternalGeometry(rectangle);
      return true;
    }
  }

  return false;
}

bool KstIfaceImpl::maximizePlot(const QString& plotName) {
  KstApp *app = KstApp::inst();
  KMdiIterator<KMdiChildView*> *iter = app->createIterator();
  while (iter->currentItem()) {
    KMdiChildView *childview = iter->currentItem();
    KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(childview);
    if (viewwindow) {
      Kst2DPlotList plotlist = viewwindow->view()->findChildrenType<Kst2DPlot>(false);
      Kst2DPlotList::Iterator plot_iter = plotlist.findTag(plotName);
      if (plot_iter != plotlist.end()) {
        app->deleteIterator(iter);
        (*plot_iter)->zoom(true);
        return true;
      }
    }
    iter->next();
  }
  app->deleteIterator(iter);
  return false;
}

bool KstIfaceImpl::unmaximizePlot(const QString& plotName) {
  KstApp *app = KstApp::inst();
  KMdiIterator<KMdiChildView*> *iter = app->createIterator();
  while (iter->currentItem()) {
    KMdiChildView *childview = iter->currentItem();
    KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(childview);
    if (viewwindow) {
      Kst2DPlotList plotlist = viewwindow->view()->findChildrenType<Kst2DPlot>(false);
      Kst2DPlotList::Iterator plot_iter = plotlist.findTag(plotName);
      if (plot_iter != plotlist.end()) {
        app->deleteIterator(iter);
        (*plot_iter)->zoom(false);
        return true;
      }
    }
    iter->next();
  }
  app->deleteIterator(iter);
  return false;
}

bool KstIfaceImpl::toggleMaximizePlot(const QString& plotName) {
  KstApp *app = KstApp::inst();
  KMdiIterator<KMdiChildView*> *iter = app->createIterator();
  while (iter->currentItem()) {
    KMdiChildView *childview = iter->currentItem();
    KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(childview);
    if (viewwindow) {
      Kst2DPlotList plotlist = viewwindow->view()->findChildrenType<Kst2DPlot>(false);
      Kst2DPlotList::Iterator plot_iter = plotlist.findTag(plotName);
      if (plot_iter != plotlist.end()) {
        app->deleteIterator(iter);
        (*plot_iter)->zoomToggle();
        return true;
      }
    }
    iter->next();
  }
  app->deleteIterator(iter);
  return false;
}

bool KstIfaceImpl::setPlotAxes(const QString& plotName,
  			   int XLower,
  			   int XUpper,
			   int YLower,
			   int YUpper) {
  //find the plot
  KstApp *app = KstApp::inst();
  KMdiIterator<KMdiChildView*> *iter = app->createIterator();
  while (iter->currentItem()) {
    KMdiChildView *childview = iter->currentItem();
    KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(childview);
    if (viewwindow) {
      Kst2DPlotList plotlist = viewwindow->view()->findChildrenType<Kst2DPlot>(false);
      Kst2DPlotList::Iterator plot_iter=plotlist.findTag(plotName);
      if (plot_iter != plotlist.end()) {
        app->deleteIterator(iter);
        (*plot_iter)->setScale(XLower, YLower,
                               XUpper, YUpper);  //set the scale
        return true;
      }
    }
    iter->next();
  }
  app->deleteIterator(iter);
  return false;
}

QString KstIfaceImpl::createHistogram(const QString& name,
			       const QString& vector,
             double min,
			       double max,
			       int numBins,
			       int normalizationType,
             const QColor& color) {

  //get the vector
  KST::vectorList.lock().readLock();
  KstVectorList::Iterator iter = KST::vectorList.findTag(vector);
  KST::vectorList.lock().readUnlock();

  if (iter == KST::vectorList.end()) {
    return QString();
  }

  //set the normalization type
  KstHsNormType normtype;

  switch (normalizationType) {
    case 1:
      normtype = KST_HS_NUMBER;
    break;
    case 2:
      normtype = KST_HS_PERCENT;
    break;
    case 3:
      normtype = KST_HS_FRACTION;
    break;
    case 4:
      normtype = KST_HS_MAX_ONE;
    default:
      normtype = KST_HS_NUMBER;
    break;
  }

  //suggest a name if not supplied
  QString htag_end;
  if (name.isEmpty())
    htag_end = QString(vector);
  else
    htag_end = QString(name);

  //count number of histograms and make a unique name
  KstHistogramList hlist = kstObjectSubList<KstDataObject,KstHistogram>(KST::dataObjectList);
  int i = hlist.count() + 1;
  QString stringnum;
  stringnum = stringnum.setNum(i);

  QString htag = "C" + stringnum + "-HS_" + htag_end;

  while (KST::dataTagNameNotUnique(htag, false)) {
    stringnum.setNum(++i);
    htag = "C" + stringnum + "-HS_" + htag_end;
  }

  KstHistogramPtr histogram = new KstHistogram(htag, *iter, min, max, numBins,
                               normtype);

  KST::dataObjectList.lock().writeLock();
  KST::dataObjectList.append(KstDataObjectPtr(histogram));
  KST::dataObjectList.lock().writeUnlock();

  _doc->forceUpdate();
  _doc->setModified();

  return htag;
}

QString KstIfaceImpl::createPowerSpectrum(const QString & name,
				   const QString& vector,
  				 bool appodize,
				   bool removeMean,
				   int fftLength,
				   const QString& rateUnits,
				   double sampleRate,
				   const QString& vectorUnits,
           const QColor& color) {
  //get the vector
  KST::vectorList.lock().readLock();
  KstVectorList::Iterator iter = KST::vectorList.findTag(vector);
  KST::vectorList.lock().readUnlock();

  if (iter == KST::vectorList.end()) {
    return QString::null;
  }

  //suggest a name if not supplied
  QString pstag_end;
  if (name.isEmpty())
    pstag_end = vector;
  else
    pstag_end = name;

  //count number of power spectra and make a unique name
  KstPSDList pslist = kstObjectSubList<KstDataObject,KstPSD>(KST::dataObjectList);
  int i = pslist.count() + 1;
  QString stringnum = QString::number(i);

  QString pstag = "C" + stringnum + "-PSD_" + pstag_end;

  while (KST::dataTagNameNotUnique(pstag, false)) {
    stringnum.setNum(++i);
    pstag = "C" + stringnum + "-PSD_" + pstag_end;
  }

  KstPSDPtr powerspectrum = new KstPSD(pstag, *iter, sampleRate, true, fftLength,
                               appodize, removeMean, vectorUnits, rateUnits);
  
  // FIXME: should we be plotting this?  Otherwise, remove color
  //KstVCurvePtr vc = new KstVCurve(pstag + "-curve", *iter, powerspectrum->vY(), 0L, 0L, color.isValid() ? color : QColor("darkBlue"));

  KST::dataObjectList.lock().writeLock();
  KST::dataObjectList.append(KstDataObjectPtr(powerspectrum));
  //KST::dataObjectList.append(KstDataObjectPtr(vc));
  KST::dataObjectList.lock().writeUnlock();

  _doc->forceUpdate();
  _doc->setModified();

  return pstag;

}

QString KstIfaceImpl::createEvent(const QString& name,
   			   const QString& expression,
  			   const QString& description,
			   int debugLogType,
			   const QString& email) {

  //suggest a name if not supplied
  QString evtag_end;
  if (name.isEmpty())
    evtag_end = QString(expression);
  else
    evtag_end = QString(name);

  //count number of events and make a unique name
  KstEventMonitorEntryList evlist = kstObjectSubList<KstDataObject,EventMonitorEntry>(KST::dataObjectList);
  int i = evlist.count() + 1;
  QString stringnum;
  stringnum = stringnum.setNum(i);

  QString evtag = "E" + stringnum + "-" + evtag_end;

  while (KST::dataTagNameNotUnique(evtag, false)) {
    stringnum.setNum(++i);
    evtag = "E" + stringnum + "-" + evtag_end;
  }

  EventMonitorEntryPtr event = new EventMonitorEntry(evtag);

  event->setEvent(expression);
  event->setDescription(description);

  if (debugLogType <= 3 && debugLogType >= 1) {
    event->setLogKstDebug(true);
    switch (debugLogType) {
      case 1:
        event->setLevel(KstDebug::Notice);
      break;
      case 2:
        event->setLevel(KstDebug::Warning);
      break;
      case 3:
        event->setLevel(KstDebug::Error);
      break;
      default:
        event->setLevel(KstDebug::Notice);
      break;
    }
  }
  else {
    event->setLogKstDebug(false);
  }
  
  if (email.isEmpty()) {
    event->setLogEMail(false);
  } else {
    event->setLogEMail(true);
    event->setEMailRecipients(email);
  }

  KST::dataObjectList.lock().writeLock();
  KST::dataObjectList.append(KstDataObjectPtr(event));
  KST::dataObjectList.lock().writeUnlock();

  _doc->forceUpdate();
  _doc->setModified();

  return evtag;

}

QStringList KstIfaceImpl::createPlugin(const QString& pluginName,
                                const QStringList& scalarInputs,
                                const QStringList& vectorInputs) {

  PluginCollection *plug_collect = PluginCollection::self();
  KstSharedPtr<Plugin> plug_ptr = plug_collect->plugin(pluginName);


  if (!plug_ptr) {
    return QStringList();
  }

  Plugin::Data plug_data = plug_ptr->data();
  QValueList<Plugin::Data::IOValue>::Iterator IOIter;
  QStringList::ConstIterator scalarParamIter;
  QStringList::ConstIterator vectorParamIter;

  KstPluginPtr kstplug_ptr = new KstPlugin;

  //iterate through inputs
  IOIter = plug_data._inputs.begin();
  scalarParamIter = scalarInputs.begin();
  vectorParamIter = vectorInputs.begin();

  while (IOIter != plug_data._inputs.end()) {
    if ((*IOIter)._type == Plugin::Data::IOValue::TableType
         && (*IOIter)._subType == Plugin::Data::IOValue::FloatSubType) {
      if (vectorParamIter != vectorInputs.end()) {
        KST::vectorList.lock().readLock();
        KstVectorList::Iterator iter = KST::vectorList.findTag(*vectorParamIter);
        KST::vectorList.lock().readUnlock();
        if (iter != KST::vectorList.end()) {
          kstplug_ptr->writeLock();
          kstplug_ptr->inputVectors().insert((*IOIter)._name, *iter);
          kstplug_ptr->writeUnlock();
        }
        else {
          return QStringList();
        }
        vectorParamIter++;
      }
      else {
        return QStringList();
      }
    }
    else if ((*IOIter)._type == Plugin::Data::IOValue::FloatType) {
      if (scalarParamIter != scalarInputs.end()) {
        KST::scalarList.lock().readLock();
        KstScalarList::Iterator iter = KST::scalarList.findTag(*scalarParamIter);
        KST::vectorList.lock().readUnlock();
        if (iter != KST::scalarList.end()) {
          kstplug_ptr->writeLock();
          kstplug_ptr->inputScalars().insert((*IOIter)._name, *iter);
          kstplug_ptr->writeUnlock();
        }
        else {
          return QStringList();
        }
        scalarParamIter++;
      }
      else {
        return QStringList();
      }
    }
    else {
      return QStringList();
    }
    IOIter++;
  }

  //set the plugin
  if (!(kstplug_ptr->setPlugin(plug_ptr))) {
    return QStringList();
  }

  //name the plugin

  KstPluginList kstpluglist = kstObjectSubList<KstDataObject,KstPlugin>(KST::dataObjectList);
  int i = kstpluglist.count() + 1;
  QString stringnum;
  stringnum = stringnum.setNum(i);

  QString plugtag = "P" + stringnum + "-" + pluginName;

  while (KST::dataTagNameNotUnique(plugtag, false)) {
    stringnum.setNum(++i);
    plugtag = "P" + stringnum + "-" + pluginName;
  }
  kstplug_ptr->setTagName(plugtag);

  //try to rename the outputs.  If something is inconsistent just ignore it and
  //leave default output names.
  KstVectorMap::Iterator kstVectorIter = kstplug_ptr->outputVectors().begin();
  KstScalarMap::Iterator kstScalarIter = kstplug_ptr->outputScalars().begin();

  IOIter = plug_data._outputs.begin();
  while (IOIter != plug_data._inputs.end()) {
    if ((*IOIter)._type == Plugin::Data::IOValue::TableType
         && (*IOIter)._subType == Plugin::Data::IOValue::FloatSubType) {
      if (kstVectorIter != kstplug_ptr->outputVectors().end()) {
        QString vectorTag = plugtag + (*IOIter)._name;
        while (KST::dataTagNameNotUnique(vectorTag, false)) {
          vectorTag += '\'';
        }
        kstplug_ptr->writeLock();
        (*kstVectorIter)->setTagName(vectorTag);
        kstplug_ptr->writeUnlock();
        kstVectorIter++;
      }
    }
    else if ((*IOIter)._type == Plugin::Data::IOValue::FloatType) {
      if (kstScalarIter != kstplug_ptr->outputScalars().end()) {
        QString scalarTag = plugtag + (*IOIter)._name;
        while (KST::dataTagNameNotUnique(scalarTag, false)) {
          scalarTag += '\'';
        }
        kstplug_ptr->writeLock();
        (*kstScalarIter)->setTagName(scalarTag);
        kstplug_ptr->writeUnlock();
        kstScalarIter++;
      }
    }
    IOIter++;
  }

  //return the output list, vectors followed by scalars
  QStringList outputList;

  kstVectorIter = kstplug_ptr->outputVectors().begin();
  kstScalarIter = kstplug_ptr->outputScalars().begin();
  while (kstVectorIter != kstplug_ptr->outputVectors().end()) {
    outputList += (*kstVectorIter)->tagName();
  }

  while (kstScalarIter != kstplug_ptr->outputScalars().end()) {
    outputList += (*kstScalarIter)->tagName();
  }
  return outputList;
}

QString KstIfaceImpl::createMatrix(const QString& name, const QString& vector, double xMin, double yMin,
                                                   double xStepSize, double yStepSize,
                                                   uint xNumSteps, uint yNumSteps,
                                                   bool useMaxX) {
  //get the vector
  KST::vectorList.lock().readLock();
  KstVectorList::Iterator iter = KST::vectorList.findTag(vector);
  KST::vectorList.lock().readUnlock();

  if (iter == KST::vectorList.end()) {
    return QString();
  }

  //suggest a name if not supplied
  QString artag;
  if (name.isEmpty()) {
    artag = KST::suggestMatrixName(vector);
  } else {
    QString artag_end = QString(name);
    //count number of data objects and make a unique name
    int i = KST::dataObjectList.count() + 1;
    QString artag = "A" + QString::number(i) + "-" + artag_end;
  }
  while (KST::dataTagNameNotUnique(artag, false)) {
    artag += "\'";
  }

  //basic check to see if parameters are consistent with vector
  (*iter)->readLock();
  if (!useMaxX && (*iter)->sampleCount() < (int)(xNumSteps * yNumSteps)) {
    (*iter)->readUnlock();
    return QString();
  }

  //can't let yNumSteps be less than 1, or will divide by 0
  if (yNumSteps < 1) {
    (*iter)->readUnlock();
    return QString();
  }

  if (xStepSize <= 0 || yStepSize <= 0) {
    (*iter)->readUnlock();
    return QString();
  }
  (*iter)->readUnlock();

  //create the matrix
  KstMatrixPtr matrix = new KstMatrix(artag, *iter, xNumSteps, yNumSteps, xMin, yMin, xStepSize, yStepSize, useMaxX);

  KST::dataObjectList.lock().writeLock();
  KST::dataObjectList.append(KstDataObjectPtr(matrix));
  KST::dataObjectList.lock().writeUnlock();

  _doc->forceUpdate();
  _doc->setModified();

  return artag;
}

QString KstIfaceImpl::createImage(const QString &name,
                                  const QString &in_matrix,
                                  double lowerZ,
                                  double upperZ,
                                  const QString &paletteName,
                                  int numContours,
                                  const QColor& contourColor,
                                  uint imageType) {
  //get the matrix
  KstMatrixList matrices = kstObjectSubList<KstDataObject, KstMatrix>(KST::dataObjectList);
  KstMatrixPtr matrix = *matrices.findTag(in_matrix);
  if (!matrix) {
    return QString::null;
  }

  //make a name if necessary
  QString imgtag;
  if (name.isEmpty()) {
    imgtag = KST::suggestImageName(in_matrix);
  } else {
    QString imgtag_end = QString(name);
    //count number of data objects and make a unique name
    int i = KST::dataObjectList.count() + 1;
    QString imgtag = "Img" + QString::number(i) + "-" + imgtag_end;
  }
  while (KST::dataTagNameNotUnique(imgtag, false)) {
    imgtag += "\'";
  }

  //determine the image type
  KstImagePtr image;
  if (imageType == 0) {
    //need a colormap
    if (lowerZ > upperZ) {
      return QString::null;
    }
    KPalette* pal = new KPalette(paletteName);
    matrix->readLock();
    image = new KstImage(imgtag, matrix, lowerZ, upperZ, false, pal);
    matrix->readUnlock();
  } else if (imageType == 1) {
    //need a contourmap
    if (numContours < 1) {
      return QString::null;
    }
    matrix->readLock();
    image = new KstImage(imgtag, matrix, numContours, contourColor.isValid() ? contourColor : QColor("darkBlue"), 0);
    matrix->readUnlock();
  } else if (imageType == 2) {
    //need both contourmap and colormap
    if (lowerZ > upperZ) {
      return QString::null;
    }
    KPalette* pal = new KPalette(paletteName);
    if (!pal) {
      return QString::null;
    }
    if (numContours < 1) {
      return QString::null;
    }
    matrix->readLock();
    image = new KstImage(imgtag, matrix, lowerZ, upperZ, false, pal,
                         numContours, contourColor.isValid() ? contourColor : QColor("darkBlue"), 0);
    matrix->readUnlock();
  } else {
    return QString::null;
  }

  KST::dataObjectList.lock().writeLock();
  KST::dataObjectList.append(KstDataObjectPtr(image));
  KST::dataObjectList.lock().writeUnlock();

  _doc->forceUpdate();
  _doc->setModified();

  return imgtag;

}

bool KstIfaceImpl::addPlotMarker(const QString &plotName, double markerValue) {
  //find the plot
  KstApp *app = KstApp::inst();
  KMdiIterator<KMdiChildView*> *iter = app->createIterator();
  while (iter->currentItem()) {
    KMdiChildView *childview = iter->currentItem();
    KstViewWindow *viewwindow = dynamic_cast<KstViewWindow*>(childview);
    if (viewwindow) {
      Kst2DPlotList plotlist = viewwindow->view()->findChildrenType<Kst2DPlot>(false);
      Kst2DPlotList::Iterator plot_iter=plotlist.findTag(plotName);
      if (plot_iter != plotlist.end() && (*plot_iter)->setPlotMarker(markerValue)) {
        app->deleteIterator(iter);
        return true;
      }
    }
    iter->next();
  }
  app->deleteIterator(iter);
  return false;
}
// vim: ts=2 sw=2 et
