/***************************************************************************
**
**  This file is part of QGpCoreTools.
**
**  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: 2004-11-27
**  Copyright: 2004-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "XMLClassFactory.h"
#include "CoreApplication.h"

namespace QGpCoreTools {

  /*!
    \fn virtual XMLClass * XMLClassCreator::create() const
    Abstract function called by XMLClassFactory for creating a new instance.
  */

  /*!
    \class XMLClassFactory XMLClassFactory.h
    \brief XMLClassFactory provides creation of instances of classes from their XML tag
  */

  QList<XMLClassFactory *> XMLClassFactory::_factories;

  /*!
    Registers all factories to properly delete them upon exit.

    \sa clearFactories()
  */
  void XMLClassFactory::registerFactory(XMLClassFactory * f)
  {
    _factories.append(f);
  }

  /*!
    Clear all factories. Used by CoreApplicationPrivate::~CoreApplicationPrivate().
  */
  void XMLClassFactory::clearFactories()
  {
    qDeleteAll(_factories);
    _factories.clear();
  }


  /*!
    Destructor
  */
  XMLClassFactory::~XMLClassFactory()
  {
    // Registered classes are not deleted. If the macros are correctly used,
    // each class creator is a static object. The class factory does not have
    // ownership of these blocks.
  }

  /*!
    Returns the list of all registered tags
  */
  QStringList XMLClassFactory::registeredTags() const
  {
    QStringList l;
    QMap<QString, int>::const_iterator it;
    for(it=_registeredTags.begin(); it!=_registeredTags.end(); it++) {
       l.append(it.key());
    }
    return l;
  }

  /*!
    Returns the list of all registered ids
  */
  QList<int> XMLClassFactory::registeredIds() const
  {
    QList<int> l;
    QMap<int, XMLClassCreator *>::const_iterator it;
    for(it=_registeredClasses.begin(); it!=_registeredClasses.end(); it++) {
       l.append(it.key());
    }
    return l;
  }

  /*!
    Returns id corresponfing to \a tag, or -1 if it does not exist.
  */
  int XMLClassFactory::id(const QString& tag) const
  {
    QMap<QString, int>::const_iterator it;
    it=_registeredTags.find(tag);
    if(it!=_registeredTags.end()) {
      return it.value();
    } else {
      return -1;
    }
  }

  /*!
    Returns a new class corresponding to \a id or null if it is not registered.
  */
  XMLClass * XMLClassFactory::create(int id) const
  {
    XMLClassCreator * c=creator(id);
    if(c) {
      return c->create();
    } else {
      return nullptr;
    }
  }

  /*!
    Returns a new class corresponding to \a tag or null if it is not registered.
  */
  XMLClass * XMLClassFactory::create(const QString& tag) const
  {
    QMap<QString, int>::const_iterator it;
    it=_registeredTags.find(tag);
    if(it!=_registeredTags.end()) {
      return create(it.value());
    } else {
      return nullptr;
    }
  }

  /*!
    Returns creator corresponding to \a tag or 0 if not registered.
  */
  XMLClassCreator * XMLClassFactory::creator(const QString& tag) const
  {
    QMap<QString, int>::const_iterator it;
    it=_registeredTags.find(tag);
    if(it!=_registeredTags.end()) {
      return creator(it.value());
    } else {
      return nullptr;
    }
  }

  /*!
    Returns creator corresponding to \a id or 0 if not registered.
  */
  XMLClassCreator * XMLClassFactory::creator(int id) const
  {
    QMap<int, XMLClassCreator *>::const_iterator it;
    it=_registeredClasses.find(id);
    if(it!=_registeredClasses.end()) {
      return it.value();
    } else {
      return nullptr;
    }
  }

  /*!
    Registers class with \a tag and its creator class. Returns its unique id.
  */
  int XMLClassFactory::registerClass(const QString& tag, XMLClassCreator * creator)
  {
    int id=_nextId++;
    _registeredClasses.insert(id, creator);
    _registeredTags.insert(tag, id);
    return id;
  }

  /*!
    Registers a new \a tag for class \a id;
  */
  void XMLClassFactory::registerTag(const QString& tag, int id)
  {
    _registeredTags.insert(tag, id);
  }

  /*!
    Registers a new \a tag for class \a id;
  */
  void XMLClassFactory::registerTag(const QString& tag, const QString& destTag)
  {
    QMap<QString, int>::const_iterator it;
    it=_registeredTags.find(destTag);
    if(it!=_registeredTags.end()) {
      registerTag(tag, it.value());
    } else {
      qWarning("XMLClassFactory::registerTag: unknown destination tag '%s'", destTag.toLatin1().data());
    }
  }

  /*!
    Does nothing but it avoid weak vtables
  */
  XMLClass * XMLClassCreator::create() const
  {
    return nullptr;
  }

} // namespace QGpCoreTools
