/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 2002 bazyl
   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.  

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

   This module creates special window with date and time.
   It's also using special structure to show elmo's work like downloading or
   sending mails.
   
*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#include <stdarg.h>
#include <time.h>
#include <unistd.h>

#include "clock.h"
#include "ecurses.h"
#include "ask.h"
#include "color.h"
#include "interface.h"
#include "cmd.h"
#include "xmalloc.h"
#include "str.h"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/

struct job_list {
        struct job_list *next;
        str_t           *desc;
        int              max;
        int              old;
        int              cur;
        int              index;
};

/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/

/* Clock window. */
static WINDOW *clock_win = NULL;

/* Color of the text displayed in the clock window. */
static chtype text_color;

/* Format string that controls, how is the time displayed. */
static char *clock_fmt = "   %H:%M  %a, %e %b ";

/* List of jobs to be displayed with progresses. */
static struct job_list *job_list = NULL;

/* This is used to disable clock. */
static int pause_me = 0;

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

static void
draw_job (struct job_list *job, int y)
{
        int height, width;
        int cnt;

        getmaxyx (clock_win, height, width);

        if (y + 1 >= height)
                return;

        window_mvaddnstr (clock_win, y, 0, job->desc->str, width);
        
        cnt    = job->cur * width / job->max;
        width -= cnt;

        wmove (clock_win, y + 1, 0);
        while (cnt--)
                window_addch (clock_win, '#');
        while (width--)
                window_addch (clock_win, ' ');
}



static void
draw_jobs (struct job_list *list, int y)
{
        if (list == NULL)
                return;

        draw_job (list, y);
        draw_jobs (list->next, y + 2);
}



static void
display_jobs (void)
{
        int height, width;
        int i;

        if (pause_me)
                return;
        
        getmaxyx (clock_win, height, width);

        for (i = 1; i < height; i++){
                wmove (clock_win, i, 0);
                wclrtoeol (clock_win);
        }
        draw_jobs (job_list, 1);
}



static void
display_time (void)
{
        static char   buf[50];
        static time_t oldtime = 0;
        time_t        curtime;
        struct tm    *tm;
        int           width, nothing;
        cmd_state_t   state = cmd_state_get (0);

        if (state == CMD_READ_MAIL || state == CMD_HELP
            || state == CMD_ATTACH || state == CMD_SENDER
            || state == CMD_ABOOK_ADD)
                return;
        
        curtime = time (NULL);
        
        if (curtime == oldtime)
                return;

        tm      = localtime (& curtime);
        oldtime = curtime;

        getmaxyx (clock_win, nothing, width);
        
        strftime (buf, sizeof (buf) - 1, clock_fmt, tm);
        width -= window_mvaddnstr (clock_win, 0, 0, buf, width);

        while (width--){
                window_addch (clock_win, ' ');
        }
}



static void
clock_hook (int nothing)
{
        display_time ();
        wnoutrefresh (clock_win);
}



static void
destroy_list (struct job_list *list)
{
        if (list == NULL)
                return;

        destroy_list (list->next);
        xfree (list);
}



static struct job_list *
list_find_index (struct job_list *list, int index)
{
        if (list == NULL)
                return NULL;

        if (list->index == index)
                return list;

        return list_find_index (list->next, index);
}



static struct job_list *
list_remove_index (struct job_list *list, int index)
{
        struct job_list *next;
        
        if (list == NULL)
                return NULL;

        if (list->index == index){
                next = list->next;
                if (list->desc)
                        str_destroy (list->desc);
                xfree (list);
                return next;
        }

        list->next = list_remove_index (list->next, index);
        return list;
}


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

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

void
clock_init (void)
{
        clock_win = interface_init ();
        cmd_add_timeout_handler (clock_hook);
}



void
clock_free_resources (void)
{
        destroy_list (job_list);
}



void
clock_pause (void)
{
        pause_me = 1;
}



void
clock_resume (void)
{
        pause_me = 0;
}



int
progress_setup (int max, const char *desc, ...)
{
        va_list          ap;
        struct job_list *list;
        
        if (max < 1)
                return -1;

        list        = xmalloc (sizeof (struct job_list));
        list->max   = max;
        list->old   = 0;
        list->cur   = 0;
        list->index = (job_list) ? job_list->index + 1 : 0;
        list->next  = job_list;
        list->desc  = str_create ();

        va_start (ap, desc);
        str_vsprintf (list->desc, desc, ap);
        va_end (ap);
        
        job_list    = list;

        display_jobs ();
        wnoutrefresh (clock_win);
        doupdate ();
        return list->index;
}



void
progress_advance (int index, int count)
{
        struct job_list *list = list_find_index (job_list, index);

        if (list == NULL)
                return;
        
        list->cur += count;
        if (list->cur > list->max)
                list->cur = list->max;

        display_jobs ();
        wnoutrefresh (clock_win);
        doupdate ();
}



void
progress_close (int index)
{
        job_list = list_remove_index (job_list, index);

        display_jobs ();
        wnoutrefresh (clock_win);
        doupdate ();
}



void
progress_change_desc (int index, const char *desc, ...)
{
        va_list          ap;
        struct job_list *list = list_find_index (job_list, index);

        if (list == NULL)
                return;

        if (list->desc)
                str_clear (list->desc);
        else
                list->desc = str_create ();

        va_start (ap, desc);
        str_vsprintf (list->desc, desc, ap);
        va_end (ap);

        display_jobs ();
        wnoutrefresh (clock_win);
        doupdate ();
}


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


syntax highlighted by Code2HTML, v. 0.9.1