/*
 * gnc-ab-utils.h --
 *
 * 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.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, contact:
 *
 * Free Software Foundation           Voice:  +1-617-542-5942
 * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
 * Boston, MA  02110-1301,  USA       gnu@gnu.org
 */

/**
 * @addtogroup Import_Export
 * @{
 * @addtogroup AqBanking
 * @{
 * @file gnc-ab-utils.h
 * @brief AqBanking utility functions
 * @author Copyright (C) 2002 Christian Stimming <stimming@tuhh.de>
 * @author Copyright (C) 2008 Andreas Koehler <andi5.py@gmx.net>
 */

#ifndef GNC_AB_UTILS_H
#define GNC_AB_UTILS_H

#include <glib.h>
#include <gtk/gtk.h>
#include <aqbanking/banking.h>
#include <gwenhywfar/version.h>

#include "Account.h"

G_BEGIN_DECLS

/** A define that combines the aqbanking version number into one single
 * integer number. Assumption: Both MINOR and PATCHLEVEL numbers are
 * in the interval [0..99]. */
#define AQBANKING_VERSION_INT (10000 * AQBANKING_VERSION_MAJOR + 100 * AQBANKING_VERSION_MINOR + AQBANKING_VERSION_PATCHLEVEL)

/** A define that combines the gwenhywfar version number into one single
 * integer number. Assumption: Both MINOR and PATCHLEVEL numbers are
 * in the interval [0..99]. */
#define GWENHYWFAR_VERSION_INT (10000 * GWENHYWFAR_VERSION_MAJOR + 100 * GWENHYWFAR_VERSION_MINOR + GWENHYWFAR_VERSION_PATCHLEVEL)

#if AQBANKING_VERSION_INT >= 59900
# define AQBANKING6 1
# define GNC_AB_ACCOUNT_SPEC AB_ACCOUNT_SPEC
# define GNC_AB_ACCOUNT_SPEC_LIST AB_ACCOUNT_SPEC_LIST
# define GNC_AB_JOB AB_TRANSACTION
# define GNC_AB_JOB_LIST2 AB_TRANSACTION_LIST2
# define GNC_AB_JOB_LIST2_ITERATOR AB_TRANSACTION_LIST2_ITERATOR
# define GNC_AB_JOB_STATUS AB_TRANSACTION_STATUS
# define GNC_GWEN_DATE GWEN_DATE
#else
# define GNC_AB_ACCOUNT_SPEC AB_ACCOUNT
# define GNC_AB_ACCOUNT_SPEC_LIST AB_ACCOUNT_LIST2
# define GNC_AB_JOB AB_JOB
# define GNC_AB_JOB_LIST2 AB_JOB_LIST2
# define GNC_AB_JOB_LIST2_ITERATOR AB_JOB_LIST2_ITERATOR
# define GNC_AB_JOB_STATUS AB_JOB_STATUS
# define GNC_GWEN_DATE GWEN_TIME
#endif
#if GWENHYWFAR_VERSION_INT >= 49900
# define GWENHYWFAR5
#endif

#define GNC_PREFS_GROUP_AQBANKING       "dialogs.import.hbci"
#define GNC_PREF_FORMAT_SWIFT940        "format-swift-mt940"
#define GNC_PREF_FORMAT_SWIFT942        "format-swift-mt942"
#define GNC_PREF_FORMAT_DTAUS           "format-dtaus"
#define GNC_PREF_USE_TRANSACTION_TXT    "use-ns-transaction-text"
#define GNC_PREF_VERBOSE_DEBUG          "verbose-debug"

typedef struct _GncABImExContextImport GncABImExContextImport;

#define AWAIT_BALANCES      1 << 1
#define FOUND_BALANCES      1 << 2
#define IGNORE_BALANCES     1 << 3
#define AWAIT_TRANSACTIONS  1 << 4
#define FOUND_TRANSACTIONS  1 << 5
#define IGNORE_TRANSACTIONS 1 << 6

/**
 * Initialize the gwenhywfar library by calling GWEN_Init() and setting up
 * gwenhywfar logging.
 */
void gnc_GWEN_Init(void);

/**
 * Finalize the gwenhywfar library.
 */
void gnc_GWEN_Fini(void);

/**
 * If there is a cached AB_BANKING object, return it initialized.  Otherwise,
 * create a new AB_BANKING, let it load its environment from its default
 * configuration and cache it.
 *
 * @return The AB_BANKING object
 */
AB_BANKING *gnc_AB_BANKING_new(void);

/**
 * Delete the AB_BANKING @a api.  If this is also the one that was cached by
 * gnc_AB_BANKING_new(), then all references are deleted, too.
 *
 * @param api AB_BANKING or NULL for the cached AB_BANKING object
 */
void gnc_AB_BANKING_delete(AB_BANKING *api);

/**
 * Finish the AB_BANKING @a api.  If this is also the one that was cached by
 * gnc_AB_BANKING_new(), then finish only if the decremented reference count
 * reaches zero.  After this call, you may only call gnc_AB_BANKING_new() to get
 * the api again in a properly initialized state.
 *
 * @param api AB_BANKING object
 * @return Zero on success
 */
gint gnc_AB_BANKING_fini(AB_BANKING *api);

/**
 * Get the corresponding AqBanking account to the GnuCash account @a gnc_acc.
 * Of course this only works after the GnuCash account has been set up for
 * AqBanking use, i.e. the account's hbci data have been set up and populated.
 *
 * @param api The AB_BANKING to get the GNC_AB_ACCOUNT_SPEC from
 * @param gnc_acc The GnuCash account to query for GNC_AB_ACCOUNT_SPEC reference data
 * @return The GNC_AB_ACCOUNT_SPEC found or NULL otherwise
 */
GNC_AB_ACCOUNT_SPEC *gnc_ab_get_ab_account(const AB_BANKING *api, Account *gnc_acc);

/**
 * Print the value of @a value with two decimal places and @a value's
 * currency appended, or 0.0 otherwise
 *
 * @param value AB_VALUE or NULL
 * @return A newly allocated string
 */
gchar *gnc_AB_VALUE_to_readable_string(const AB_VALUE *value);

/**
 * Return the job as string.
 *
 * @param value GNC_AB_JOB or NULL
 * @return A newly allocated string
 */
gchar *gnc_AB_JOB_to_readable_string(const GNC_AB_JOB *job);

/**
 * Return the job_id as string.
 *
 * @param job_id
 * @return A newly allocated string
 */
gchar *gnc_AB_JOB_ID_to_string(gulong job_id);

/**
 * Retrieve the merged "remote name" fields from a transaction.  The returned
 * string must be g_free'd by the caller.  If there was no "remote name" field,
 * NULL (!) is returned.
 *
 * @param ab_trans AqBanking transaction
 * @return A newly allocated string or NULL otherwise
 */
gchar *gnc_ab_get_remote_name(const AB_TRANSACTION *ab_trans);

/**
 * Retrieve the merged purpose fields from a transaction.  The returned string
 * must be g_free'd by the caller.  If there was no purpose, an empty (but
 * allocated) string is returned.
 *
 * @param ab_trans AqBanking transaction
 * @return A newly allocated string, may be ""
 */
gchar *gnc_ab_get_purpose(const AB_TRANSACTION *ab_trans, gboolean is_ofx);

/**
 * Create the appropriate description field for a GnuCash Transaction by the
 * information given in the AB_TRANSACTION @a ab_trans.  The returned string
 * must be g_free'd by the caller.
 *
 * @param ab_trans AqBanking transaction
 * @return A newly allocated string, may be ""
 */
gchar *gnc_ab_description_to_gnc(const AB_TRANSACTION *ab_trans, gboolean is_ofx);

/**
 * Create the appropriate memo field for a GnuCash Split by the information
 * given in the AB_TRANSACTION @a ab_trans.  The returned string must be
 * g_free'd by the caller.
 *
 * @param ab_trans AqBanking transaction
 * @return A newly allocated string, may be ""
 */
gchar *gnc_ab_memo_to_gnc(const AB_TRANSACTION *ab_trans);

/**
 * Create an unbalanced and dirty GnuCash transaction with a split to @a gnc_acc
 * from the information available in the AqBanking transaction @a ab_trans.
 *
 * @param ab_trans AqBanking transaction
 * @param gnc_acc Account of to use for the split
 * @return A dirty GnuCash transaction or NULL otherwise
 */
Transaction *gnc_ab_trans_to_gnc(const AB_TRANSACTION *ab_trans, Account *gnc_acc);

/**
 * Import balances and transactions found in a AB_IMEXPORTER_CONTEXT into
 * GnuCash.  By using @a awaiting the caller can specify what the user will
 * expect to receive.  By using @a execute_txns, transactions in @a context can
 * be used to generate corresponding AqBanking jobs, e.g. after a file import.
 *
 * @param context AB_IMEXPORTER_CONTEXT to import
 *
 * @param awaiting Information the caller expects to receive or wants to ignore,
 * bitmask of AWAIT_* or IGNORE_* values
 *
 * @param execute_txns If @a awaiting contains AWAIT_TRANSACTIONS, whether to
 * create an aqbanking job for each of the transactions found
 *
 * @param api If @a execute_txns is TRUE, the AB_BANKING to get
 * GNC_AB_ACCOUNT_SPECs from
 *
 * @param parent Widget to set new dialogs transient for, may be NULL
 *
 * @return A new GncABImExContextImport object which must be freed with
 * g_free(), or NULL otherwise.  If execute_txns is TRUE, additionally
 * gnc_ab_ieci_get_job_list() must be called and the result freed with
 * AB_Job_List2_FreeAll()
 */
GncABImExContextImport *gnc_ab_import_context(
    AB_IMEXPORTER_CONTEXT *context, guint awaiting, gboolean execute_txns,
    AB_BANKING *api, GtkWidget *parent);

/**
 * Extract awaiting from @a data.
 *
 * @param ieci The return value of gnc_ab_import_context()
 * @return The initial awaiting bitmask plus IGNORE_* for unexpected and then
 * ignored items, and FOUND_* for non-empty items
 */
guint gnc_ab_ieci_get_found(GncABImExContextImport *ieci);

/**
 * Extract the job list from @a data.
 *
 * @param ieci The return value of gnc_ab_import_context()
 * @return The list of jobs, freeable with AB_Job_List2_FreeAll()
 */
GNC_AB_JOB_LIST2 *gnc_ab_ieci_get_job_list(GncABImExContextImport *ieci);

/**
 * Run the generic transaction matcher dialog.
 *
 * @param ieci The return value of gnc_ab_import_context()
 * @return The return value of gnc_gen_trans_list_run().
 */
gboolean gnc_ab_ieci_run_matcher(GncABImExContextImport *ieci);


/**
 * get the GWEN_DB_NODE from AqBanking configuration files
 *
 * @return a GWEN_DB containing all permanently accepted SSL certificates (hashed).
 */
GWEN_DB_NODE *gnc_ab_get_permanent_certs(void);

/**
 * Creates an online ID from bank code and account number.
 *
 * The returned string must be g_free'd by the caller.
 *
 * @param bankcode       Bank code
 * @param accountnumber  Account number
 * @return an online ID
 */
gchar* gnc_ab_create_online_id(const gchar *bankcode, const gchar *accountnumber);

G_END_DECLS

/** @} */
/** @} */

#endif /* GNC_AB_UTILS_H */
