/***************************************************************************
 $RCSfile: api.h,v $
                             -------------------
    cvs         : $Id: api.h,v 1.33 2003/06/23 22:52:33 cstim Exp $
    begin       : Sat Jun 08 2002
    copyright   : (C) 2001 by Martin Preuss
    email       : openhbci@aquamaniac.de

 ***************************************************************************
 *                                                                         *
 *   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 library 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., 59 Temple Place, Suite 330, Boston,                 *
 *   MA  02111-1307  USA                                                   *
 *                                                                         *
 ***************************************************************************/

/** @file api.h
 *
 * @short Contains the definition of HBCI::API as well as its @ref
 * HBCI_API C wrapper functions.  */

#ifndef HBCIAPI_H
#define HBCIAPI_H

#ifdef __cplusplus
#include <string>
#include <list>

namespace HBCI {
  class API;
};

#endif /* __cplusplus */
#include <openhbci/dllimport.h>
#include <openhbci/hbci.h>
#include <openhbci/pointer.h>
#include <openhbci/error.h>
#include <openhbci/bank.h>
#include <openhbci/account.h>
#include <openhbci/medium.h>
#include <openhbci/mediumpluginlist.h>
#ifdef __cplusplus
#include <openhbci/adminjobs.h>


/** @short This is the C-accessible type for the central OpenHBCI
 * class HBCI::API.
 *
 * For the "real" documentation of what you can do with objects of
 * this class, always remember to look up the member method
 * documentation (especially if the C function is not [yet]
 * documented). E.g., for <code>@ref HBCI_API_loadEnvironment()</code>,
 * look up the documentation of <code>@ref
 * HBCI::API::loadEnvironment</code>.
 *
 * Just like in C++, once you got an existing OpenHBCI configuration
 * file and setup, you only need a few steps to use it in C:
 *
 * <ul> <li><code>@ref HBCI_API_loadEnvironment()</code>: to load all
 * known users, accounts, and banks from the configuration file</li>
 * <li>create jobs (e.g. <code>@ref HBCI_OutboxJobGetBalance</code>)</li>
 * <li>add the jobs to the outbox (<code>@ref HBCI_API_addJob()</code>)</li>
 * <li><code>@ref HBCI_API_executeQueue()</code>: to perform all those jobs</li>
 * <li><code>@ref HBCI_API_saveEnvironment()</code>: to finally save all
 * data back to the configuration file</li> </ul>
 *
 * @ingroup HBCI_APIg
 * */
typedef struct HBCI::API HBCI_API;
#else /* __cplusplus */
typedef struct HBCI_API HBCI_API;
#endif /* __cplusplus */

#ifdef __cplusplus
#include <openhbci/loader.h>
#include <openhbci/outbox.h>
#include <openhbci/mediumplugin.h>
#include <openhbci/mediumpluginfile.h>
#endif /* __cplusplus */
#include <openhbci/progressmonitor.h>
#include <openhbci/outboxjob.h>
#ifdef __cplusplus

#define HBCIAPP_CONFIG_MODE (\
    PARSER_FLAGS_SKIP_BLANKS            |\
    PARSER_FLAGS_CUT_BLANKS             |\
    PARSER_FLAGS_REMOVE_QUOTATION_MARKS |\
    CONFIG_MODE_QUOTED_VALUES           |\
    CONFIG_MODE_UNIQUE_VARS             |\
    CONFIG_MODE_RETURN_ON_ERROR         |\
    CONFIG_MODE_WRITE_GROUP_NAME        |\
    CONFIG_MODE_IGNORE_GROUP_CASE       |\
    CONFIG_MODE_IGNORE_VAR_CASE         |\
    CONFIG_MODE_ALLOW_EMPTY_VALUES      |\
    CONFIG_MODE_ONE_VALUE_PER_LINE      |\
    CONFIG_MODE_BACKSLASH_CONTINUATION)


/**
 * @short Namespace for all OpenHBCI classes.
 */
namespace HBCI {

class Connection;
    
/**
 * @short This is the central OpenHBCI wrapper class.
 *
 * Once you got an existing OpenHBCI configuration file and setup, you
 * only need a few steps to use it:
 *
 * <ul>
 * <li><code>@ref loadEnvironment</code>: to load all known users, accounts, 
 * and banks from the configuration file</li>
 * <li>create jobs (derived from <code>@ref OutboxJob</code>)</li>
 * <li>add the jobs to the outbox (<code>@ref addJob</code>)</li>
 * <li><code>@ref executeQueue</code>: to perform all those jobs</li>
 * <li><code>@ref saveEnvironment</code>: to finally save all data
 * back to the configuration file</li> </ul>
 *
 * For first-time use, there are a few additional steps. As an
 * example, have a look at aqmoney and/or cmoney and what they do.
 * In short:
 * <ul>
 * <li>Create a bank with <code>@ref bankFactory</code>, 
 * add it to the list with <code>@ref addBank</code></li>
 * <li>Create a new medium with <code>@ref createNewMedium</code></li>
 * <li>Create a user with <code>@ref userFactory</code> using the new 
 * medium, add it to the <code>Bank</code> with <code>Bank::addUser</code></li>
 * <li>Create a customer with <code>@ref customerFactory</code>, add
 * it to the <code>User</code> with
 * <code>User::addCustomer</code></li>
 * <li>Save the newly created environment with 
 * <code>@ref saveEnvironment</code>.</li>
 * <li>For RDH medium (key file):
 *   <ul>
 *   <li>Create an <code>OutboxJobGetKeys</code> to get the 
 *   bank server's keys (<code>@ref addJob</code>, 
 *   <code>@ref executeQueue</code>) 
 *   and compare it with their Ini-Letter. If it 
 *   doesn't match, you better stop contacting that server.</li>
 *   <li>Create an <code>OutboxJobSendKeys</code> to send your 
 *   newly created keys (from the medium) to the server
 *   (<code>@ref addJob</code>, 
 *   <code>@ref executeQueue</code>), using your newly created Customer.</li>
 *   <li>Create the user's Ini-Letter by querying the appropriate methods in 
 *   <code>MediumRDHBase</code>, e.g. 
 *   <code>MediumRDHBase::getUserIniLetterModulus</code>, print it out
 *   and send it to your bank. Then wait several days until the bank
 *   has received and processed the user's Ini-Letter.</li>
 *   <li>When the bank has processed/accepted the user's Ini-letter,
 *   execute an <code>OutboxJobGetSystemId</code> to let the bank
 *   assign a synchronization id to your client system, using your
 *   newly created Customer. (FIXME: Is it correct that this can't be
 *   done before the ini-letter has been processed?)</li>
 *   </ul>
 * For DDV medium (chip card) you can proceed immediately.</li>
 * <li>Now get the list of all accessible accounts with an 
 * <code>OutboxJobGetAccounts</code>, which also creates the necessary 
 * Account and Customer objects. </li>
 * <li>Save the updated environment with 
 * <code>@ref saveEnvironment</code> and continue with other 
 * (real) OutboxJobs according to the bullet list above.</li>
 * </ul>
 * @author Martin Preuss<martin@libchipcard.de> */
class DLLIMPORT API : public Hbci {
  friend class OutboxJobKeys; /* for postProcessInitJob */
  friend class OutboxJobSynchronize; /* for postProcessInitJob */
  friend class OutboxJobDisableKeys; /* for postProcessInitJob */
  friend class OutboxJobChangeKeys; /* for postProcessInitJob */
private:
  list<Pointer<Bank> > _banks;
  list<Pointer<MediumPlugin> > _mediumPlugins;
  list<Pointer<MediumPluginFile> > _pluginFiles;
  Pointer<Loader> _loader;
  Pointer<ProgressMonitor> _monitor;
  Pointer<Outbox> _queue;
  static unsigned _nextTransactionId;

  void _logMessage(int loglevel, const string &msg);
  Error _handleMessageQueue(Pointer<Connection> conn,
			    Pointer<MessageQueue> mbox);
  Error _handleJobQueue(const list<Pointer<OutboxJob> > &jq,
			Pointer<Connection> conn,
			Pointer<MessageQueue> mbox,
			bool dlg,
			bool chg);
  Error _handleUserQueue(Pointer<customerQueue> q,
			 Pointer<Connection> conn,
			 bool chg=true);
  Error _handleBankQueue(Pointer<bankQueue> q, bool chg=true);
  Error _handleQueue(Pointer<Outbox> q, bool chg=true);

  string _getLibraryPrefix(const string &path);
  Pointer<MediumPlugin> _findMediumPlugin(const string &name);
  Error _tryToLoadPlugin(const string &path, const list<string> &mtye);
  Error _tryToLoadPlugin(const list<string> &dnames, const string &mtyes);
  Pointer<MediumPlugin> _ensureMediumPlugin(const string &name);
  void _addPluginsFromDirs(Pointer<MediumPluginList> pl,
			   const list<string> &dname);

  /**
   * This method commits changes inflicted by a JOBDialogInit.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  Error postProcessInitJob(JOBDialogInit &job);

  /**
   * This method reads all institute messages from the given message
   * queue and sorts them to the appropriate banks.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  Error processInstituteMessages(Pointer<MessageQueue> mbox);

public:
  /**
   *  Constructor.
   *
   * @author Martin Preuss<martin@libchipcard.de>
   *
   * @param readonly if true then no jobs are allowed which actually
   * do something with your account at the
   * bank. (e.g. JobSingleTransfer)
   *
   * @param retrievalOnly If set to true, OpenHBCI will only store
   * the minimum of data per account required for subsequent
   * retrieval of account data. I.e. it will not store the balance,
   * transactions, and standing orders of an account.
   */
  API(bool readonly = false,
      bool retrievalOnly = false);

  /**  Default Destructor. */
  ~API();

  /** @name File operations
   *
   * Methods to load and save HBCI::API's data to a file. */
  /*@{*/
  /**
   *  Load all banks, users and accounts.
   *
   * There is a flag to define which parts of the data are supposed
   * to be loaded. Generally you wouldn't need to specify anything
   * else than the default. If you are really sure that you need to
   * specify something non-default, then please study the
   * implementation of the data loading and saving process in the
   * HBCI::Loader class.
   *
   * @param filename The name of the file where data is loaded from.
   * @param fl Flag to define which part of the data should be loaded
   * @author Martin Preuss<martin@libchipcard.de> */
  Error loadEnvironment(const string &filename,
			unsigned int fl=HBCILOADER_DEFAULT);

  /**
   *  Save all banks, users, accounts.
   *
   * There is a flag to define which parts of the data are supposed
   * to be saved. Generally you wouldn't need to specify anything
   * else than the default. If you are really sure that you need to
   * specify something non-default, then please study the
   * implementation of the data loading and saving process in the
   * HBCI::Loader class.
   *
   * @param filename The name of the file where data is saved to.
   * @param fl Flag to define which part of the data should be saved
   * @author Martin Preuss<martin@libchipcard.de> */
  Error saveEnvironment(const string &filename,
			unsigned int fl=HBCILOADER_DEFAULT) const;
  /*@}*/

  /** @name Object Retrieval
   *
   * Methods that return the objects owned by HBCI::API.*/
  /*@{*/
#ifndef OPENHBCI_NO_COMPAT
  /**
   *  Returns the list of known banks.
   *
   * List of known banks. May be used for browsing
   * or saving them to disk.
   * This method is deprecated, newer programs should use @ref banks()
   * instead.
   * @return a list of all known banks
   * @author Martin Preuss<martin@libchipcard.de>
   */
  const list<Pointer<Bank> > &bankList() const
    { return banks(); };
#endif

  /**
   *  Returns the list of known banks.
   *
   * List of known banks. May be used for browsing
   * or saving them to disk.
   * @return a list of all known banks
   * @author Martin Preuss<martin@libchipcard.de>
   */
  const list<Pointer<Bank> > &banks() const
    { return _banks; };

  /**
   *  Search for a bank.
   *
   * Searches for a bank in the internally stored list.
   * No joker or wildcard allowed.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param country Country code
   * @param instcode Bank code
   */
  Pointer<Bank> findBank(int country, const string &instcode) const;

  /**
   * Searches for a medium of the given name. It therefore checks
   * the media of all already knowncustomers.
   *
   * @author Martin Preuss<martin@libchipcard.de>
   * @param name medium name (card number in case of a chip card (DDV), file
   * path and name in case of a keyfile (RDH)) */
  Pointer<Medium> findMedium(const string &name) const;

  /**
   *  Get a list of matching accounts.
   *
   * Returns a list of all matching accounts known to the system.
   * This method creates a new list and returns it. Please note that
   * changes made to the accounts in the list returned WILL affect these
   * accounts in any list. This is due to the usage of Pointer.
   * This way it is much easier to modify accounts.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  list<Pointer<Account> >
    getAccounts(int country=0,
		const string &bankId="*",
		const string &accountId="*") const;

  /**
   *  Get a list of matching users.
   *
   * This method collects a list of users that match the given criteria.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param country country code (280 for Germany, 0 matches all)
   * @param instid institute id (German "Bankleitzahl"), joker ("?") and
   * wildcards ("*") are allowed
   * @param userid id assigned to you by your bank, joker ("?") and
   * wildcards ("*") are allowed
   */
  list<Pointer<User> >
    getUsers(int country=0,
	     const string &instid="*",
	     const string &userid="*") const;

  /**
   *  Get a list of matching customers.
   *
   * This method collects a list of customers that match the given criteria.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param country country code (280 for Germany, 0 matches all)
   * @param instid institute id (German "Bankleitzahl"), joker ("?") and
   * wildcards ("*") are allowed
   * @param custid id assigned to you by your bank, joker ("?") and
   * wildcards ("*") are allowed
   */
  list<Pointer<Customer> >
    getCustomers(int country=0,
		 const string &instid="*",
		 const string &custid="*") const;
  /*@}*/

  /** @name Convenience Object Retrieval
   *
   * Methods that return objects owned by a Bank that is owned
   * by HBCI::API. These methods just execute a HBCI::API::findBank
   * first, then execute that Bank's method to find the desired
   * object. */
  /*@{*/
  /**
   * Searches for an account in the internally stored list.
   * No joker or wildcard allowed.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param country Country code of the bank
   * @param instcode Bank code of the bank
   * @param accnr Account number of the account
   * @param suffix New in HBCI2.2: Account number suffix
   */
  Pointer<Account> findAccount(int country,
			       const string &instcode,
			       const string &accnr,
			       const string &suffix="") const;

  /**
   * Searches for a user in the internally stored lists.
   * No joker or wildcard allowed.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param country Country code of the bank
   * @param instcode Bank code of the bank
   * @param user User ID of the user
   */
  Pointer<User> findUser(int country,
			 const string &instcode,
			 const string &user) const;

  /**
   * Searches for a customer in the internally stored lists.
   * No joker or wildcard allowed.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param country Country code of the bank
   * @param instcode Bank code of the bank
   * @param cust Customer ID of the customer
   */
  Pointer<Customer> findCustomer(int country,
				 const string &instcode,
				 const string &cust) const;

  /** Returns the total number of accounts that exist within all
   * banks of this API.
   *
   * @author Christian Stimming <stimming@tuhh.de>
   * @return Number of accounts in this API.  */
  int totalAccounts() const;

  /** Returns the total number of users that exist within all banks
   * of this API.
   *
   * @author Christian Stimming <stimming@tuhh.de>
   * @return Number of users in this API.  */
  int totalUsers() const;
  /*@}*/

  /** @name Manage Objects
   *
   * Methods to manage the list of objects owned by HBCI::API.
   */
  /*@{*/
  /**
   *  Add a bank.
   *
   * Add a bank to the internally stored list. Throws an Error if
   * this bank already exists.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  void addBank(Pointer<Bank> b);

  /**
   *  Remove a bank.
   *
   * Removes the given bank from the internal list.  The object
   * itself is not destroyed (since Pointers have automatic
   * reference-counting). After this method call, the object is in
   * the same state as one returned by
   * HBCI::API::bankFactory(). I.e. since it doesn't belong to any
   * internal lists it is not allowed to be used in subsequent calls
   * to OpenHBCI.
   * @author Martin Preuss<martin@libchipcard.de> */
  void removeBank(Pointer<Bank> b);
  /*@}*/

  /** @name OutboxJob Management
   *
   * Methods to get and set the OutboxJob's managed through HBCI::API.
   */
  /*@{*/
  /**
   *  Add a job to the internal outbox queue.
   *
   * This method accepts a HBCI::Pointer to an OutboxJob, not one to
   * a derived class OutboxJobSomething. Since the HBCI::Pointer
   * doesn't do automatic (up)casting, you need to use the Pointer's
   * Pointer::cast() method explicitly: Use
   * <code>myApi.addJob(myDerivedJob.cast<OutboxJob>())</code>.
   *
   * Unlike in former versions you still have access to the jobs,
   * since you only supply a pointer with this method.
   *
   * For now no error is returned (i.e. it will always indicate success),
   * but maybe later this method will check if the given job fits into the
   * current queue.
   *
   * @author Martin Preuss<martin@libchipcard.de> */
  Error addJob(Pointer<OutboxJob> job);

  /**
   *  Execute jobs in queue.
   *
   * This method executes all jobs in the outbox queue.
   *
   * The jobs remain in the queue until you remove them either via
   * @ref clearQueueByStatus() or via @ref clearQueueByResult().
   * Since the queue contains a list of (reference-counting)
   * Pointers, the jobs will only be destroyed via
   * clearQueueBy*() if you don't have any further Pointers
   * stored on your own, otherwise your own Pointers will still
   * be valid and will take care of deletion.
   *
   * @param chg Specifies whether the jobs in the queue are allowed
   * to change your OpenHBCI data. This affects both HBCI-specific
   * data such as the UPD/BPD (user/bank parameter data) as well as
   * financial data of your accounts such as balance, transactions and
   * standing orders.
   * If this flag is false, then NO changes are made in your OpenHBCI data
   * at all.
   * FIXME: Maybe we should modify this, at least the UPD/BPD should
   * be updated accordingly ! (Martin)
   *
   * @author Martin Preuss<martin@libchipcard.de> */
  Error executeQueue(bool chg=true);

  /**
   *  Returns a list of all queued jobs.
   *
   * Returns a list of all queued jobs, of all customers and banks.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  list<Pointer<OutboxJob> > queuedJobs() const;

  /**
   *  Remove all jobs with the given result code.
   *
   * @param result The result code, where all jobs with that result
   * code are removed from the queue. If HBCI_JOB_RESULT_NONE is
   * given then ALL jobs are removed.
   *
   * @author Martin Preuss<martin@libchipcard.de> */
  void clearQueueByResult(OutboxJob_Result result=HBCI_JOB_RESULT_NONE);

  /**
   *  Remove all jobs with the given status code.
   *
   * @param status The status code, where all jobs with that status
   * code are removed from the queue. If HBCI_JOB_RESULT_NONE is
   * given then ALL jobs are removed.
   *
   * @author Martin Preuss<martin@libchipcard.de>
   */
  void clearQueueByStatus(OutboxJob_Status status=HBCI_JOB_STATUS_NONE);

  /**
   *  Removes a given job from the queue.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  void removeQueuedJob(Pointer<OutboxJob> job);
  /*@}*/

  /** @name User Interaction
   *
   * Methods to get and set the user interaction classes.  */
  /*@{*/
  /**
   *  Returns a pointer to the current progress monitor.
   *
   * The default monitor dumps all messages to stderr. Set a new
   * monitor if you want to use other means to show a progress.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  Pointer<ProgressMonitor> monitor() const;

  /**
   *  Set the current progress monitor.
   *
   * Set a new progress monitor to be used.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param monitor pointer to the monitor to use
   */
  void setMonitor(Pointer<ProgressMonitor> monitor);
  /*@}*/

  /** @name Factory Methods
   *
   * Factory methods for the main objects within OpenHBCI. These are
   * normal members of HBCI::API.  Factory methods are necessary
   * instead of using constructors since the actual implementation
   * classes are not visible for the application (and should never
   * be). */
  /*@{*/
  /**
   *  Creates a bank object.
   *
   * This will NOT be automatically added to internally stored lists.
   * @author Martin Preuss<martin@libchipcard.de>
   *
   * @param country The ISO-3166 country code of this bank. ("280"
   * is for Germany; see also HBCI::Bank::countryCode.)
   * @param bankCode The bank code of this bank.
   * @param server The IP address of the HBCI server of this bank.
   * @param hbciVersion The HBCI protocol version used with this
   * bank in dotted notation.
   */
  Pointer<Bank>
    bankFactory(int country=280,
		const string &bankCode="",
		const string &server="",
		int hbciVersion=HBCI_VERSION_201) const;

  /**
   *  Creates an medium object.
   *
   * This will NOT be automatically added to internally stored
   * lists.
   *
   * This method rather than HBCI::API::createNewMedium is to be used
   * when the actual medium already exists (i.e. the RDH
   * keyfile).
   *
   * @author Martin Preuss<martin@libchipcard.de>
   * @param name The name of this medium (see createNewMedium)
   * @param mediumType Chooses the kind of medium to be created.
   */
  Pointer<Medium> mediumFactory(const string &name,
				const string &mediumType);


  /**
   *  Creates a new Medium object (and perhaps a new medium file).
   *
   * The newly created object will not be added to internally stored
   * lists; also, no bank, user, or customer object is being created.
   *
   * In case of a DDV medium (chip card) there is not much to be
   * done since all the information is on the DDV chipcard --
   * therefore simply the Medium object is created and returned.
   *
   * In case of a RDH medium (keyfile), this method will perform
   * the following steps:
   * <ul>
   * <li> Create the keyfile if it does not exist.  If a file with
   * the same name does exist already, then this method will assume
   * that this file already is a keyfile and will return the
   * MediumRDHBase object with the path of that file (without further
   * checking, i.e. if that file isn't a keyfile, you will run into
   * errors upon medium mounting).</li>
   * <li> For a new file, create the given user on the medium.</li>
   * <li> For a new file, generate new sign and crypt keys for this user</li>
   * <li> Save the new keyfile and return the MediumRDHBase object pointing
   * to that file.</li>
   * </ul>
   *
   * Throws an Error upon error, e.g. when bankId or userid are
   * empty.
   *
   * Please note that under no circumstances this method will
   * overwrite a file. If the file already exists, then this method
   * assumes that the file contains a valid medium. In that case no
   * keys will be created. You can try to mount the medium after
   * calling this method to check if the existing file really is a
   * medium. But beware: when changing data in the medium prior to
   * mounting it (e.g. by creating new keys) then the file may be
   * overwritten by the medium class. (see also @ref MediumRDHBase )
   *
   * @author Martin Preuss<martin@libchipcard.de>
   * @return smart pointer to the new medium created
   * @param mtype chooses the kind of medium to be created
   * @param readonly REMOVE_ME
   * @param country ISO-3166 country code. In HBCI, "280" stands for
   * Germany (see also @ref Bank::countryCode)
   * @param bankId The bank code of the bank of this user (German
   * "Bankleitzahl")
   * @param userId The user ID of the user; assigned by the bank
   * @param name For DDV media (chip card), this should be the
   * unique card number stored on the card, or simply an empty
   * string. For RDH media (keyfile), this MUST be the full path and
   * filename of the keyfile.
   */
  Pointer<Medium> createNewMedium(const string &mtype,
                                  bool readonly,
				  int country,
				  const string &bankId,
				  const string &userId,
				  const string &name);

  /**
   * This method is used to create a medium object using the data given in
   * a configuration file.
   * The only mandatory variable is "typename", because its content is used to
   * determine which plugin has to provide the medium.
   * This method loads the appropriate plugin if needed.
   * The plugin may then use whichever variables it finds necessary.
   * If the corresponding plugin is not available an exception will
   * be thrown
   */
  Pointer<Medium> mediumFromConfig(SimpleConfig &cfg,
				   cfgPtr group);

  /**
   * This method is used to store information from a medium to a configuration
   * file (in order to be restorable by @ref mediumFromConfig).
   * The only mandatory variable is "typename", because its content is used to
   * determine which plugin has to provide the medium.
   * The plugin may then use whichever variables it finds necessary.
   */
  Error mediumToConfig(Pointer<Medium> m,
		       SimpleConfig &cfg,
		       cfgPtr group);

  /**
   * This method returns the enum MediumType of the named mediumtype.
   * The responsible plugin is loaded if needed.
   * If the corresponding plugin is not available an exception will
   * be thrown
   * @author Martin Preuss<martin@libchipcard.de>
   * @param mtype named type (like "DDVCard", "RDHFile" etc)
   */
  MediumType mediumType(const string &mtype);

  /**
   * Returns the folder which is used to load plugins from.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  string pluginPath() const;

  Pointer<MediumPluginList> enumerateMediumPlugins();

  /*@}*/

  /** @name Medium Plugin Management
   *
   * Methods for loading and registering medium plugins.
   */
  /*@{*/

  /**
   * Register a medium plugin. After successfull registration the new
   * medium type is available to OpenHBCI.
   * This method is called from within the PluginFile upon
   * @ref PluginFile::registerYourSelf().
   * @author Martin Preuss<martin@libchipcard.de>
   */
  Error registerMediumPlugin(Pointer<MediumPlugin> mp);

  /**
   * This method loads and registers a medium plugin.
   * @author Martin Preuss<martin@libchipcard.de>
   */
  Error loadMediumPlugin(const string &path);

  /*@}*/

  /** @name Static Factory Methods
   *
   * Factory methods for the main objects within OpenHBCI. These are
   * static members of HBCI::API.  Factory methods are necessary
   * instead of using constructors since the actual implementation
   * classes are not visible for the application (and should never
   * be). */
  /*@{*/
  /**
   *  Creates a user object.
   *
   * This will NOT be automatically added to internally stored lists.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param b The bank that this user belongs to.
   * @param m The security medium this user owns.
   * @param userid The user id that identifies this user to his bank.
   *
   * @param version The UPD version (User Parameter Data) of this
   * user (only nonzero if there has been HBCI connectivity for this
   * user before)
   *
   * @param userName The clear-text name of this user; this not
   * given by the bank, but can be chosen arbitrarily.
   *
   * @param knowsSupportedJobs True if the UPD contain all supported jobs */
  static Pointer<User> userFactory(Pointer<Bank> b,
				   Pointer<Medium> m,
				   const string &userid,
				   int version=0,
				   const string &userName="",
				   bool knowsSupportedJobs=false);

  /**
   *  Creates a customer object.
   *
   * This will NOT be automatically added to the given user.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param u The user this customer (role) belongs to
   * @param id The customer ID that the bank assigned to this customer.
   * @param role The name of this customer. You can choose this
   * name as you like, e.g. "business", "private" or whatever you
   * prefer. I.e. you can set this to any arbitrary string you consider
   * helpful.  */
  static Pointer<Customer> customerFactory(Pointer<User> u,
					   const string &id,
					   const string &role);

  /**
   *  Creates an account object.
   *
   * This will NOT be automatically added to internally stored lists.
   * @author Martin Preuss<martin@libchipcard.de>
   * @param b The bank that this account belongs to.
   * @param accountId The account number (id) that identifies this account.
   * @param accountSubId New in HBCI2.2: The suffix of the account number.
   */
  static Pointer<Account>
    accountFactory(Pointer<Bank> b,
		   const string &accountId="",
		   const string &accountSubId="");
  /*@}*/

  /** @name Counter for transaction ids */
  /*@{*/
  static unsigned nextTransactionId();
  static unsigned lastTransactionId();
  static void setLastTransactionId(unsigned int i);
  /*@}*/
};

} /* namespace HBCI */
#endif /* __cplusplus */

/* C wrappers have been moved to api_c.h */
#include "api_c.h"



#endif
