/*
 * Copyright (c)2004 Cat's Eye Technologies.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 *   Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 *   Neither the name of Cat's Eye Technologies nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

/*
 * main.c
 * Main program for dfuife_curses.
 * $Id: main.c,v 1.2 2004/07/11 03:26:56 cpressey Exp $
 */

#include <ctype.h>
#include <curses.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <dfui/dfui.h>
#include <dfui/mem.h>

#ifdef DEBUG
#include <dfui/dump.h>
#endif

#include "curses_form.h"
#include "curses_widget.h"
#include "curses_bar.h"
#include "curses_util.h"
#include "curses_xlat.h"

/*** GLOBALS ***/

struct curses_bar *menubar, *statusbar;

/*** SIGNAL HANDLING ***/

#ifdef SIGNAL_HANDLING
volatile sig_atomic_t caught_signal;

void signal_handler(int signo)
{
	caught_signal = signo;
}

void
abort_frontend(struct dfui_connection *c)
{
	dfui_fe_abort(c);

	clear();
	refresh();
	endwin();
	exit(1);
}
#endif

struct dfui_response *
present_form(struct dfui_connection *c, struct dfui_form *f)
{
	struct dfui_response *r = NULL;
	struct curses_form *cf;
	struct curses_widget *cw;

	cf = curses_form_construct_from_dfui_form(f);
	curses_form_draw(cf);
	curses_form_refresh(cf);
	cw = curses_form_frob(cf);
#ifdef SIGNAL_HANDLING
	if (caught_signal) abort_frontend(c);
#endif
	r = response_construct_from_curses_form(f, cf, cw);
	curses_form_free(cf);
	curses_form_refresh(NULL);
	return(r);
}

void
usage(char **argv)
{
	fprintf(stderr, "Usage: %s "
	    "[-b backdrop] [-r rendezvous] [-t caps|npipe|tcp]\n",
	    argv[0]);
	exit(1);
}

/*
 * dfuife_curses
 * DFUI Curses frontend.
 */
int
main(int argc, char **argv)
{
	struct dfui_connection *c;
	struct dfui_form *f;
	struct dfui_response *r;
	struct dfui_progress *pr;

	struct curses_form *pf = NULL;
	struct curses_widget *pbar = NULL, *plab = NULL, *pcan = NULL;

	void *payload;
	int done = 0;
	char msgtype;
	int opt;
	int last_amount = 0;
	char last_message[80];
	int ch;
	char *bdropfn = NULL;
	char *rendezvous = NULL;
	int transport = DFUI_TRANSPORT_TCP;

	/*
	 * Get command-line arguments.
	 */
	while ((opt = getopt(argc, argv, "b:r:t:")) != -1) {
		switch(opt) {
		case 'b':
			bdropfn = dfui_strdup(optarg);
			break;
		case 'r':
			rendezvous = dfui_strdup(optarg);
			break;
		case 't':
			if (strcmp(optarg, "npipe") == 0) {
				transport = DFUI_TRANSPORT_NPIPE;
			} else if (strcmp(optarg, "caps") == 0) {
				transport = DFUI_TRANSPORT_CAPS;
			} else if (strcmp(optarg, "tcp") == 0) {
				transport = DFUI_TRANSPORT_TCP;
			} else {
				usage(argv);
			}
			break;
		case '?':
		default:
			usage(argv);
		}
	}
	argc -= optind;
	argv += optind;

	if (rendezvous == NULL) {
		if (transport == DFUI_TRANSPORT_TCP) {
			rendezvous = dfui_strdup("9999");
		} else {
			rendezvous = dfui_strdup("test");
		}
	}

	/*
	 * Set up screen.
	 */

	initscr();

#ifdef SIGNAL_HANDLING
	signal(SIGINT, signal_handler);
	signal(SIGTERM, signal_handler);
#endif

	curses_colors_init();
	cbreak();
	noecho();
	nonl();
	keypad(stdscr, TRUE);
	curs_set(0);

	getmaxyx(stdscr, ymax, xmax);

	if (bdropfn == NULL) {
		curses_colors_set(stdscr, CURSES_COLORS_BACKDROP);
		curses_window_blank(stdscr);
	} else {
		curses_load_backdrop(stdscr, bdropfn);
	}

	menubar = curses_bar_new(0, 0, -1, 1, CURSES_COLORS_MENUBAR);
	statusbar = curses_bar_new(0, -1, -1, 1, CURSES_COLORS_STATUSBAR);

	curses_bar_set_text(menubar, "F1=Help F10=Refresh Display");
	curses_bar_set_text(statusbar, "Waiting for backend...");

	update_panels();
	doupdate();

#ifdef DEBUG
	dfui_debug_file = fopen("/tmp/dfuife_curses_debug.log", "w");
#endif

	c = dfui_connection_new(transport, rendezvous);
	dfui_fe_connect(c);

	curses_bar_set_text(statusbar, "Connected");

	while (!done) {
		dfui_fe_receive(c, &msgtype, &payload);
		switch (msgtype) {
		case DFUI_BE_MSG_PRESENT:
			f = (struct dfui_form *)payload;
			r = present_form(c, f);
#ifdef SIGNAL_HANDLING
			if (caught_signal) abort_frontend(c);
#endif
			dfui_fe_submit(c, r);
			dfui_form_free(f);
			dfui_response_free(r);
			break;
		case DFUI_BE_MSG_PROG_BEGIN:
			pr = (struct dfui_progress *)payload;
			if (pf != NULL)
				curses_form_free(pf);
			last_amount = dfui_progress_get_amount(pr);
			strncpy(last_message, dfui_info_get_short_desc(
			    dfui_progress_get_info(pr)), 79);
			pf = curses_form_construct_from_dfui_progress(pr,
			    &pbar, &plab, &pcan);
			curses_form_draw(pf);
			curses_form_refresh(pf);
			dfui_progress_free(pr);
			nodelay(stdscr, TRUE);
			dfui_fe_progress_continue(c);
			break;
		case DFUI_BE_MSG_PROG_UPDATE:
			pr = (struct dfui_progress *)payload;
			if (pf != NULL) {
				curses_widgets_update_from_dfui_progress(pr,
				    pbar, plab, pcan);
			}
			dfui_progress_free(pr);
			ch = getch();
			if (ch == ' ' || ch == '\n' || ch == '\r') {
				dfui_fe_progress_cancel(c);
			} else if (ch == KEY_F(10)) {
				redrawwin(stdscr);
				curses_form_refresh(NULL);
				dfui_fe_progress_continue(c);
			} else {
				dfui_fe_progress_continue(c);
			}
			break;
		case DFUI_BE_MSG_PROG_END:
			if (pf != NULL) {
				curses_form_free(pf);
				curses_form_refresh(NULL);
			}
			pf = NULL;
			plab = pbar = pcan = NULL;
			nodelay(stdscr, FALSE);
			dfui_fe_progress_continue(c);
			break;
		case DFUI_BE_MSG_STOP:
			dfui_fe_confirm_stop(c);
			done = 1;
			break;
		}
	}

	dfui_fe_disconnect(c);

#ifdef DEBUG
	fclose(dfui_debug_file);
#endif

	curses_bar_free(menubar);
	curses_bar_free(statusbar);

	clear();
	refresh();
	endwin();

	if (rendezvous != NULL)
		free(rendezvous);
	if (bdropfn != NULL)
		free(bdropfn);

	exit(0);
}
