/* outboxjob.h
 
 ***************************************************************************
 *                                                                         *
 *   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                                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef OUTBOXJOB_H
#define OUTBOXJOB_H

/** @file outboxjob.h
 *
 * @short Abstract base class HBCI::OutboxJob and its C wrapper @ref
 * HBCI_OutboxJob functions. */

#ifdef __cplusplus
#include <string>
#include <list>
#endif /* __cplusplus */

#include <openhbci/dllimport.h>
#include <openhbci/pointer.h>
#include <openhbci/customer.h>
#include <openhbci/user.h>
#include <openhbci/bank.h>
#include <openhbci/account.h>
#include <openhbci/statusreport.h>
#include <openhbci/listwrappers.h>
#include <openhbci/progressmonitor.h>


/** Status of an OutboxJob. */
typedef enum OutboxJob_Status {
    /** No status, i.e. for freshly created jobs */
    HBCI_JOB_STATUS_NONE = 0,
    /** Job is to be executed */
    HBCI_JOB_STATUS_TODO,
    /** Job was executed */
    HBCI_JOB_STATUS_DONE
} OutboxJob_Status;
/** Result of an OutboxJob. */
typedef enum OutboxJob_Result {
    /** Job was not executed */
    HBCI_JOB_RESULT_NONE = 0,
    /** Job was successfully performed */
    HBCI_JOB_RESULT_SUCCESS,
    /** Job was executed and failed */
    HBCI_JOB_RESULT_FAILED
} OutboxJob_Result;

#ifdef __cplusplus
#include <openhbci/messagequeue.h>
/* Forward declaration */
namespace HBCI {
  class OutboxJob;
};
/** @ingroup HBCI_OutboxJobg
 * @short C accessible type of HBCI::OutboxJob */
typedef HBCI::OutboxJob HBCI_OutboxJob;
#include <openhbci/api.h>

/* Used to tell the the commit()-method that not the response for a
 * single message should be committed, but the response for the whole
 * job.  This is because a job may consist of more than one message,
 * and it might be necessary to commit recieved changes before the
 * rest of the job is sent. */
#define HBCI_COMMIT_WHOLE_JOB  -1

namespace HBCI {

/**
 * @short Abstract base class for all jobs to be used with HBCIAPI
 * 
 * This is an abstract base class for the jobs of the OpenHBCI-Wrapper
 * API. Every job to be used in the @ref Outbox is derived from this. 
 *
 * If you plan to add a new job, just code your own derivation. But
 * note that in order to provide the @ref ProgressMonitor with the
 * information that *this* job is being started, you would need to add
 * an appropriate enum value to JobProgressType in progressmonitor.h
 * . Apart from that, you don't need to take care of anything else
 * except to derive from OutboxJob.
 *
 * @author Martin Preuss<martin@libchipcard.de>
 */
class DLLIMPORT OutboxJob {
    friend class API;
    friend class Outbox;
    friend class customerQueue;
  private:
    OutboxJob_Status _status;
    int _id;
    list<Pointer<Customer> > _signers;
    MessageReference _msgReference;
  protected:
    Pointer<Customer> _cust;
    Pointer<Bank> _bank;
    OutboxJob_Result _result;

  public:
    /**
     *  Default Constructor.
     */
    OutboxJob(Pointer<Customer> c);
    /**
     *  Default Destructor.
     */
    virtual ~OutboxJob();

    /** @name Manage Customer 
     *
     * Methods to manage the Customer's involved in this OutboxJob. */
    /*@{*/
    /**
     *  Returns a pointer to the Customer owning this job.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    Pointer<Customer> customer() const { return _cust;};

    /**
     *  Adds a signer.
     *
     * Here you can add a signer. In most cases you don't need this
     * method, since the first signer is already given in the
     * constructor. But you need this method if this job needs
     * multiple signers for your bank.
     *
     * @author Martin Preuss<martin@libchipcard.de> */
    void addSigner(Pointer<Customer> c);
    /*@}*/

    /** @name Status Information 
     *
     * Methods to retrieve information about this OutboxJob's status
     * and result. */
    /*@{*/
    /**
     *  Returns the status of this job.
     *
     * Returns the status of this job. It can be one of the following:
     * <ul>
     * <li>@ref HBCI_JOB_STATUS_NONE (no status, e.g. for freshly created jobs)
     * </li>
     * <li>@ref HBCI_JOB_STATUS_TODO (job is to be executed)</li>
     * <li>@ref HBCI_JOB_STATUS_DONE (job was executed) </li>
     * </ul>
     * @author Martin Preuss<martin@libchipcard.de>
     */
    OutboxJob_Status status() const { return _status;};

    /**
     *  Return the result code of the job. 
     *
     * Return the result code of the job. This of course is only usefull
     * AFTER the job has been performed ;-)
     * The result can be one of these:
     * <ul>
     * <li>@ref HBCI_JOB_RESULT_NONE (job was not executed)</li>
     * <li>@ref HBCI_JOB_RESULT_SUCCESS (job was successfully performed) </li>
     * <li>@ref HBCI_JOB_RESULT_FAILED (job was executed and failed) </li>
     * </ul>
     * @author Martin Preuss<martin@libchipcard.de>
     */
    OutboxJob_Result result() const { return _result;};

    /**
     *  Return the id of this job. 
     *
     * Return the id of this job. Each enqueued job has a unique
     * id. This can be used from an application to identify specific
     * jobs after they have been added to the outbox queue.
     *
     * @author Martin Preuss<martin@libchipcard.de> */
    int id() const { return _id;};

    /**
     *  Return a short description of what the job is supposed to do.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    virtual string description() const = 0;

    /**  Returns a list of result codes of this job. 
     *
     * This can be used to get more detailed information if the result
     * of this job was HBCI_JOB_RESULT_FAILED. In that case, you can
     * traverse this list, checking for resultcodes >= 9000. Each of
     * those can be the source of the job failure, so you can react
     * accordingly. %HBCI spec suggests that the most important of
     * them can be found at the front() already, but that depends on
     * your bank. 
     *
     * Note: A resultcode >= 9000 does not automatically mean an
     * error, see MessageQueue::getResult().
     *
     * @see MessageQueue::getResult(), Job::errorcodeIsLibraryBug() */
    virtual list<int> resultCodes() const = 0;

    /**
     * Returns the message reference of this job. This is later used
     * for status reports, StatusReport::messageReference(). FIXME:
     * This is not set in the beginning, but it is only set after that
     * job has been executed, or did I get something wrong?
     */
    const MessageReference &messageReference() const { return _msgReference;};

    /**
     * Returns the number of the segment to be used for status
     * reports, i.e. the number that shows up in
     * StatusReport::segment() (FIXME: is this correct?)
     *
     * FIXME: This is not set in the beginning, but it is only set
     * after that job has been executed, or did I get something wrong?
     *
     * By default this is "-1", meaning no segment number (NOTE: In
     * this case the corresponding field in HKPRO will be left
     * out). This can be overriden by a derived OutboxJob.
     */
    virtual int segmentForStatusReport() const;

    /** 
     *  Return the JobProgressType of this job.
     * @author Christian Stimming <stimming@tuhh.de>
     */
    virtual JobProgressType type() const = 0;
    
    /*@}*/

  protected:

    /**
     *  Helper function to copy the stored signers to the given
     * message queue.
     */
    void addSignersToQueue(Pointer<MessageQueue> q) const;

    /**   Returns the number of messages this job needs.  
     *
     * This method is used to calculate the return value of
     * OutboxJob::stillMessagesToSend, and it is used by
     * API::_handleJobQueue to determine the number of actions that
     * are going to be started.
     *
     * If this is a dialog job, then it consists of at least two messages:
     * <ul>
     * <li>dialog init message</li>
     * <li>dialog closing message</li>
     * </ul>
     * Since not all jobs may be mixed in ONE message this method returns
     * the number of messages it needs.
     *
     * @author Martin Preuss<martin@libchipcard.de> */
    virtual int messages() const { return 1;};

    /** 
     * Helper function to extract a list of result codes from a Job. */
    static list<int> resultCodesFromJob(const Job& job);

    /** @name Manipulation from HBCIAPI
     *
     * Methods to be called only from HBCIAPI or Outbox. These methods
     * manipulate this OutboxJob.  */
    /*@{*/
    /**
     *  Set id.
     *
     * This is called by the Outbox to assign a unique id to all
     * enqueued jobs.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    void setId(int i) { _id=i;};

    /**
     * Sets the reference of this message, used for status reports later.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    void setMessageReference(const MessageReference &ref);

    /**  Set status of this job. */
    void setStatus(OutboxJob_Status s) { _status=s;};

    /**
     *  Let the job create the "real" jobs and add them to the message
     * queue given.
     *
     * @author Martin Preuss<martin@libchipcard.de>
     * @return true on success, false otherwise
     * @param mbox pointer to the messagebox to add the jobs to
     * @param n the number of the message to create. In most cases this is
     * zero.
     */
    virtual bool createHBCIJobs(Pointer<MessageQueue> mbox, int n=0)=0;

    /**
     *  Let the job check the result and set the flags. 
     *
     * Let the job check the result. This means checking the results
     * of all Jobs involved (which otherwise is not done
     * automatically). This method sets its status and result
     * accordingly -- otherwise the status and result flags might not
     * be up-to-date.
     *
     * @author Martin Preuss<martin@libchipcard.de>
     * @return true if job was successfull, false otherwise */
    virtual bool evaluate()=0;

    /**
     *  Call this method to commit changes to the system.
     *
     * Since Jobs do not change the system you may call this method to
     * commit the changes. A job for getting the balance for example may
     * decide to store the retrieved balance in the corresponding account.
     * @param msgNumber Number of the message for which the response should
     * be committed. As a job may consist of more than one message, it might
     * be necessary to commit recieved changes before the rest of the job
     * is sent. This method is called for each message and finally for the 
     * whole job (if called for the whol job, msgNumber is set to 
     * HBCI_COMMIT_WHOLE_JOB)
     * @author Martin Preuss<martin@libchipcard.de>
     * @return true on success, false otherwise
     */
    virtual bool commit(int msgNumber=HBCI_COMMIT_WHOLE_JOB)=0;
    /*@}*/

    /** @name Information for HBCIAPI
     *
     * Methods that return information only meaningful to the Outbox
     * or HBCIAPI. */
    /*@{*/
    /**
     *  Return true if this OutboxJob is a dialog job.
     *
     * A dialog job is one that handles the opening and closing of a dialog
     * itself. Such are OutboxJobGetKeys, OutboxJobSendKeys etc.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    virtual bool isDialogJob() const { return false;};

    /**
     *  Returns true if there are still messages to be sent. 
     *
     * Checks if there are still messages to be sent. This is needed because
     * some jobs don't know the number of messages they consist of, until
     * they are executed.
     * @param nextMsg The number (starting with 0) of the message that
     * would be sent next
     * @return true If there are unsent messages left
     * @author Fabian Kaiser<openhbci@derzach.de>
     */
    virtual bool stillMessagesToSend(int nextMsg) const
	{ return nextMsg < messages(); };
    /*@}*/
};

} /* namespace HBCI */

extern "C" {
#else /* __cplusplus */
    typedef struct HBCI_OutboxJob HBCI_OutboxJob;
#endif /* __cplusplus */
    /** @defgroup HBCI_OutboxJobg HBCI_OutboxJob and derivations */
    /*@{*/
    /** @name HBCI_OutboxJob */
    /*@{*/
    /** Destructor */
    extern void HBCI_OutboxJob_delete(HBCI_OutboxJob *j);

    /**
     *  Adds a signer.
     *
     * Here you can add a signer. In most cases you don't need this
     * method, since the first signer is already given in the
     * constructor. But you need this method if this job needs
     * multiple signers for your bank.
     */
    extern void HBCI_OutboxJob_addSigner(HBCI_OutboxJob *j, 
					 const HBCI_Customer *c);
    /**
     *  Returns the status of this job.
     */
    extern OutboxJob_Status HBCI_OutboxJob_status(const HBCI_OutboxJob *j);

    /** Returns the result of this job. */
    extern OutboxJob_Result HBCI_OutboxJob_result(const HBCI_OutboxJob *j);

    /**
     *  Return the id of this job. 
     *
     * Return the id of this job. Each enqueued job has a unique
     * id. This can be used from an application to identify specific
     * jobs after they have been added to the outbox queue.
     */
    extern int HBCI_OutboxJob_id(const HBCI_OutboxJob *j);

    /**  Returns a list of result codes of this job. 
     *
     * This can be used to get more detailed information if the result
     * of this job was HBCI_JOB_RESULT_FAILED. In that case, you can
     * traverse this list, checking for resultcodes >= 9000. Each of
     * those can be the source of the job failure, so you can react
     * accordingly. %HBCI spec suggests that the most important of
     * them can be found at the front() already, but that depends on
     * your bank. 
     *
     * Note: A resultcode >= 9000 does not automatically mean an
     * error, see MessageQueue::getResult().
     *
     * @see MessageQueue::getResult(), Job::errorcodeIsLibraryBug() */
    extern list_int *HBCI_OutboxJob_resultCodes(const HBCI_OutboxJob *j);

    /**
     * Returns the message reference of this job. This is later used for
     * status reports.
     */
    extern const HBCI_MessageReference *
    HBCI_OutboxJob_messageReference(const HBCI_OutboxJob *j);

    /**
     * Returns the number of the segment to be used for status reports.
     * Returns "-1" as default, meaning no segment number (NOTE: In this case
     * the corresponding field in HKPRO will be left out)
     */
    extern int HBCI_OutboxJob_segmentForStatusReport(const HBCI_OutboxJob *j);

    /** 
     *  Return the JobProgressType of this job.
     * @author Christian Stimming <stimming@tuhh.de>
     */
    extern JobProgressType HBCI_OutboxJob_type(const HBCI_OutboxJob *j);
    
    /*@}*/
    /*@}*/

#ifdef __cplusplus
}
#endif /* __cplusplus */


#endif


