/* ************************************************************************** */
/*                                                                            */
/*     copyright (c)    2000-2008 Cédric Auger (cedric@grisbi.org)            */
/*          2004-2008 Benjamin Drieu (bdrieu@april.org)                       */
/*                      2008-2020 Pierre Biava (grisbi@pierre.biava.name)     */
/*          https://www.grisbi.org/                                           */
/*                                                                            */
/*  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, write to the Free Software               */
/*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
/*                                                                            */
/* ************************************************************************** */

/**
 * \file data_partial_balance.c
 */

#include "config.h"

#include "include.h"
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>

/*START_INCLUDE*/
#include "gsb_data_partial_balance.h"
#include "dialog.h"
#include "grisbi_app.h"
#include "gsb_currency.h"
#include "gsb_data_account.h"
#include "gsb_data_currency.h"
#include "gsb_data_currency_link.h"
#include "gsb_data_transaction.h"
#include "navigation.h"
#include "gsb_real.h"
#include "gsb_rgba.h"
#include "utils_real.h"
#include "utils_str.h"
#include "utils.h"
#include "structures.h"
#include "utils_prefs.h"
#include "utils_widgets.h"
#include "erreur.h"
/*END_INCLUDE*/

/** \struct
 * contenant les éléments d'un solde partiel
 * */
typedef struct
{
    gint partial_balance_number;
    gchar *balance_name;
    gchar *liste_cptes;
    KindAccount kind;
    gint currency;
    gboolean colorise;
} struct_partial_balance;


/*START_STATIC*/
static void _gsb_data_partial_balance_free ( struct_partial_balance *partial_balance);
static gpointer gsb_data_partial_balance_get_structure ( gint partial_balance_number );
static gboolean gsb_data_partial_balance_init_from_liste_cptes ( gint partial_balance_number,
                        GtkWidget *parent );
static gboolean gsb_data_partial_balance_move ( gint orig_partial_number, gint dest_pos );
static GtkWidget *gsb_partial_balance_create_dialog ( gint action, gint spin_value );
static GtkWidget *gsb_partial_balance_create_list_accounts ( GtkWidget *entry );
static gint gsb_partial_balance_new ( const gchar *name );
static void gsb_partial_balance_renumerote ( void );
static gint gsb_partial_balance_request_currency ( GtkWidget *parent );
static gboolean gsb_partial_balance_select_account ( GtkTreeSelection *selection,
                        GtkTreeModel *model,
                        GtkTreePath *path,
                        gboolean path_currently_selected,
                        GObject *entry );
static void gsb_partial_balance_selectionne_cptes ( GtkWidget *tree_view,
                        const gchar *liste_cptes );
/*END_STATIC*/

/*START_EXTERN*/
/*END_EXTERN*/

/* devise de base des soldes partiels de comptes ayant des devises différentes */
gint no_devise_solde_partiels;

/** contains the g_slist of struct_partial_balance */
static GSList *partial_balance_list = NULL;

/** a pointer to the last partial_balance used (to increase the speed) */
static struct_partial_balance *partial_balance_buffer;

static GtkListStore *model_accueil;

/*********************************************************************************************/
/*              Fonctions générales                                                          */
/*********************************************************************************************/
/**
 * create a new partial_balance, give him a number, append it to the list
 * and return the number
 *
 * \param name the name of the partial_balance (can be freed after, it's a copy) or NULL
 *
 * \return the number of the new partial_balance
 * */
gint gsb_partial_balance_new ( const gchar *name )
{
    struct_partial_balance *partial_balance;

    partial_balance = g_malloc0 ( sizeof ( struct_partial_balance ) );
    if ( ! partial_balance )
    {
        dialogue_error_memory ( );
        return 0;
    }
    partial_balance -> partial_balance_number = g_slist_length ( partial_balance_list ) + 1;

    if ( name )
        partial_balance -> balance_name = my_strdup ( name );
    else
        partial_balance -> balance_name = NULL;

    partial_balance_list = g_slist_append ( partial_balance_list, partial_balance );

    partial_balance_buffer = partial_balance;

    return partial_balance -> partial_balance_number;
}


/**
 * create a new partial balance and insert it at position "pos"
 * and return the number
 *
 * \param name the name of the partial_balance (can be freed after, it's a copy) or NULL
 * \param pos
 *
 * \return the number of the new partial_balance
 * */
gint gsb_partial_balance_new_at_position ( const gchar *name, gint pos )
{
    struct_partial_balance *partial_balance;

    partial_balance = g_malloc0 ( sizeof ( struct_partial_balance ) );
    if ( ! partial_balance )
    {
        dialogue_error_memory ( );
        return 0;
    }

    if ( name )
        partial_balance -> balance_name = my_strdup ( name );
    else
        partial_balance -> balance_name = NULL;

    partial_balance_list = g_slist_insert ( partial_balance_list, partial_balance, pos - 1 );
    gsb_partial_balance_renumerote ( );

    partial_balance_buffer = partial_balance;

    return partial_balance -> partial_balance_number;
}


/**
 *
 * \param
 * \param
 *
 * */
GtkListStore *gsb_partial_balance_create_model ( void )
{

    model_accueil = gtk_list_store_new (7, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
										G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN, GDK_TYPE_RGBA);

    return model_accueil;
}

/**
 *
 * \param
 * \param
 *
 * */
void gsb_partial_balance_fill_model ( GtkListStore *list_store )
{
    GSList *list_tmp;
    GtkTreeIter iter;

    list_tmp = partial_balance_list;
    gtk_list_store_clear ( GTK_LIST_STORE (list_store) );

    while ( list_tmp )
    {
        struct_partial_balance *partial_balance;
        gchar *kind_str;
        gchar *currency_str;

        partial_balance = list_tmp -> data;

        switch ( partial_balance -> kind )
        {
        case GSB_TYPE_BALANCE:
            kind_str = g_strdup ( _("Additional balance") );
            break;

        case GSB_TYPE_CASH:
            kind_str = g_strdup ( _("Cash account") );
            break;

        case GSB_TYPE_LIABILITIES:
            kind_str = g_strdup ( _("Liabilities account") );
            break;

        case GSB_TYPE_ASSET:
            kind_str = g_strdup ( _("Assets account") );
            break;

		case GSB_TYPE_BANK:
        default:
            kind_str = g_strdup ( _("Bank account") );
        }
        currency_str = gsb_data_currency_get_name ( partial_balance -> currency );

        gtk_list_store_append (GTK_LIST_STORE (list_store), &iter);
        gtk_list_store_set (GTK_LIST_STORE (list_store), &iter,
                    0, partial_balance -> balance_name,
                    1, partial_balance -> liste_cptes,
                    2, kind_str,
                    3, currency_str,
                    4, partial_balance -> partial_balance_number,
                    5, partial_balance -> colorise,
                    -1);
		g_free (kind_str);

        list_tmp = list_tmp -> next;
    }
}


/**
 * add a partial_balance
 *
 * */
void gsb_partial_balance_add ( GtkWidget *button, GtkWidget *main_widget )
{
    GtkWidget *dialog;
    GtkWidget *entry_name;
    GtkWidget *entry_list;
    GtkWidget *spin_bouton;
    GtkWidget *colorise_bouton;
    gint action = 1; /* 1 create 2 modify */
    gint result;

    devel_debug ( NULL);

    dialog = gsb_partial_balance_create_dialog ( action,
                        g_slist_length ( partial_balance_list ) + 1 );

    entry_name = g_object_get_data ( G_OBJECT ( dialog ), "entry_name" );
    entry_list = g_object_get_data ( G_OBJECT ( dialog ), "entry_list" );
    spin_bouton = g_object_get_data ( G_OBJECT ( dialog ), "spin_bouton" );
    colorise_bouton = g_object_get_data ( G_OBJECT ( dialog ), "colorise_bouton" );

    gtk_widget_show_all ( GTK_WIDGET ( dialog ) );

dialog_return:
    result = gtk_dialog_run ( GTK_DIALOG ( dialog ) );

    if (result == GTK_RESPONSE_OK)
    {
        GtkTreeView *treeview;
        GtkTreeModel *model;
        const gchar *name, *liste_cptes;
        gint partial_balance_number;
        gint position;

        name = gtk_entry_get_text ( GTK_ENTRY ( entry_name ) );
        liste_cptes = gtk_entry_get_text ( GTK_ENTRY ( entry_list ) );

        if ( strlen ( name ) && strlen ( liste_cptes )
         &&
         g_utf8_strchr  ( liste_cptes, -1, ';' ) )
        {
            position = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON ( spin_bouton ) );
            if ( position > (gint) g_slist_length ( partial_balance_list ) )
                partial_balance_number = gsb_partial_balance_new ( name );
            else
                partial_balance_number = gsb_partial_balance_new_at_position (
                        name, position );

            gsb_data_partial_balance_set_liste_cptes ( partial_balance_number,
                        liste_cptes );
            gsb_data_partial_balance_init_from_liste_cptes ( partial_balance_number,
                        dialog );
            gsb_data_partial_balance_set_colorise ( partial_balance_number,
                        gtk_toggle_button_get_active (
                        GTK_TOGGLE_BUTTON ( colorise_bouton ) ) );

            /* on met à jour le model */
            treeview = g_object_get_data ( G_OBJECT (main_widget), "treeview" );
            model = gtk_tree_view_get_model ( treeview );
            gsb_partial_balance_fill_model ( GTK_LIST_STORE ( model ) );

            /* MAJ HOME_PAGE */
            gsb_gui_navigation_update_home_page ( );
        }
        else if (  g_utf8_strchr ( liste_cptes, -1, ';' ) == NULL )
        {
            dialogue_warning_hint ( _("You must select at least two accounts."),
                        _("Only one account is selected.") );
            goto dialog_return;
        }
        else
        {
            dialogue_warning_hint ( _("The name of the partial balance "
                        "and the list of accounts must be completed."),
                        _("All fields are not filled in") );
            goto dialog_return;
        }
    }
    gtk_widget_destroy ( GTK_WIDGET ( dialog ) );
}


/**
 * Edit a partial_balance
 *
 * */
void gsb_partial_balance_edit ( GtkWidget *button, GtkWidget *main_widget )
{
    GtkWidget *dialog;
    GtkWidget *entry_name;
    GtkWidget *entry_list;
    GtkWidget *spin_bouton;
    GtkWidget *colorise_bouton;
    GtkWidget *account_list;
    GtkWidget *treeview;
    GtkWidget *account_treeview;
    GtkTreeSelection *selection;
    GtkTreeModel *model;
    GtkTreeIter iter;
    gchar *balance_name;
    gchar *liste_cptes;
    gint partial_balance_number;
    gint action = 2; /* 1 create 2 modify */
    gint result;

    devel_debug ( NULL);

    dialog = gsb_partial_balance_create_dialog ( action,
                        g_slist_length ( partial_balance_list ) + 1 );

    entry_name = g_object_get_data ( G_OBJECT ( dialog ), "entry_name" );
    entry_list = g_object_get_data ( G_OBJECT ( dialog ), "entry_list" );
    account_list = g_object_get_data ( G_OBJECT ( dialog ), "account_list" );
    spin_bouton = g_object_get_data ( G_OBJECT ( dialog ), "spin_bouton" );
    colorise_bouton = g_object_get_data ( G_OBJECT ( dialog ), "colorise_bouton" );

    gtk_widget_show_all ( GTK_WIDGET ( dialog ) );

    /* initialisation des données */
    treeview = g_object_get_data ( G_OBJECT ( main_widget ), "treeview" );
    selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW (treeview) );
    if ( !gtk_tree_selection_get_selected ( selection, &model, &iter) )
        return ;

    gtk_tree_model_get ( model, &iter,
                        0, &balance_name,
                        1, &liste_cptes,
                        4, &partial_balance_number,
                        -1);

    gtk_entry_set_text ( GTK_ENTRY ( entry_name ), balance_name );
    gtk_entry_set_text ( GTK_ENTRY ( entry_list ), liste_cptes );
    gtk_spin_button_set_value ( GTK_SPIN_BUTTON ( spin_bouton ),
                        (gdouble) partial_balance_number );
    gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( colorise_bouton ),
                        gsb_data_partial_balance_get_colorise (
                        partial_balance_number ) );
    account_treeview = g_object_get_data ( G_OBJECT ( account_list ), "account_treeview");
    gsb_partial_balance_selectionne_cptes ( account_treeview, liste_cptes );

    gtk_widget_show_all ( GTK_WIDGET ( dialog ) );

dialog_return:
    result = gtk_dialog_run ( GTK_DIALOG ( dialog ));

    if (result == GTK_RESPONSE_OK)
    {
        const gchar *name, *new_liste_cptes;
        gint position;

        name = gtk_entry_get_text ( GTK_ENTRY ( entry_name ) );
        new_liste_cptes = gtk_entry_get_text ( GTK_ENTRY ( entry_list ) );

        if ( strlen ( name ) && strlen (new_liste_cptes) &&
         g_utf8_strchr  (new_liste_cptes, -1, ';' ) )
        {
            gsb_data_partial_balance_set_name ( partial_balance_number, name );
            gsb_data_partial_balance_set_liste_cptes ( partial_balance_number, new_liste_cptes);
            gsb_data_partial_balance_init_from_liste_cptes ( partial_balance_number,
                        dialog );
            gsb_data_partial_balance_set_colorise ( partial_balance_number,
                        gtk_toggle_button_get_active (
                        GTK_TOGGLE_BUTTON ( colorise_bouton ) ) );

            position = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON ( spin_bouton ) );
            if ( position != partial_balance_number )
            gsb_data_partial_balance_move ( partial_balance_number, position );

            /* on met à jour le model */
            gsb_partial_balance_fill_model ( GTK_LIST_STORE ( model ) );

            /* MAJ HOME_PAGE */
            gsb_gui_navigation_update_home_page ( );
        }
        else if (  g_utf8_strchr (new_liste_cptes, -1, ';' ) == NULL )
        {
            dialogue_warning_hint ( _("You must select at least two accounts."),
                        _("Only one account is selected.") );
            goto dialog_return;
        }
        else
        {
            dialogue_warning_hint ( _("The name of the partial balance "
                        "and the list of accounts must be completed."),
                        _("All fields are not filled in") );
            goto dialog_return;
        }
    }
    gtk_widget_destroy ( GTK_WIDGET ( dialog ) );
}


/**
 * remove a partial_balance
 *
 * */
void gsb_partial_balance_remove ( GtkWidget *button, GtkWidget *main_widget )
{
    GtkTreeView *treeview;
    GtkTreeModel *model;
    GtkTreeIter iter;
    GSList *list_tmp;
    gint partial_balance_number;

    treeview = g_object_get_data ( G_OBJECT (main_widget), "treeview" );
    if ( !gtk_tree_selection_get_selected (
                        gtk_tree_view_get_selection (treeview),
                        &model,
                        &iter ))
        return;

    gtk_tree_model_get ( model, &iter, 4, &partial_balance_number, -1 );

    if ( partial_balance_number > 0 )
    {
        list_tmp = partial_balance_list;
        while ( list_tmp )
        {
            struct_partial_balance *partial_balance;

            partial_balance = list_tmp -> data;

            if ( partial_balance -> partial_balance_number == partial_balance_number )
            {
                GtkWidget *edit_button;

                partial_balance_list = g_slist_remove (
                        partial_balance_list, partial_balance );
                gsb_partial_balance_renumerote ( );
                gtk_list_store_remove  ( GTK_LIST_STORE ( model ), &iter );

                /* MAJ HOME_PAGE */
                gsb_gui_navigation_update_home_page ( );

                edit_button = g_object_get_data ( G_OBJECT (main_widget), "edit_button" );
                gtk_widget_set_sensitive ( edit_button, FALSE );
                gtk_widget_set_sensitive ( button, FALSE );
                break;
            }
            list_tmp = list_tmp -> next;
        }
    }
}


/**
 * renumerote la liste des soldes partiels
 *
 * */
void gsb_partial_balance_renumerote ( void )
{
    GSList *list_tmp;
    gint i = 1;

    list_tmp = partial_balance_list;
    while ( list_tmp )
    {
        struct_partial_balance *partial_balance;

        partial_balance = list_tmp -> data;
        partial_balance -> partial_balance_number = i;
        i++;
        list_tmp = list_tmp -> next;
    }
}


/**
 * Fonction appellée quand on sélectionne un solde partiel
 *
 * */
gboolean gsb_partial_balance_select_func ( GtkTreeSelection *selection,
                        GtkTreeModel *model,
                        GtkTreePath *path,
                        gboolean path_currently_selected,
                        GObject *main_widget )
{
    GtkWidget *button;

    button = g_object_get_data ( G_OBJECT (main_widget), "edit_button" );
    gtk_widget_set_sensitive ( button, TRUE );
    button = g_object_get_data ( G_OBJECT (main_widget), "remove_button" );
    gtk_widget_set_sensitive ( button, TRUE );

    return TRUE;
}


/**
 * sélectionne les comptes donnés en paramètre
 *
 * */
void gsb_partial_balance_selectionne_cptes ( GtkWidget *tree_view,
                        const gchar *liste_cptes )
{
    GtkTreeModel *model;
    GtkTreeIter iter;
    GtkTreeSelection *selection;
    gchar **tab;
    gint i;
    gint num_cpte;
    gboolean valid;

    model = gtk_tree_view_get_model ( GTK_TREE_VIEW ( tree_view ) );
    selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW ( tree_view ) );

    if ( liste_cptes == NULL || strlen ( liste_cptes ) == 0 )
        return;

    tab = g_strsplit ( liste_cptes, ";", 0 );
    for ( i = 0; tab[i]; i++ )
    {
        num_cpte = utils_str_atoi ( tab[i] );

        valid = gtk_tree_model_get_iter_first ( model, &iter);
        while ( valid )
        {
            gint   account_nb;

            gtk_tree_model_get ( model, &iter, 1, &account_nb, -1 );
            if ( account_nb == num_cpte )
                gtk_tree_selection_select_iter ( selection, &iter);

            valid = gtk_tree_model_iter_next ( model, &iter );
        }
    }
    g_strfreev ( tab );
}


/**
 * gère le clavier sur la liste des soldes partiels
 *
**/
gboolean gsb_partial_balance_key_press ( GtkWidget *tree_view, GdkEventKey *ev )
{
    switch ( ev -> keyval )
    {
    case GDK_KEY_Return :   /* entrée */
    case GDK_KEY_KP_Enter :
    case GDK_KEY_Tab :
        g_object_set_data ( G_OBJECT ( tree_view ), "treeview", tree_view );
        gsb_partial_balance_edit ( NULL, tree_view );
        return TRUE;
        break;
    case GDK_KEY_Delete:    /*  del  */
        g_object_set_data ( G_OBJECT ( tree_view ), "treeview", tree_view );
        gsb_partial_balance_remove ( NULL, tree_view );
        return TRUE;
        break;
    }

    return FALSE;
}


/**
 * called when press a mouse button on the partial_balance_list
 *
 * \param tree_view
 * \param ev a GdkEventButton
 *
 * \return TRUE if double - click else FALSE
 * */
gboolean gsb_partial_balance_button_press ( GtkWidget *tree_view,
                        GdkEventButton *ev,
                        gpointer null )
{
    /*     if we are not in the list, go away */
    if ( ev -> window != gtk_tree_view_get_bin_window ( GTK_TREE_VIEW ( tree_view ) ) )
        return FALSE;

    /*  if double - click */
    if ( ev -> type == GDK_2BUTTON_PRESS )
    {
        g_object_set_data ( G_OBJECT ( tree_view ), "treeview", tree_view );
        gsb_partial_balance_edit ( NULL, tree_view );
        return TRUE;
    }

    return FALSE;
}


/**
 *
 *
**/
void gsb_partial_balance_colorise_toggled ( GtkCellRendererToggle *cell,
                        gchar *path_str,
                        GtkWidget *tree_view )
{
    GtkTreePath * treepath;
    GtkTreeIter iter;
    gboolean toggle;
    gint partial_number;
    GtkTreeModel *model;

    devel_debug (NULL);

    model = gtk_tree_view_get_model ( GTK_TREE_VIEW ( tree_view ) );

    /* invert the toggle */
    treepath = gtk_tree_path_new_from_string ( path_str );
    gtk_tree_model_get_iter ( GTK_TREE_MODEL (model), &iter, treepath );

    gtk_tree_model_get ( GTK_TREE_MODEL ( model ), &iter,
                        4, &partial_number,
                        5, &toggle,
                        -1);
    toggle ^= 1;
    gtk_list_store_set (GTK_LIST_STORE ( model ), &iter, 5, toggle, -1);

     /* and save it */
    gsb_data_partial_balance_set_colorise ( partial_number, toggle );

    /* MAJ HOME_PAGE */
    gsb_gui_navigation_update_home_page ( );
}


/*********************************************************************************************/
/*              Données                                                                      */
/*********************************************************************************************/
/**
 * set the partial_balance global variables to NULL,
 * usually when we init all the global variables
 *
 * \param
 *
 * \return FALSE
 * */
gboolean gsb_data_partial_balance_init_variables ( void )
{
    if ( partial_balance_list )
    {
        GSList* tmp_list = partial_balance_list;
        while ( tmp_list )
        {
            struct_partial_balance *partial_balance;

            partial_balance = tmp_list -> data;
            tmp_list = tmp_list -> next;
            _gsb_data_partial_balance_free ( partial_balance );
        }
        g_slist_free ( partial_balance_list );
    }
    partial_balance_list = NULL;
    partial_balance_buffer = NULL;

    return FALSE;
}


/**
 * find and return the structure of the partial_balance asked
 *
 * \param partial_balance_number number of partial_balance
 *
 * \return the adr of the struct of the partial_balance (NULL if doesn't exit)
 * */
gpointer gsb_data_partial_balance_get_structure ( gint partial_balance_number )
{
    GSList *tmp;

    if ( !partial_balance_number )
        return NULL;

    /* before checking all the import rule, we check the buffer */
    if ( partial_balance_buffer
     &&
     partial_balance_buffer -> partial_balance_number == partial_balance_number )
        return partial_balance_buffer;

    tmp = partial_balance_list;

    while ( tmp )
    {
        struct_partial_balance *partial_balance;

        partial_balance = tmp -> data;

        if ( partial_balance -> partial_balance_number == partial_balance_number )
        {
            partial_balance_buffer = partial_balance;
            return partial_balance;
        }

        tmp = tmp -> next;
    }
    return NULL;
}


/**
 * give the g_slist of partial_balance structure
 * usefull when want to check all partial_balance
 * carrefull : it's not a copy, so we must not free or change it
 *
 * \param none
 *
 * \return the g_slist of partial_balance structure
 * */
GSList *gsb_data_partial_balance_get_list ( void )
{
    return partial_balance_list;
}


/**
 * return the number of the partial_balance given in param
 *
 * \param balance_ptr a pointer to the struct of the partial_balance
 *
 * \return the number of the partial_balance, 0 if problem
 * */
gint gsb_data_partial_balance_get_number ( gpointer balance_ptr )
{
    struct_partial_balance *partial_balance;

    if ( !balance_ptr )
        return 0;

    partial_balance = balance_ptr;
    partial_balance_buffer = partial_balance;
    return partial_balance -> partial_balance_number;
}


/**
 * This internal function is called to free the memory used by an
 * struct_partial_balance structure
 */
static void _gsb_data_partial_balance_free ( struct_partial_balance *partial_balance)
{
    if ( ! partial_balance )
        return;
    if ( partial_balance -> balance_name
     &&
     strlen ( partial_balance -> balance_name ) )
        g_free ( partial_balance -> balance_name );
    if ( partial_balance -> liste_cptes
     &&
     strlen ( partial_balance -> liste_cptes ) )
        g_free ( partial_balance -> liste_cptes );

    g_free ( partial_balance );

    if ( partial_balance_buffer == partial_balance )
        partial_balance_buffer = NULL;
}


/**
 * return the liste_cptes of the partial_balance
 *
 * \param partial_balance_number the number of the partial_balance
 *
 * \return the liste_cptes of the partial_balance or NULL if fail
 * */
const gchar *gsb_data_partial_balance_get_liste_cptes ( gint partial_balance_number )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return NULL;

    return partial_balance -> liste_cptes;
}


/**
 * set the liste_cptes of the partial_balance
 * the value is dupplicate in memory
 *
 * \param partial_balance_number the number of the partial_balance
 * \param liste_cptes of the partial_balance
 *
 * \return TRUE if ok or FALSE if problem
 * */
gboolean gsb_data_partial_balance_set_liste_cptes ( gint partial_balance_number,
                        const gchar *liste_cptes )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return FALSE;

    /* we free the last name */
    if ( partial_balance -> liste_cptes )
        g_free (partial_balance -> liste_cptes);

    /* and copy the new one */
    partial_balance -> liste_cptes = my_strdup ( liste_cptes );

    return TRUE;
}


/**
 * return the name of the partial_balance
 *
 * \param partial_balance_number the number of the partial_balance
 *
 * \return the name of the partial_balance or NULL if fail
 * */
const gchar *gsb_data_partial_balance_get_name ( gint partial_balance_number )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return NULL;

    return partial_balance -> balance_name;
}


/**
 * set the name of the import_rule
 * the value is dupplicate in memory
 *
 * \param import_rule_number the number of the import_rule
 * \param name the name of the import_rule
 *
 * \return TRUE if ok or FALSE if problem
 * */
gboolean gsb_data_partial_balance_set_name ( gint partial_balance_number,
                        const gchar *name )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return FALSE;

    /* we free the last name */
    if ( partial_balance -> balance_name )
        g_free (partial_balance -> balance_name);

    /* and copy the new one */
    partial_balance -> balance_name = my_strdup ( name );

    return TRUE;
}


/**
 * get the kind of the partial_balance
 * \param partial_balance_number no of the partial_balance
 *
 * \return partial_balance type or 0 if the partial_balance doesn't exist
 * */
KindAccount gsb_data_partial_balance_get_kind ( gint partial_balance_number )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return 0;

    return partial_balance -> kind;
}


/**
 * set the kind of the partial_balance
 * \param partial_balance_number no of the partial_balance
 * \param kind type to set
 *
 * \return TRUE, ok ; FALSE, problem
 * */
gboolean gsb_data_partial_balance_set_kind ( gint partial_balance_number,
                        KindAccount kind )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return FALSE;

    partial_balance -> kind = kind;

    return TRUE;
}


/**
 * get the currency of the partial_balance
 *
 * \param partial_balance_number no of the partial_balance
 *
 * \return partial_balance currency or 0 if the partial_balance doesn't exist
 * */
gint gsb_data_partial_balance_get_currency ( gint partial_balance_number )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return 0;

    return partial_balance -> currency;
}


/**
 * set the currency of the partial_balance
 *
 * \param partial_balance_number no of the partial_balance
 * \param currency to set
 *
 * \return TRUE, ok ; FALSE, problem
 * */
gboolean gsb_data_partial_balance_set_currency ( gint partial_balance_number,
                        gint currency )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return FALSE;

    partial_balance -> currency = currency;

    return TRUE;
}


/**
 *
 *
 * \param partial_balance_number no of the partial_balance
 *
 * \return
 * */
gboolean gsb_data_partial_balance_get_colorise ( gint partial_balance_number )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return 0;

    return partial_balance -> colorise;
}


/**
 * \param partial_balance_number no of the partial_balance
 * \param colorise
 *
 * \return TRUE, ok ; FALSE, problem
 * */
gboolean gsb_data_partial_balance_set_colorise ( gint partial_balance_number,
                        gboolean colorise )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return FALSE;

    partial_balance -> colorise = colorise;

    return TRUE;
}


/**
 *
 *
 * */
gchar *gsb_data_partial_balance_get_marked_balance ( gint partial_balance_number )
{
    struct_partial_balance *partial_balance;
    GsbReal solde = null_real;
    gchar **tab;
    gchar *string;
    gint i;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return NULL;

    if ( partial_balance -> liste_cptes == NULL ||
     strlen ( partial_balance -> liste_cptes ) == 0 )
        return NULL;

    tab = g_strsplit ( partial_balance -> liste_cptes, ";", 0 );
    for ( i = 0; tab[i]; i++ )
    {
        GsbReal tmp_real;
        gint account_nb;
        gint account_currency;
        gint link_number;

        account_nb = utils_str_atoi ( tab[i] );
        account_currency = gsb_data_account_get_currency ( account_nb );
        tmp_real = gsb_data_account_get_marked_balance ( account_nb );

        if ( tmp_real.mantissa != 0 && partial_balance -> currency != account_currency )
        {
            if ( ( link_number = gsb_data_currency_link_search ( account_currency,
                        partial_balance -> currency ) ) )
            {
                if ( gsb_data_currency_link_get_first_currency (
                 link_number) == account_currency )
                    tmp_real = gsb_real_mul ( tmp_real,
                                gsb_data_currency_link_get_change_rate ( link_number ) );
                else
                    tmp_real = gsb_real_div ( tmp_real,
                                gsb_data_currency_link_get_change_rate ( link_number ) );
            }

        }
        solde = gsb_real_add ( solde, tmp_real );
    }
    g_strfreev ( tab );

    if (partial_balance->colorise)
    {
        gchar *color;
		gchar *tmp_str;

        if (solde.mantissa < 0)
            color = g_strdup ("red");
        else
		{
			gchar *str_to_free;

			str_to_free = gsb_rgba_get_couleur_to_hexa_string ("text_gsetting_option_normal");
            color = g_strdup (str_to_free);
			g_free (str_to_free);
		}

		tmp_str = utils_real_get_string_with_currency (solde, partial_balance -> currency, TRUE);
        string = g_strdup_printf ("<span color=\"%s\">%s</span>", color, tmp_str);
        g_free ( color );
		g_free (tmp_str);
    }
    else
        string = utils_real_get_string_with_currency (
                        solde, partial_balance -> currency, TRUE );

    return string;
}


/**
 *
 *
 * */
GsbReal gsb_data_partial_balance_get_current_amount ( gint partial_balance_number )
{
    struct_partial_balance *partial_balance;
    GsbReal solde = null_real;
    gchar **tab;
    gint i;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return null_real;

    if ( partial_balance -> liste_cptes == NULL ||
     strlen ( partial_balance -> liste_cptes ) == 0 )
        return null_real;

    tab = g_strsplit ( partial_balance -> liste_cptes, ";", 0 );
    for ( i = 0; tab[i]; i++ )
    {
        GsbReal tmp_real;
        gint account_nb;
        gint account_currency;
        gint link_number;

        account_nb = utils_str_atoi ( tab[i] );
        account_currency = gsb_data_account_get_currency ( account_nb );
        tmp_real = gsb_data_account_get_current_balance ( account_nb );

        if ( tmp_real.mantissa != 0 && partial_balance -> currency != account_currency )
        {
            if ( ( link_number = gsb_data_currency_link_search ( account_currency,
                        partial_balance -> currency ) ) )
            {
                if ( gsb_data_currency_link_get_first_currency (
                        link_number) == account_currency )
                    tmp_real = gsb_real_mul ( tmp_real,
                                gsb_data_currency_link_get_change_rate ( link_number ) );
                else
                    tmp_real = gsb_real_div ( tmp_real,
                                gsb_data_currency_link_get_change_rate ( link_number ) );
            }
        }
        solde = gsb_real_add ( solde, tmp_real );
    }
    g_strfreev ( tab );

    return solde;
}


/**
 *
 *
 * */
gchar *gsb_data_partial_balance_get_current_balance ( gint partial_balance_number )
{
    struct_partial_balance *partial_balance;
    GsbReal solde = null_real;
    gchar *string;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return NULL;

    solde = gsb_data_partial_balance_get_current_amount ( partial_balance_number );

    if (partial_balance->colorise)
    {
        gchar *color;
		gchar *tmp_str;

        if (solde.mantissa < 0)
            color = g_strdup ("red");
        else
		{
			gchar *str_to_free;

			str_to_free = gsb_rgba_get_couleur_to_hexa_string ("text_gsetting_option_normal");
            color = g_strdup (str_to_free);
			g_free (str_to_free);
		}

		tmp_str = utils_real_get_string_with_currency (solde, partial_balance -> currency, TRUE);
        string = g_strdup_printf ( "<span color=\"%s\">%s</span>", color, tmp_str);
        g_free ( color );
		g_free (tmp_str);
    }
    else
        string = utils_real_get_string_with_currency (
                        solde, partial_balance -> currency, TRUE );

    return string;
}


/**
 *
 *
 * */
gboolean gsb_partial_balance_select_account ( GtkTreeSelection *selection,
                        GtkTreeModel *model,
                        GtkTreePath *path,
                        gboolean path_currently_selected,
                        GObject *entry )
{
    GList *list;

    if ( strlen ( gtk_entry_get_text ( GTK_ENTRY ( entry ) ) ) > 0 )
        gtk_entry_set_text ( GTK_ENTRY ( entry ), "" );

    list = gtk_tree_selection_get_selected_rows ( selection, NULL );

    if ( path_currently_selected )
    {
        while ( list )
        {
            GtkTreeIter iter;
            gint account_nb;

            if ( gtk_tree_path_compare ( path, list -> data ) != 0 )
            {
                gtk_tree_model_get_iter ( model, &iter, list -> data );
                gtk_tree_model_get ( model, &iter, 1, &account_nb, -1);
                if ( strlen ( gtk_entry_get_text ( GTK_ENTRY ( entry ) ) ) > 0 )
                {
					gchar *tmp_str = g_strdup_printf ( "%d", account_nb );
                    gtk_entry_set_text ( GTK_ENTRY ( entry ),
                                g_strconcat ( gtk_entry_get_text ( GTK_ENTRY ( entry ) ), ";",
                                tmp_str, NULL));
					g_free(tmp_str);
                }
                else
                    gtk_entry_set_text ( GTK_ENTRY ( entry ), g_strdup_printf ( "%d", account_nb ) );
            }
            list = list -> next;
        }
    }
    else
    {
        list = g_list_append ( list, gtk_tree_path_copy ( path ) );

        while ( list )
        {
            GtkTreeIter iter;
            gint account_nb;

            gtk_tree_model_get_iter ( model, &iter, list -> data );
            gtk_tree_model_get ( model, &iter, 1, &account_nb, -1);
            if ( strlen ( gtk_entry_get_text ( GTK_ENTRY ( entry ) ) ) > 0 )
            {
				gchar *tmp_str1, *tmp_str2;
				tmp_str1 = g_strdup_printf ( "%d", account_nb );
				tmp_str2 = g_strconcat ( gtk_entry_get_text ( GTK_ENTRY ( entry ) ), ";",
										tmp_str1, NULL );
                gtk_entry_set_text ( GTK_ENTRY ( entry ), tmp_str2);
				g_free(tmp_str1);
				g_free(tmp_str2);
            }
            else
			{
				gchar *tmp_str1;
				tmp_str1 = g_strdup_printf ( "%d", account_nb );
                gtk_entry_set_text ( GTK_ENTRY ( entry ), tmp_str1 );
				g_free(tmp_str1);
			}

            list = list -> next;
        }
    }

    g_list_free_full ( list, ( GDestroyNotify ) gtk_tree_path_free );

    return TRUE;
}


/**
 * Détermine la devise et le type de compte pour le solde partiel
 *
 * \param partial_balance_number
 *
 * \return FALSE si tous les comptes n'ont pas les mêmes données sinon TRUE
 * */
gboolean gsb_data_partial_balance_init_from_liste_cptes ( gint partial_balance_number,
                        GtkWidget *parent )
{
    struct_partial_balance *partial_balance;
    gchar **tab;
    gint i;
    gint account_nb;
    gint currency_nb = 0;
    KindAccount kind = -1;
    KindAccount kind_nb = -1;
    gchar *tmp_str;
    gboolean return_val = TRUE;
    gboolean currency_mixte = FALSE;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return FALSE;

    if ( partial_balance -> liste_cptes == NULL ||
     strlen ( partial_balance -> liste_cptes ) == 0 )
        return FALSE;

    tab = g_strsplit ( partial_balance -> liste_cptes, ";", 0 );
    for ( i = 0; tab[i]; i++ )
    {
        gint account_currency;

        account_nb = utils_str_atoi ( tab[i] );
        account_currency = gsb_data_account_get_currency ( account_nb );
        if ( currency_nb == 0 )
            currency_nb = account_currency;
        else if ( currency_nb != account_currency )
        {
            if ( currency_mixte == FALSE )
            {
                no_devise_solde_partiels = gsb_partial_balance_request_currency ( parent );
                if ( gsb_data_currency_link_search ( currency_nb, account_currency ) == 0 )
                {
                    tmp_str = g_strdup_printf (
                            _("You need to create a link between currency %s and %s."),
                            gsb_data_currency_get_name ( currency_nb ),
                            gsb_data_currency_get_name ( account_currency ) );
                    dialogue_warning_hint ( tmp_str,
                            _("Attention missing link between currencies") );
                }
            }
            currency_mixte = TRUE;
            return_val = FALSE;
        }
        if ( kind == -1 )
            kind = gsb_data_account_get_kind ( account_nb );
        else if ( ( kind_nb = gsb_data_account_get_kind ( account_nb ) ) != kind )
        {
            switch ( kind )
            {
            case GSB_TYPE_BALANCE:
                break;

            case GSB_TYPE_BANK:
            case GSB_TYPE_CASH:
                if ( kind_nb >= GSB_TYPE_LIABILITIES )
                    return_val = FALSE;
                break;

            case GSB_TYPE_LIABILITIES:
                return_val = FALSE;
                break;

            case GSB_TYPE_ASSET:
                return_val = FALSE;
                break;
            }
        }
    }
    g_strfreev ( tab );

    if ( currency_mixte )
        gsb_data_partial_balance_set_currency ( partial_balance_number,
                        no_devise_solde_partiels );
    else
        gsb_data_partial_balance_set_currency ( partial_balance_number, currency_nb );
    if ( return_val == FALSE )
        gsb_data_partial_balance_set_kind ( partial_balance_number, -1 );
    else
        gsb_data_partial_balance_set_kind ( partial_balance_number, kind );

    return return_val;
}


/**
 * callback when tree_view Home tab receive a drag and drop signal
 *
 * \param drag_dest
 * \param dest_path
 * \param selection_data
 *
 * \return FALSE
 */
gboolean gsb_data_partial_balance_drag_data_received ( GtkTreeDragDest * drag_dest,
                        GtkTreePath * dest_path,
                        GtkSelectionData * selection_data )
{
    gchar *tmpstr = gtk_tree_path_to_string ( dest_path );
    gchar *tmpstr2 = g_strdup_printf ( "Dest path : %s", tmpstr);
    devel_debug (tmpstr2);
    g_free (tmpstr);
    g_free (tmpstr2);

    if ( dest_path && selection_data )
    {
        GtkTreeModel * model;
        GtkTreeIter iter;
        GtkTreePath * orig_path;
        gint orig_partial_number = 0;
        gint dest_pos;

        /* On récupère le model et le path d'origine */
        gtk_tree_get_row_drag_data (selection_data, &model, &orig_path);

        if ( gtk_tree_model_get_iter ( model, &iter, orig_path ) )
            gtk_tree_model_get ( model, &iter, 4, &orig_partial_number, -1 );

        dest_pos = utils_str_atoi ( gtk_tree_path_to_string ( dest_path ) );

        gsb_data_partial_balance_move ( orig_partial_number, dest_pos );
        gsb_partial_balance_fill_model ( GTK_LIST_STORE ( model ) );

        /* MAJ HOME_PAGE */
            gsb_gui_navigation_update_home_page ( );
    }
    return FALSE;
}


/**
 * Fill the drag & drop structure with the path of selected column.
 * This is an interface function called from GTK, much like a callback.
 *
 * \param drag_source		Not used.
 * \param path			Original path for the gtk selection.
 * \param selection_data	A pointer to the drag & drop structure.
 *
 * \return FALSE, to allow future processing by the callback chain.
 */
gboolean gsb_data_partial_balance_drag_data_get ( GtkTreeDragSource * drag_source,
                        GtkTreePath * path,
                        GtkSelectionData * selection_data )
{
    if ( path )
        gtk_tree_set_row_drag_data ( selection_data, GTK_TREE_MODEL( model_accueil ), path );

    return FALSE;
}


/**
 * change the position of partial_balance in the list
 *
 * \param account_number	the partial_balance we want to move
 * \param dest_account_number	partial_balance before we want to move
 *
 * \return FALSE
 * */
gboolean gsb_data_partial_balance_move ( gint orig_partial_number, gint dest_pos )
{
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( orig_partial_number );

    if ( !orig_partial_number )
        return FALSE;

    partial_balance_list = g_slist_remove ( partial_balance_list, partial_balance );
    partial_balance_list = g_slist_insert ( partial_balance_list, partial_balance, dest_pos );
    gsb_partial_balance_renumerote ( );

    return FALSE;
}


/**
 * calcule le solde des comptes d'un solde partiel à une date donnée
 *
 * \param account_number    numéro du compte concerné
 * \param date              date de calcul du solde
 *
 * \return GPtrArray        un tableau avec le solde de chaque compte concerné
 * */
GPtrArray *gsb_data_partial_balance_calculate_balances_at_date ( gint partial_balance_number,
                        GDate *date )
{
    GSList *tmp_list;
    GPtrArray *current_balances;
    GPtrArray *current_balances_later;
    GArray *floating_points;
    GArray *account_numbers;
    gchar **tab;
    gint i;
    gint nbre_comptes;
    struct_partial_balance *partial_balance;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return NULL;

    tab = g_strsplit ( partial_balance->liste_cptes, ";", 0 );

    nbre_comptes = g_strv_length ( tab );
    if ( nbre_comptes )
    {
        floating_points = g_array_new ( FALSE, TRUE, sizeof ( gint ) );
        account_numbers = g_array_new ( FALSE, TRUE, sizeof ( gint ) );
        current_balances = g_ptr_array_new ();
        current_balances_later = g_ptr_array_new ();
    }
    else
        return NULL;

    for ( i = 0; tab[i]; i++ )
    {
        gint account_number;
        gint floating_point;
        GsbReal *balance;
        GsbReal tmp_balance;

        /* on remplit le tableau des numeros des comptes */
        account_number = utils_str_atoi ( tab[i] );
        g_array_append_val ( account_numbers, account_number );

        /* on remplit le tableau des données des devises */
        floating_point = gsb_data_account_get_currency_floating_point ( account_number );
        g_array_append_val ( floating_points, floating_point );

        /* on initialise le tableau des soldes de chaque compte */
        balance = g_malloc0 ( sizeof ( GsbReal ) );
        tmp_balance = gsb_data_account_get_init_balance ( account_number, floating_point );
        balance->mantissa = tmp_balance.mantissa;
        balance->exponent = tmp_balance.exponent;
        g_ptr_array_add ( current_balances, balance );

        /* on initialise le tableau des soldes en erreur de chaque compte */
        balance = g_malloc0 ( sizeof ( GsbReal ) );
        balance->mantissa = null_real.mantissa;
        balance->exponent = null_real.exponent;
        g_ptr_array_add ( current_balances_later, balance );
    }

    tmp_list = gsb_data_transaction_get_complete_transactions_list ();

    while (tmp_list)
    {
        gint transaction_number;

        transaction_number = gsb_data_transaction_get_transaction_number ( tmp_list->data );

        for ( i = 0; i < nbre_comptes; i++ )
        {
            gint account_number;
            gboolean trouve = FALSE;

            account_number = g_array_index ( account_numbers, gint, i );

            if ( gsb_data_transaction_get_account_number ( transaction_number ) == account_number )
            {
                if ( g_date_compare ( gsb_data_transaction_get_value_date_or_date ( transaction_number ),
                 date ) <= 0 )
                {
                    if ( gsb_data_transaction_get_mother_transaction_number ( transaction_number ) == 0 )
                    {
                        trouve = TRUE;
                    }
                }
            }
            if ( trouve )
            {
                gint floating_point;
                GsbReal adjusted_amout;
                GsbReal tmp_balance;
                GsbReal *balance;
                GsbReal current_balance;

                floating_point = g_array_index ( floating_points, gint, i );
                balance = (GsbReal *) g_ptr_array_index ( current_balances, i );
                current_balance.mantissa = balance->mantissa;
                current_balance.exponent = balance->exponent;

                adjusted_amout = gsb_data_transaction_get_adjusted_amount ( transaction_number, floating_point );
                tmp_balance = gsb_real_add ( current_balance, adjusted_amout );

                if ( tmp_balance.mantissa != error_real.mantissa )
                {
                    balance->mantissa = tmp_balance.mantissa;
                    balance->exponent = tmp_balance.exponent;
                }
                else
                {
                    GsbReal *balance_later;

                    balance_later = (GsbReal *) g_ptr_array_index ( current_balances_later, i );
                    balance_later->mantissa = G_MININT64;
                    balance_later->exponent = 0;
                }
            }
        }
        tmp_list = tmp_list->next;
    }
    g_array_free ( account_numbers, TRUE );
    g_array_free ( floating_points, TRUE );

    return current_balances;
}

/**
 *
 *
 * \param
 *
 * \return
 **/
void gsb_data_partial_balance_renum_account_number_0 (gint account_number)
{
    GSList *tmp_list;

    tmp_list = partial_balance_list;
    while (tmp_list)
    {
		gchar *liste_cptes;
        struct_partial_balance *partial_balance;

        partial_balance = tmp_list->data;
		liste_cptes = partial_balance->liste_cptes;
		if (g_strstr_len (liste_cptes, -1, "0"))
		{
			gchar **tab;
			gint i;

			tab = g_strsplit (liste_cptes, ";", 0);
			for ( i = 0; tab[i]; i++ )
			{
				gint account_nb;

				account_nb = utils_str_atoi (tab[i]);
				if (account_nb == 0)
				{
					gchar *tmp_number_str;
					gchar *str_to_free;
					gchar *new_str;

					tmp_number_str = utils_str_itoa (account_number);
					str_to_free = tab[i];
					tab[i] = tmp_number_str;
					g_free (str_to_free);
					new_str = g_strjoinv (";", tab);
					g_free (partial_balance->liste_cptes);
					partial_balance->liste_cptes = new_str;
					break;
				}
			}
			g_strfreev (tab);
		}
		tmp_list = tmp_list->next;
	}
}

/**
 *
 *
 * \param
 *
 * \return
 **/
void gsb_partial_balance_remove_from_account (gint deleted_account)
{
	GSList *tmp_list;
	gchar *deleted_account_str;

	deleted_account_str = utils_str_itoa (deleted_account);
	tmp_list = partial_balance_list;
	while (tmp_list)
	{
		gchar *liste_cptes;
		struct_partial_balance *partial_balance;

		partial_balance = tmp_list->data;
		liste_cptes = partial_balance->liste_cptes;
		if (g_strstr_len (liste_cptes, -1, deleted_account_str))
		{
			gchar **tab;
			gint i;

			tab = g_strsplit (liste_cptes, ";", 0);
			for ( i = 0; tab[i]; i++ )
			{
				gint account_nb;

				account_nb = utils_str_atoi (tab[i]);
				if (account_nb == deleted_account)
				{
					gchar *str_to_free_1 = NULL;
					gchar *str_to_free_2;

					if (i == 0)
					{
						str_to_free_1 = g_strconcat (tab[i], ";", NULL);
					}
					else
					{
						str_to_free_1 = g_strconcat (";", tab[i], NULL);
					}
					str_to_free_2 = partial_balance->liste_cptes;
					partial_balance->liste_cptes = gsb_string_remplace_string (str_to_free_2, str_to_free_1, "");
					g_free(str_to_free_1);
				}
			}
			g_strfreev(tab);
		}
		tmp_list = tmp_list->next;
	}
	g_free(deleted_account_str);
}

/*********************************************************************************************/
/*              Interface                                                                    */
/*********************************************************************************************/
/**
 *
 *
 * */
GtkWidget *gsb_partial_balance_create_list_accounts ( GtkWidget *entry )
{
    GtkWidget *vbox;
    GtkWidget *sw;
    GtkWidget *treeview;
    GtkListStore *list_store;
    GtkTreeIter iter;
    GSList *list_tmp;
    GtkTreeViewColumn *column;
    GtkCellRenderer *cell;
    GtkTreeSelection *selection;
    gint i = 0;

    vbox = gtk_box_new ( GTK_ORIENTATION_VERTICAL, MARGIN_BOX );
    sw = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
                        GTK_SHADOW_ETCHED_IN);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
                        GTK_POLICY_NEVER,
                        GTK_POLICY_ALWAYS);
    gtk_widget_set_size_request( sw, 600, 200 );

    /* create the model */
    list_store = gtk_list_store_new ( 2, G_TYPE_STRING, G_TYPE_INT );
    list_tmp = gsb_data_account_get_list_accounts ();

    while ( list_tmp )
    {
        gint account_number;

        account_number = gsb_data_account_get_no_account ( list_tmp -> data );

        if ( !gsb_data_account_get_closed_account ( account_number ) )
        {
            gtk_list_store_append ( GTK_LIST_STORE ( list_store), &iter );
            gtk_list_store_set ( GTK_LIST_STORE ( list_store ), &iter,
                            0,  gsb_data_account_get_name ( account_number ),
                            1, account_number,
                            -1 );
            i++;
        }
        list_tmp = list_tmp -> next;
    }
    if ( i > 10 )
        i = 10;
    /* create the treeview */
    treeview = gtk_tree_view_new_with_model ( GTK_TREE_MODEL ( list_store ) );
 	gtk_widget_set_name (treeview, "tree_view");
    g_object_unref ( list_store );

    gtk_widget_set_size_request ( treeview, -1, i*20 );
    selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW ( treeview ) );
    gtk_tree_selection_set_mode ( selection, GTK_SELECTION_MULTIPLE );
    gtk_tree_selection_set_select_function ( selection,
                        (GtkTreeSelectionFunc) gsb_partial_balance_select_account,
                        entry, NULL );
    gtk_container_add ( GTK_CONTAINER ( sw ), treeview );
    gtk_box_pack_start ( GTK_BOX ( vbox ), sw, FALSE, FALSE, 0 );
    g_object_set_data ( G_OBJECT (vbox), "account_treeview", treeview );

     /* account name */
    cell = gtk_cell_renderer_text_new ( );
    column = gtk_tree_view_column_new_with_attributes ( _("Account name"),
                        cell,
                        "text",
                        0,
                        NULL );
    gtk_tree_view_column_set_expand ( column, TRUE );
    gtk_tree_view_column_set_sort_column_id ( column, 0 );
    gtk_tree_view_append_column ( GTK_TREE_VIEW ( treeview ), column );

     /* account number */
    cell = gtk_cell_renderer_text_new ();
    column = gtk_tree_view_column_new_with_attributes (_("Account number"), cell, "text", 1, NULL);
    gtk_tree_view_column_set_expand (column, TRUE);
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview ), column);

    return vbox;
}


/**
 *
 *
 * */
GtkWidget *gsb_partial_balance_create_dialog ( gint action, gint spin_value )
{
    GtkWidget *dialog, *label, *main_vbox;
	GtkWidget *button_cancel;
	GtkWidget *button_OK;
    GtkWidget *paddinggrid;
    GtkWidget *entry_name, *entry_list, *account_list, *bouton;
	gchar *tmp_str;

    devel_debug ( NULL);

	if (action == 1)
		tmp_str = g_strdup (_("Add a partial balance"));
	else
		tmp_str = g_strdup (_("Modify a partial balance"));

	dialog = gtk_dialog_new_with_buttons (tmp_str,
										  GTK_WINDOW ( grisbi_app_get_active_window (NULL) ),
										  GTK_DIALOG_MODAL,
										  NULL, NULL,
										  NULL);
	g_free (tmp_str);

	button_cancel = gtk_button_new_with_label (_("Cancel"));
	gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button_cancel, GTK_RESPONSE_CANCEL);
	gtk_widget_set_can_default (button_cancel, TRUE);

	button_OK = gtk_button_new_with_label (_("Validate"));
	gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button_OK, GTK_RESPONSE_OK);
	gtk_widget_set_can_default (button_OK, TRUE);

    gtk_window_set_position ( GTK_WINDOW ( dialog ), GTK_WIN_POS_CENTER_ON_PARENT );

    main_vbox = new_vbox_with_title_and_icon ( _("Partial balance details"), "gsb-payment-32.png" );
    gtk_box_pack_start ( GTK_BOX ( dialog_get_content_area ( dialog ) ), main_vbox, TRUE, TRUE, 0 );

    /* Create paddinggrid */
    paddinggrid = utils_prefs_paddinggrid_new_with_title ( main_vbox, _("Details") );
    gtk_grid_set_column_spacing (GTK_GRID (paddinggrid), 5);
    gtk_grid_set_row_spacing (GTK_GRID (paddinggrid), 5);

    /* Partial balance name */
    label = gtk_label_new ( _("Name: ") );
    utils_labels_set_alignment ( GTK_LABEL ( label ), 0, 1 );
    gtk_label_set_justify ( GTK_LABEL ( label ), GTK_JUSTIFY_RIGHT );
    gtk_grid_attach (GTK_GRID (paddinggrid), label, 0, 0, 1, 1);

    entry_name = gtk_entry_new ( );
    gtk_entry_set_activates_default ( GTK_ENTRY ( entry_name ), TRUE );
    gtk_grid_attach (GTK_GRID (paddinggrid), entry_name, 1, 0, 1, 1);

    /* List of the accounts */
    label = gtk_label_new ( _("Accounts list: ") );
    utils_labels_set_alignment ( GTK_LABEL ( label ), 0, 1);
    gtk_label_set_justify ( GTK_LABEL ( label ), GTK_JUSTIFY_LEFT );
    gtk_grid_attach (GTK_GRID (paddinggrid), label, 0, 1, 1, 1);

    entry_list = gtk_entry_new ( );
    gtk_editable_set_editable ( GTK_EDITABLE ( entry_list ), FALSE );
    gtk_widget_set_sensitive ( entry_list, FALSE );
    gtk_grid_attach (GTK_GRID (paddinggrid), entry_list, 1, 1, 1, 1);

    account_list = gsb_partial_balance_create_list_accounts ( entry_list );
    gtk_grid_attach (GTK_GRID (paddinggrid), account_list, 0, 2, 2, 2);

    /* create the position */
    label = gtk_label_new ( _("Position in the list of accounts: ") );
    gtk_widget_set_margin_top (label, MARGIN_TOP);
    utils_labels_set_alignment ( GTK_LABEL ( label ), 0, 1);
    gtk_label_set_justify ( GTK_LABEL ( label ), GTK_JUSTIFY_LEFT );
    gtk_grid_attach (GTK_GRID (paddinggrid), label, 0, 4, 1, 1);

    bouton = gtk_spin_button_new_with_range ( 1.0, spin_value, 1.0);
    gtk_widget_set_margin_top (bouton, MARGIN_TOP);
    gtk_spin_button_set_value ( GTK_SPIN_BUTTON ( bouton ),
                        g_slist_length ( partial_balance_list ) + 1 );
    gtk_grid_attach (GTK_GRID (paddinggrid), bouton, 1, 4, 1, 1);
    g_object_set_data ( G_OBJECT ( dialog ), "spin_bouton", bouton );

    /* create the colorized button */
    bouton = gtk_check_button_new_with_label ( _("Colorized in red if the balance is negative") );
    gtk_widget_set_margin_top (bouton, MARGIN_TOP);
    g_object_set_data ( G_OBJECT ( dialog ), "colorise_bouton", bouton );
    gtk_grid_attach (GTK_GRID (paddinggrid), bouton, 0, 5, 2, 1);

    g_object_set_data ( G_OBJECT ( dialog ), "entry_name", entry_name );
    g_object_set_data ( G_OBJECT ( dialog ), "entry_list", entry_list );
    g_object_set_data ( G_OBJECT ( dialog ), "account_list", account_list );

    return dialog;
}

/**
 *
 *
 * */
gint gsb_partial_balance_request_currency ( GtkWidget *parent )
{
    GtkWidget *dialog, *hbox, *label, *combo_devise;
	GtkWidget *button_cancel;
	GtkWidget *button_OK;
    gint currency_nb = 1;	/* Initialisation avec la première devise : fixe bug 1881 */

    dialog = gtk_dialog_new_with_buttons (_("Enter the currency of the balance part"),
										  GTK_WINDOW (parent),
										  GTK_DIALOG_MODAL,
										  NULL, NULL,
										  NULL);

	button_cancel = gtk_button_new_with_label (_("Cancel"));
	gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button_cancel, GTK_RESPONSE_CANCEL);
	gtk_widget_set_can_default (button_cancel, TRUE);

	button_OK = gtk_button_new_with_label (_("Validate"));
	gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button_OK, GTK_RESPONSE_OK);
	gtk_widget_set_can_default (button_OK, TRUE);

	gtk_widget_set_size_request ( dialog, -1, 150 );
    gtk_window_set_position ( GTK_WINDOW ( dialog ), GTK_WIN_POS_CENTER_ON_PARENT );

    hbox = gtk_box_new ( GTK_ORIENTATION_HORIZONTAL, MARGIN_BOX );
    gtk_box_pack_start ( GTK_BOX ( dialog_get_content_area( dialog ) ), hbox, TRUE, FALSE, 0 );

    label = gtk_label_new ( _("Select the currency of the partial balance: ") );
    utils_labels_set_alignment ( GTK_LABEL  ( label ), 0, 1 );
    gtk_label_set_justify ( GTK_LABEL ( label ), GTK_JUSTIFY_LEFT );
    gtk_box_pack_start ( GTK_BOX ( hbox ), label, TRUE, TRUE, 0 );

    combo_devise = gsb_currency_combobox_new ( &currency_nb, NULL );
    gtk_box_pack_start ( GTK_BOX ( hbox ), combo_devise, FALSE, FALSE, 10 );

    gtk_widget_show_all ( GTK_WIDGET ( dialog ) );

    gsb_currency_set_combobox_history (combo_devise, currency_nb);
    gtk_dialog_run ( GTK_DIALOG ( dialog ) );

    gtk_widget_destroy ( GTK_WIDGET ( dialog ) );

    return currency_nb;
}

/**
 * calcule le solde d'un solde partiel à une date donnée
 *
 * \param partial_balance_number    numéro du solde partiel concerné
 * \param date                      date de calcul du solde
 *
 * \return GsbReal         le solde du solde partiel
 * */
GsbReal gsb_data_partial_balance_get_balance_at_date ( gint partial_balance_number,
                        GDate *date )
{
    struct_partial_balance *partial_balance;
    GsbReal solde = null_real;
    gchar **tab;
    gint i;

    partial_balance = gsb_data_partial_balance_get_structure ( partial_balance_number );

    if ( !partial_balance )
        return null_real;

    if ( partial_balance -> liste_cptes == NULL ||
     strlen ( partial_balance -> liste_cptes ) == 0 )
        return null_real;

    tab = g_strsplit ( partial_balance -> liste_cptes, ";", 0 );
    for ( i = 0; tab[i]; i++ )
    {
        GsbReal tmp_real;
        gint account_number;
        gint account_currency;
        gint link_number;

        account_number = utils_str_atoi ( tab[i] );
        account_currency = gsb_data_account_get_currency ( account_number );
        tmp_real = gsb_data_account_get_balance_at_date ( account_number, date );

        if ( tmp_real.mantissa != 0 && partial_balance -> currency != account_currency )
        {
            if ( ( link_number = gsb_data_currency_link_search ( account_currency,
                        partial_balance -> currency ) ) )
            {
                if ( gsb_data_currency_link_get_first_currency ( link_number) == account_currency )
                    tmp_real = gsb_real_mul ( tmp_real,
                                gsb_data_currency_link_get_change_rate ( link_number ) );
                else
                    tmp_real = gsb_real_div ( tmp_real,
                                gsb_data_currency_link_get_change_rate ( link_number ) );
            }
        }
        solde = gsb_real_add ( solde, tmp_real );
    }
    g_strfreev ( tab );

    return solde;
}


/**
 *
 *
 * \param
 *
 * \return
 * */
/* Local Variables: */
/* c-basic-offset: 4 */
/* End: */
