/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 2003 rzyjontko

   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; version 2.

   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.  

   ----------------------------------------------------------------------

   mail box selection
   
*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>

#include "select.h"
#include "rstring.h"
#include "xmalloc.h"
#include "gettext.h"
#include "ask.h"
#include "cmd.h"
#include "folder.h"
#include "mybox.h"
#include "error.h"
#include "hook.h"
#include "exec.h"
#include "box_selection.h"
#include "file.h"
#include "wrapbox.h"
#include "color.h"
#include "label.h"
#include "interface.h"
#include "str.h"
#include "eprintf.h"
#include "frames.h"
#include "search.h"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
 ****************************************************************************/

#define PREAMBLE do { if (box_select == NULL) return; } while (0)

/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/

/* This holds an array of directory names. */
static rstring_t *true_items = NULL;

/* Box selection window consists of select_t object and an optional label. */
static elabel_t *label      = NULL;
static select_t *box_select = NULL;

/* Colors used in box_selection window. */
static chtype text_color;
static chtype tree_color;
static chtype tree_bar_color;
static chtype root_color;
static chtype hilight_color;

/* This string is used to eprintf the box information. */
static str_t *str_line = NULL;

/* This string is a format to the eprintf_box function, and controls how
   are boxes displayed. */
static char *box_fmt = " %010n (%u/%t)";

/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/


static void
goto_this_box (const char *path)
{
        int         i;
        const char *short_path = strrchr (path, '/');

        if (short_path == NULL)
                short_path = path;
        else
                short_path++;

        for (i = 0; i < true_items->count; i++){
                if (strcmp (short_path, true_items->array[i]) == 0)
			break;
        }

	if (i < true_items->count)
		select_goto (box_select, i + 1);
}



static void
draw_top (WINDOW *win, int maxlen)
{
        if (win == box_select->win){
                wattrset (win, root_color);
        }
        else {
                wattrset (win, select_bar_color ());
        }
        maxlen -= window_addnstr (win, mybox_dir, maxlen);
        while (maxlen-- > 0)
                window_addch (win, ' ');
}



static void
draw_tree (WINDOW *win, int last)
{
        if (win == box_select->win){
                wattrset (win, text_color);
                window_addch (win, ' ');
                wattrset (win, tree_color);
        }
        else {
                wattrset (win, select_bar_color ());
                window_addch (win, ' ');
                wattrset (win, tree_bar_color);
        }

        if (last)
                window_addch (win, frames_ch (ACS_LLCORNER));
        else
                window_addch (win, frames_ch (ACS_LTEE));
        window_addch (win, frames_ch (ACS_HLINE));
}



static void
set_hilight_color (WINDOW *win)
{
        if (win == box_select->win)
                wattrset (win, hilight_color);
        else
                wattrset (win, select_hilight_color ());
}



static void
unset_hilight_color (WINDOW *win)
{
        if (win == box_select->win)
                wattrset (win, text_color);
        else
                wattrset (win, select_bar_color ());
}



static int
add_string (WINDOW *win, char *str, int maxlen, search_t *search)
{
        int pos = -1;
        int len = 1;

        if (maxlen <= 0)
                return 0;

        if (search)
                pos = search_perform (search, str);

        if (pos != -1){
                len  = search->pattern->len;
                pos -= len - 1;
                if (pos < 0)
                        pos = 0;
                window_addnstr (win, str, pos);
                set_hilight_color (win);
                window_addnstr (win, str + pos, len);
                unset_hilight_color (win);
                maxlen -= pos + len;
        }

        return pos + len + window_addnstr (win, str + pos + len, maxlen - 1);
}


static void
draw_item (WINDOW *win, int maxlen, char *str, search_t *search)
{
        if (str_line == NULL)
                str_line = str_create ();
        
        if (win == box_select->win)
                wattrset (win, text_color);
        else
                wattrset (win, select_bar_color ());

        str_clear (str_line);
        if (str)
                eprintf_box_str (box_fmt, str, str_line);
        
        maxlen -= add_string (win, str_line->str, maxlen, search);
        while (maxlen-- > 0)
                window_addch (win, ' ');
}



static void
draw_line (WINDOW *win, int maxlen, int index, search_t *search)
{
        char *box = NULL;
        
        if (index == 0){
                draw_top (win, maxlen);
                return;
        }

        if (index <= true_items->count){
                box = true_items->array[index - 1];
                draw_tree (win, index == true_items->count);
        }

        draw_item (win, maxlen, box, search);
}



static int
match_box (search_t *search, int index)
{
        char *box;
        char *seek;
        
        if (index <= 0 || index > true_items->count)
                return 0;

        box  = true_items->array[index - 1];
        seek = strrchr (box, '/');

        if (seek == NULL)
                seek = box;
        else
                seek++;

        return search_perform (search, seek) != -1;
}



static int
count (select_t *nothing)
{
        if (true_items)
                return true_items->count + 1;
        return 0;
}


/* This file is generated by interface.pl script from interface.desc,
   and inc.in. */
static WINDOW *interface_init (void);
#include "box_selection.inc"


/****************************************************************************
 *    DISPLAY FUNCTIONS
 ****************************************************************************/

void
box_selection_init (void)
{
        WINDOW *window;
	
        true_items = mybox_subdirs ();
        if (true_items == NULL)
                return;

        window     = interface_init ();
        box_select = select_open (window, 0, draw_line, count);

        window_set_functions (window, box_selection_refresh,
                              box_selection_redraw, box_selection_set_focus,
                              box_selection_unset_focus);
        window_show (window);

        if (box_select && wrapbox_marray){
                goto_this_box (wrapbox_marray->path);
        }

        box_selection_redraw ();
}



void
box_selection_free_resources (void)
{
        if (box_select){
                select_close (box_select);
        }
        box_select = NULL;
        
        if (true_items)
                rstring_delete (true_items);
        true_items = NULL;

        if (label)
                label_destroy (label);
        label = NULL;

        if (str_line)
                str_destroy (str_line);
        str_line = NULL;
}



void
box_selection_redraw (void)
{
        PREAMBLE;

        select_redraw (box_select);
	label_redraw (label);
}



void
box_selection_refresh (void)
{
        PREAMBLE;

	select_show (box_select);
        label_show (label);
}



void
box_selection_set_focus (void)
{
        PREAMBLE;

	label_set_focus (label);
        cmd_state_push (CMD_SELECT_BOX);

        box_selection_redraw ();
}



void
box_selection_unset_focus (void)
{
        PREAMBLE;

        label_unset_focus (label);
        label_redraw (label);
	cmd_state_pop ();
}

/****************************************************************************
 *    INTERFACE FUNCTIONS
 ****************************************************************************/

void
box_selection_next (void)
{
        PREAMBLE;
  
        select_next (box_select);
}



void
box_selection_prev (void)
{
        PREAMBLE;

        select_prev (box_select);
}



void
box_selection_next_page (void)
{
        PREAMBLE;
  
        select_next_page (box_select);
}



void
box_selection_prev_page (void)
{
        PREAMBLE;
  
        select_prev_page (box_select);
}



void
box_selection_first (void)
{
        PREAMBLE;
  
        select_first (box_select);
}



void
box_selection_last (void)
{
        PREAMBLE;
  
        select_last (box_select);
}



void
box_selection_hit (void)
{
        int   index;
        char *newbox;

        PREAMBLE;

        if (box_select->bar_pos == 0)
                return;
        
        folder_at_leave ();
        index  = box_select->bar_pos - 1;
        newbox = file_with_dir (mybox_dir, true_items->array[index]);

        mybox_switching_to (newbox);

        if (folder_read_box (newbox)){
                mybox_switching_to (wrapbox_marray->path);
                box_selection_re_read ();
        }

        box_selection_redraw ();
        box_selection_refresh ();

        xfree (newbox);
        interface_focus (1);
}



void
box_selection_re_read (void)
{
        PREAMBLE;
  
        if (true_items)
                rstring_delete (true_items);
  
        true_items = mybox_subdirs ();
        if (true_items == NULL)
                return;
}



void
box_selection_search_backward (void)
{
        select_search_setup_backward (box_select, match_box);
}


void
box_selection_search_forward (void)
{
        select_search_setup_forward (box_select, match_box);
}


/****************************************************************************
 *    INTERFACE CLASS BODIES
 ****************************************************************************/
/****************************************************************************
 *
 *    END MODULE box_selection.c
 *
 ****************************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1