/***************************************************************************
 $RCSfile: standingorder.h,v $
 -------------------
 cvs         : $Id: standingorder.h,v 1.11 2003/04/15 22:10:23 cstim Exp $
 begin       : Mon Jun 17 2002
 copyright   : (C) 2002 by Fabian Kaiser
 email       : openhbci@derzach.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                                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef HBCI_STANDINGORDER_H
#define HBCI_STANDINGORDER_H

/** @file standingorder.h
 * 
 * @short HBCI::StandingOrder and C wrapper @ref HBCI_StandingOrder. */

#ifdef __cplusplus
#include <list>
#include <string>
#include <openhbci/pointer.h>
using namespace std;

namespace HBCI {
  class StandingOrder;
}
/* for C wrapper functions */
/** @ingroup HBCI_StandingOrderg */
typedef struct HBCI::StandingOrder HBCI_StandingOrder;
/** @ingroup HBCI_StandingOrderg */
typedef list<HBCI::Pointer<HBCI::StandingOrder> > list_HBCI_StO;
/** @ingroup HBCI_StandingOrderg */
typedef list<HBCI::Pointer<HBCI::StandingOrder> >::const_iterator 
   list_HBCI_StO_iter;
#else /* __cplusplus */
typedef struct HBCI_StandingOrder HBCI_StandingOrder;
typedef struct list_HBCI_StO list_HBCI_StO;
typedef struct list_HBCI_StO_iter list_HBCI_StO_iter;
#endif /* __cplusplus */

#include <openhbci/value.h>
#include <openhbci/date.h>
#include <openhbci/account.h>
#include <openhbci/bank.h>

#ifdef __cplusplus

namespace HBCI {

/** 
 * @short Holds all the data of a Standing Order in HBCI. 
 *
 * A Standing Order is stored at the bank and regularly invokes a
 * transaction in your account. 
 *
 * Note: Some data members have comments referencing the SWIFT MT940
 * specification, but IIRC this is not the right specification for a
 * standing order. FIXME: Add clear references about which
 * specifications set the rules for interpretation of each data
 * member.
 *
 * @author Fabian Kaiser<openhbci@derzach.de> */
class DLLIMPORT StandingOrder : AbstractTrans {
private:
    string _jobId;
    string _ourAccountId;
    string _ourSuffix;
    string _ourBankCode;
    int _ourCountryCode;
    string _otherBankCode;
    int _otherCountryCode;
    string _otherAccountId;
    string _otherSuffix;
    list<string> _otherName;
    Value _value;
    int _transactionCode;
    list<string> _description;
    Date _execDate;

    /* details */
    Date _firstExecution;
    Date _lastExecution;
    int _period;
    int _cycle;
    int _execDay;

    /* modification flags */
    bool modOurAccount;
    bool modOtherAccount;
    bool modOtherName;
    bool modValue;
    bool modTransactionCode;
    bool modDescription;
    bool modExecDate;
    bool modDetails;

public:
    /**
     * @see setPeriod()
     * @see period()
     */
    const static int EXECUTE_WEEKLY;
    /**
     * @see setPeriod()
     * @see period()
     */
    const static int EXECUTE_MONTHLY;

    /**
     *
     */
    StandingOrder(const string &s, Pointer<Account> account);

    /**
     *
     */
    StandingOrder(Pointer<Account> account);

    /**
     *
     */
    StandingOrder();

    /**
     * Checks if two standing orders are equal.
     * Some banks do not support the jobId, so you have to specify all
     * order-data. Using all this data, two jobs are compared.
     */
    bool operator==(const StandingOrder &otherOrder) const;

    /** @name Order Identification */
    /*@{*/
    /**
     * Returns a string that identifies this standing order.
     * Use this identification to name an order you want to
     * modify.<p>
     * Note: It is safe to store this id within the application. It
     * is valid until the order is getting deleted (at the bank)
     */
    const string &jobIdentification() const;

    /**
     * Set a string that identifies this standing order.
     * Use this identification to name an order you want to
     * modify.
     */
    void setJobIdentification(const string &s);
    /*@}*/

    /** @name Execution Date */
    /*@{*/
    /**
     * Return the date when this order is/was executed for the first time
     */
    const Date &firstExecutionDate() const;

    /**
     * Set the date when this order should be executed for the first time<p>
     * Note: It must be consistent with period() and execDay()
     * @see minDaysToExec(), maxDaysToExec() for valid values
     */
    void setFirstExecutionDate(const Date &ex);

    /**
     * Return the date when this order is executed the last time
     */
    const Date &lastExecutionDate() const;

    /**
     * Set the date when this order should be executed the last time
     */
    void setLastExecutionDate(const Date &ex);
    /**
     * Returns the date when this order will be executed next time
     */
    const Date &executionDate() const;

    /**
     * Only used when modifying an order.<br>
     * Set the date when the modified order should be executed for
     * the first time
     * @see minDaysToExec(), maxDaysToExec() for valid values
     */
    void setExecutionDate(const Date &ex);

    /**
     * Returns the numer of time-units that have to elaps between two
     * executions of this order.
     * @see setPeriod(int) For the time-unit
     */
    int cycle() const;

    /**
     * Set the numer of time-units that have to elaps between two
     * executions of this order.
     * @see setPeriod(int) For the time-unit
     * @see monthlyCycle(), weeklyCycle() for valid values
     */
    void setCycle(int v=1);

    /**
     * Returns whether the time-unit for cycle() is a week or a month
     */
    int period() const;

    /**
     * Set the time-unit for cycle() to week or month<p>
     * Note: It must be consistent with firstExecutionDate() and execDay()
     */
    void setPeriod(int c=EXECUTE_MONTHLY);

    /**
     * Returns the day within a week or a month (depending on period()) when
     * this order should be executed.
     * @see execDaysMonth(), execDaysWeek() for valid values
     */
    int execDay() const;

    /**
     * Set the day of week/month (depending on period()) when this order
     * should be executed.<p>
     * Note: It must be consistent with firstExecutionDate() and period()
     */
    void setExecDay(int d=1);
    /*@}*/


    /** @name Our account */
    /*@{*/
    /** country code of your institute -- MT940: not in MT940 */
    int ourCountryCode() const;
    /** country code of your institute -- MT940: not in MT940 */
    void setOurCountryCode(int i);

    /** bank code of your institute (BLZ or S.W.I.F.T. code) -- MT940: BLZ in
      :25: */
    const string &ourBankCode() const;
    /** bank code of your institute (BLZ or S.W.I.F.T. code) -- MT940: BLZ in
      :25: */
    void setOurBankCode(const string &code);

    /** Your account number; up to 23 characters. Note: possibly
     * including the currency (yes, that's what MT940 says) --
     * MT940: Kontonummer in :25: */
    const string &ourAccountId() const;
    /** Your account number; up to 23 characters. Note: possibly
     * including the currency (yes, that's what MT940 says) --
     * MT940: Kontonummer in :25: */
    void setOurAccountId(const string &id);

    /** If your account has subaccounts which are distinguished by
     * different suffixes, then this is that suffix. Otherwise it's
     * empty. -- MT940: not in MT940 */
    const string &ourSuffix() const;
    /** If your account has subaccounts which are distinguished by
     * different suffixes, then this is that suffix. Otherwise it's
     * empty. -- MT940: not in MT940 */
    void setOurSuffix(const string &id);
    /*@}*/

    /** @name Value */
    /*@{*/
    /**
     * Returns the order's value
     */
    const Value &value() const;
    /**
     * Set the order's value
     */
    void setValue(const Value &v);
    /*@}*/

    /** @name Order Description */
    /*@{*/
    /**
     * Returns a code that identifies the type of order
     * This should be 52 in most cases
     */
    int transactionCode() const;
    /**
     * Set the type of order. Should be 52 in most cases
     */
    void setTransactionCode(int c);

    /**
     * Returns a list of string describing this order
     */
    const list<string> &description() const;
    /**
     * Set a textual description
     * @see maxDescriptionLines() for valid values
     */
    void addDescription(const string &s);
    /*@}*/

    /** @name Other account */
    /*@{*/
    /**
     * Return the country code of the recipient's bank, according to ISO 3166
     * <p>
     * Note: For Germany, it is 280 in HBCI.
     */
    int otherCountryCode() const;
    /**
     * Set the country code of the recipient's bank
     * @param i The country code according to ISO 3166<p>
     * Note: For Germany, it is 280 in HBCI.
     */
    void setOtherCountryCode(int i);

    /**
     * Returns the code of the institute which hold the recipient's account
     */
    const string &otherBankCode() const;

    /**
     * Set the code of the bank which hold the recipient's account.
     * @param s The institute code
     */
    void setOtherBankCode(const string &s);

    /**
     * Returns the account number of the recipient. To this account,
     * money is transfered.
     */
    const string &otherAccountId() const;
    /**  
     * Set the account number to which the money shall be transfered
     * @param s The account number
     */
    void setOtherAccountId(const string &s);

    /**
     * Returns a suffix to the account number to which the money shall be
     * tranfered. Normaly not used.
     */
    const string &otherSuffix() const;
    /**
     * Set a suffix to the account number to which the money shall be
     * tranfered. Normaly not used.
     */
    void setOtherSuffix(const string &id);

    /**
     * Returns the names of the recipient
     */ 
    const list<string> &otherName() const;
    /** Set the name of the recipient. Two strings can be set for
     * this, so call this method not more than two times.  */
    void addOtherName(const string &s);
    /*@}*/
};

} /* namespace HBCI */

extern "C" {
#endif /* __cplusplus */

    /** @defgroup HBCI_StandingOrderg HBCI_StandingOrder */
    /*@{*/
    /** @name List of HBCI_StandingOrder */
    /*@{*/
    extern void list_HBCI_StO_delete(list_HBCI_StO *l);
    extern int list_HBCI_StO_size(const list_HBCI_StO *l);
    extern void list_HBCI_StO_iter_delete(list_HBCI_StO_iter *l);
    extern list_HBCI_StO_iter* list_HBCI_StO_begin(const list_HBCI_StO *l);
    extern list_HBCI_StO_iter* list_HBCI_StO_end(const list_HBCI_StO *l);
    extern const HBCI_StandingOrder* 
    list_HBCI_StO_iter_get(const list_HBCI_StO_iter *l);
    extern void list_HBCI_StO_iter_next(list_HBCI_StO_iter *l);
    extern int list_HBCI_StO_iter_equal(const list_HBCI_StO_iter *l1, 
					const list_HBCI_StO_iter *l2);
    /** Callback function for list_HBCI_StO_foreach. */
    typedef void *(*list_HBCI_StO_cb) (const HBCI_StandingOrder *sto, 
				       void *user_data);
    /** Traverses the list, calling the callback function 'func' on
     * each list element.  Traversal will stop when 'func' returns a
     * non-NULL value, and the routine will return with that
     * value. Otherwise the routine will return NULL. 
     * @param list The list to traverse.
     * @param func The function to be called with each list element.
     * @param user_data A pointer passed on to the function 'func'.
     * @return The non-NULL pointer returned by 'func' as soon as it
     * returns one. Otherwise (i.e. 'func' always returns NULL)
     * returns NULL.
     * @author Christian Stimming <stimming@tuhh.de> */
    extern void *list_HBCI_StO_foreach (const list_HBCI_StO *list, 
					list_HBCI_StO_cb func,
					void *user_data);
    /*@}*/


    /** Constructor */
    extern HBCI_StandingOrder * HBCI_StandingOrder_new();
    /** Destructor */
    extern void HBCI_StandingOrder_delete(HBCI_StandingOrder *t);


    /** @name Order Identification */
    /*@{*/
    /**
     * Returns a string that identifies this standing order.
     * Use this identification to name an order you want to
     * modify.<p>
     * Note: It is safe to store this id within the application. It
     * is valid until the order is getting deleted (at the bank)
     */
    extern const char *
    HBCI_StandingOrder_jobIdentification(const HBCI_StandingOrder *h);

    /**
     * Set a string that identifies this standing order.
     * Use this identification to name an order you want to
     * modify.
     */
    extern void HBCI_StandingOrder_setJobIdentification(HBCI_StandingOrder *h,
							const char *s);
    /*@}*/

    /** @name Execution Date */
    /*@{*/
    /**
     * Return the date when this order is/was executed for the first time
     */
    extern const HBCI_Date *
    HBCI_StandingOrder_firstExecutionDate(const HBCI_StandingOrder *h);

    /**
     * Set the date when this order should be executed for the first time<p>
     * Note: It must be consistent with period() and execDay()
     * @see minDaysToExec(), maxDaysToExec() for valid values
     */
    extern void 
    HBCI_StandingOrder_setFirstExecutionDate(HBCI_StandingOrder *h, 
					     const HBCI_Date *ex);

    /**
     * Return the date when this order is executed the last time
     */
    extern const HBCI_Date *
    HBCI_StandingOrder_lastExecutionDate(const HBCI_StandingOrder *h);

    /**
     * Set the date when this order should be executed the last time
     */
    extern void 
    HBCI_StandingOrder_setLastExecutionDate(HBCI_StandingOrder *h,
					    const HBCI_Date *ex);
    /**
     * Returns the date when this order will be executed next time
     */
    extern const HBCI_Date *
    HBCI_StandingOrder_executionDate(const HBCI_StandingOrder *h);

    /**
     * Only used when modifying an order.<br>
     * Set the date when the modified order should be executed for
     * the first time
     * @see minDaysToExec(), maxDaysToExec() for valid values
     */
    extern void 
    HBCI_StandingOrder_setExecutionDate(HBCI_StandingOrder *h, 
					const HBCI_Date *ex);

    /**
     * Returns the numer of time-units that have to elaps between two
     * executions of this order.
     * @see setPeriod(int) For the time-unit
     */
    extern int HBCI_StandingOrder_cycle(const HBCI_StandingOrder *h);

    /**
     * Set the numer of time-units that have to elaps between two
     * executions of this order.
     * @see setPeriod(int) For the time-unit
     * @see monthlyCycle(), weeklyCycle() for valid values
     */
    extern void HBCI_StandingOrder_setCycle(HBCI_StandingOrder *h,
					    int v);

    /**
     * Returns whether the time-unit for cycle() is a week or a month
     */
    extern int HBCI_StandingOrder_period(const HBCI_StandingOrder *h);

    /**
     * Set the time-unit for cycle() to week or month<p>
     * Note: It must be consistent with firstExecutionDate() and execDay()
     */
    extern void HBCI_StandingOrder_setPeriod(HBCI_StandingOrder *h,
					     int c);

    /**
     * Returns the day within a week or a month (depending on period()) when
     * this order should be executed.
     * @see execDaysMonth(), execDaysWeek() for valid values
     */
    extern int HBCI_StandingOrder_execDay(const HBCI_StandingOrder *h);

    /**
     * Set the day of week/month (depending on period()) when this order
     * should be executed.<p>
     * Note: It must be consistent with firstExecutionDate() and period()
     */
    extern void HBCI_StandingOrder_setExecDay(HBCI_StandingOrder *h, 
					      int d);
    /*@}*/

    /** @name Our account */
    /*@{*/
    /** country code of your institute -- not in MT940. */
    extern int HBCI_StandingOrder_ourCountryCode(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_setOurCountryCode(HBCI_StandingOrder *t, int i);

    /** bank code of your institute (BLZ or S.W.I.F.T. code) -- BLZ in
      :25:
      *
      * The const char* pointer of this and all the following
      * functions points to the c_str() result of the underlying
      * std::string object. It is therefore valid as long as the
      * StandingOrder object wasn't changed, and it should NOT be
      * free'd by the caller.  */
    extern const char * 
    HBCI_StandingOrder_ourBankCode(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_setOurBankCode(HBCI_StandingOrder *t, const char *code);

    /** Your account number; up to 23 characters. Note: possibly
     * including the currency (yes, that's what MT940 says) --
     * Kontonummer in :25: */
    extern const char * 
    HBCI_StandingOrder_ourAccountId(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_setOurAccountId(HBCI_StandingOrder *t, const char *id);

    /** If your account has subaccounts which are distinguished by
     * different suffixes, then this is that suffix. Otherwise it's
     * empty. -- not in MT940 */
    extern const char * 
    HBCI_StandingOrder_ourSuffix(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_setOurSuffix(HBCI_StandingOrder *t, const char *id);
    /*@}*/
    
    /** @name Value */
    /*@{*/
    /** The value of this transaction in the account's currency. --
     * Betrag in :61: */
    extern const HBCI_Value* 
    HBCI_StandingOrder_value(const HBCI_StandingOrder *t);

    /** 
     * @param t The object to perform this action on.
     * @param v the value. a deep copy of its data will be stored, so the
     * pointer lifecycle doesn't affect this transaction. */
    extern void 
    HBCI_StandingOrder_setValue(HBCI_StandingOrder *t, const HBCI_Value *v);
    /*@}*/

    /** @name StandingOrder Description */
    /*@{*/
    /**
     * Returns a code that identifies the type of order
     * This should be 52 in most cases
     */
    extern int HBCI_StandingOrder_transactionCode(const HBCI_StandingOrder *t);
    /**
     * Set the type of order. Should be 52 in most cases
     */
    extern void 
    HBCI_StandingOrder_setTransactionCode(HBCI_StandingOrder *t, int c);

    /** Description of what this transaction is for, and how the Bank
     * describes this transaction.  -- Verwendungszweck; fields 20-29
     * and 60-63 in field :86:  */
    extern const list_string* 
    HBCI_StandingOrder_description(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_addDescription(HBCI_StandingOrder *t, const char *s);
    /*@}*/

    /** @name Other account */
    /*@{*/
    /** Country code (BLZ) of the other party's institute -- not in
     * MT940/field :86: */
    extern int 
    HBCI_StandingOrder_otherCountryCode(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_setOtherCountryCode(HBCI_StandingOrder *t, int i);

    /** Institute code (BLZ);
     * field 30 in field :86: */
    extern const char * 
    HBCI_StandingOrder_otherBankCode(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_setOtherBankCode(HBCI_StandingOrder *t, const char *s);

    /** Account number of the other party -- Kontonummer; field 31 in
     * field :86: */
    extern const char * 
    HBCI_StandingOrder_otherAccountId(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_setOtherAccountId(HBCI_StandingOrder *t, const char *s);

    /** If the account of the other party has subaccounts which are
     * distinguished by different suffixes, then this is that suffix
     * of the other party. Otherwise it's empty. -- *not* in MT940 /
     * field :86: */
    extern const char * 
    HBCI_StandingOrder_otherSuffix(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_setOtherSuffix(HBCI_StandingOrder *t, const char *id);

    /** Name of the other party -- fields 32 and 33 in field :86: */
    extern const list_string* 
    HBCI_StandingOrder_otherName(const HBCI_StandingOrder *t);
    extern void 
    HBCI_StandingOrder_addOtherName(HBCI_StandingOrder *t, const char *s);
    /*@}*/

    /*@}*/

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif
