/*
 * Copyright (c) 2003, Daniel Bryan
 * 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 the author 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 OWNER 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.
 *
 */

#include <string.h>
#include <sys/time.h>

#include "common.h"
#include "screen.h"
#include "misc.h"
#include "path.h"
#include "color.h"

int winw,winh,mainww;
int mainwsbw; /* width of status bar */
int eosi = 0; /* end of speed indicator */

/* create windows, draw border and title */
void scrn_draw() {
	int dev_null;
	if(scrn_border) {
		wborder(stdscr,0,0,0,0,0,0,0,0);
		mvwhline(stdscr,10,1,0,winw-2);
		wmove(stdscr,10,0);
		waddch(stdscr,ACS_LTEE);
		wmove(stdscr,10,winw-1);
		waddch(stdscr,ACS_RTEE);
	}
	mainw = newwin(8,winw-2,1,1);
	logw = newwin(winh-12,winw-2,11,1);
	overwrite(mainw, stdscr);
	overwrite(logw, stdscr);

	nonl();
	cbreak();
	noecho();
	refresh();
	nodelay(mainw, TRUE);
	keypad(mainw, TRUE);
	keypad(logw, TRUE);
	scrollok(logw, TRUE);
	getmaxyx(mainw, dev_null, mainww);
	mainwsbw = mainww - 2;

	wmove(stdscr,0,(winw/2)-6);
	coloron(stdscr);	
	waddch(stdscr,'[');
	coloroff(stdscr);
	wprintw(stdscr," vcp %d.%d ",VER_MAJ,VER_MIN);	
	coloron(stdscr);	
	waddch(stdscr,']');
	coloroff(stdscr);
	
	curs_set(0);
	refresh();	
	return;
}

/* check to see if the window has been re-sized */
int scrn_check() {
	int rwinh, rwinw;
	if(!use_curses)
		return 0;
	
	getmaxyx(stdscr, rwinh, rwinw);
	if(rwinh != winh || rwinw != winw) {
		winw = rwinw;
		winh = rwinh;
		/* TODO: check for valid screen size */
		delwin(mainw);
		delwin(logw);
		clear();
		scrn_draw();
		getmaxyx(mainw,rwinw,mainww);
		refresh();
		mainwsbw = mainww - 2;
		scrn_updatefc(0);
		wrefresh(mainw);
		return 1;
	} else {
		return 0;
	}
}

void scrn_init() {

	if(tflag) {
		use_curses = 0;
		return;
	}
	
	initscr();
	getmaxyx(stdscr, winh, winw);
	if(winh < 11 || winw < 20) {
		endwin();
		use_curses = 0;
		logadds(LOG_ERR,"Screen size too small, text output",NULL,NULL);
		return;
	}

	use_curses = 1;
		
	if(has_colors() != TRUE)
		use_color = 0;
	if(use_color > 0) {
		start_color();
		use_default_colors();
		if(use_color == BLACK || use_color == BLACK2)
			init_pair(1, COLOR_BLACK,   -1);
		else if(use_color == RED || use_color == RED2)
			init_pair(1, COLOR_RED,     -1);
		else if(use_color == GREEN || use_color == GREEN2)	
			init_pair(1, COLOR_GREEN,   -1);
		else if(use_color == YELLOW || use_color == YELLOW2)
			init_pair(1, COLOR_YELLOW,  -1);
		else if(use_color == BLUE || use_color == BLUE2)
			init_pair(1, COLOR_BLUE,    -1);
		else if(use_color == MAGENTA || use_color == MAGENTA2)	
			init_pair(1, COLOR_MAGENTA, -1);
		else if(use_color == CYAN || use_color == CYAN2)
			init_pair(1, COLOR_CYAN,    -1);
		else if(use_color == WHITE || use_color == WHITE2)
			init_pair(1, COLOR_WHITE,   -1);
	}

	scrn_draw();
	
	refresh();
	return;
}

/* TODO: slow the update speed */
/* update screen in non-curses output */
void scrn_updtxt(unsigned long sizecpd,unsigned long size,int lastl) {
	int x = 0;
	int xo = 0;
	static int maxline = 0;
	
	struct timeval now;
	static struct timeval last;
	static unsigned long speed = 0;
	static unsigned long sizelast = 0;
	struct size_foo sizecpds;
	struct speed_foo speeds;
	
	if(!vflag)
		return;
	
	if(sizecpd > 0) {
		x = (float)sizecpd / (float)size * 40;
		xo = 40 - x;
	} else {
		x = 0;
		xo = 40;
	}
	
	if(lastl) {
		/* clear line */
		fprintf(stderr,"\r");
		x = maxline + 41;
		while(x > 0) {
			fprintf(stderr," ");
			x--;
		}
		fprintf(stderr,"\r");
		maxline = 0;
		return;
	}

	fprintf(stderr,"\r[");
	while(x > 0) {
		fprintf(stderr,"=");
		x--;
	}
	while(xo > 0) {
		fprintf(stderr," ");
		xo--;
	}
	
	gettimeofday(&now,NULL);
	if(sizelast > sizecpd)
		sizelast = 0;
		
	if((now.tv_sec - last.tv_sec) > 1) {
		speed = (float)(sizecpd - sizelast) / \
			(float)(now.tv_sec - last.tv_sec);
		gettimeofday(&last,NULL);
		sizelast = sizecpd;
	}
	whatsize(sizecpd,&sizecpds);
	whatspeed(speed,&speeds);
	
	x += fprintf(stderr,"] %lu %s ",sizecpds.size,sizecpds.c);
	x += fprintf(stderr,"(%1.1f %s/s)    \b\b\b\b",speeds.size,speeds.c);
	
	if(x > maxline)
		maxline = x;
	
	fflush(stderr);
	return;
}

/* update file speed, size copied(& to be), status bar(s) */
void scrn_updatepart(unsigned long sizecpd,unsigned long size) {
	struct timeval now;
	static struct timeval last;
	static unsigned long sizelast = 0;
	static unsigned long speed = 0;
	struct speed_foo speeds;
	struct size_foo sizecpds;
	struct size_foo sizes;
	int dev_null;
	unsigned long timer;
	
	if(!use_curses)
		return;

	if(sizecpd > size)
		return;
	
	gettimeofday(&now,NULL);
	scrn_check();
	
	if(sizelast > sizecpd)
		sizelast = 0;
	
	if((now.tv_sec - last.tv_sec) > 1) {
		speed = (float)(sizecpd - sizelast) / (float)(now.tv_sec - last.tv_sec);
		gettimeofday(&last,NULL);
		sizelast = sizecpd;
	}
	whatspeed(speed,&speeds);
		
	wmove(mainw,4,0);
	
	wprintw(mainw,"%1.1f %s",speeds.size,speeds.c);
	
	coloron(mainw);
	waddch(mainw,'/');
	coloroff(mainw);
	waddch(mainw,'s');
	getyx(mainw,dev_null,eosi);

	wmove(mainw,3,0);
	if(size - sizecpd > 0 && speed > 0) {
		timer = (size - sizecpd) / (int)speed;
		if(timer > 3600) {
			wprintw(mainw,"%d",timer / 3600);
			coloron(mainw);
			wprintw(mainw,"h ");
			coloroff(mainw);
			timer -= ((timer / 3600) * 3600);
		}
		
		if(timer > 60) {
			wprintw(mainw,"%d",timer / 60);
			coloron(mainw);
			wprintw(mainw,"m ");
			coloroff(mainw);			
			timer -= ((timer / 60) * 60);
		}
		wprintw(mainw,"%d",timer);
		coloron(mainw);
		wprintw(mainw,"s ");
		coloroff(mainw);
		wprintw(mainw,"ETR"); wclrtoeol(mainw);
	}
	
	wmove(mainw,4,eosi); wclrtoeol(mainw);
	wmove(mainw,4,mainww - 3 - whatsize(sizecpd,&sizecpds) - \
		whatsize(size,&sizes));
	
	wprintw(mainw,"%lu %s ",sizecpds.size,sizecpds.c);
	coloron(mainw);
	wprintw(mainw,"/");
	coloroff(mainw);	
	wprintw(mainw," %lu %s",sizes.size,sizes.c);
	
	/* draw both status bars, looks better for only one file */
	if(totalfiles == 1) {
		scrn_setsb(7,(float)sizecpd / (float)size * (float)mainwsbw);
	}
	wmove(mainw,6,1); wclrtoeol(mainw);
	scrn_setsb(6,(float)sizecpd / (float)size * (float)mainwsbw);
	
	if(sizecpd > 0 && size > 0) {
		wmove(mainw,6,(mainwsbw / 2) - 2);
		wprintw(mainw," %2.0f%% ",(float)((float)sizecpd / (float)size * 100));
	}

	wrefresh(mainw);
	return;
}

void scrn_updatezero() {
	if(!use_curses)
		return;
	
	scrn_check();
		
	wmove(mainw,4,eosi); wclrtoeol(mainw);
	wmove(mainw,4,mainww - 9);
	wprintw(mainw,"0 B ");
	coloron(mainw);
	wprintw(mainw,"/");
	coloroff(mainw);
	wprintw(mainw," 0 B");
	
	if(totalfiles == 1)
		scrn_setsb(7,mainwsbw);
	wmove(mainw,6,1); wclrtoeol(mainw);
	scrn_setsb(6,mainwsbw);

	wrefresh(mainw);
	return;	
}

/* update files copied(& to be) */
void scrn_updatefc(int refreshw) {
	if(!use_curses)
		return;
	wmove(mainw,0,(mainww-3-countd(curfile)-countd(totalfiles)));
	wprintw(mainw, "%lu ",curfile);
	coloron(mainw);
	waddch(mainw, '/');
	coloroff(mainw);
	wprintw(mainw, " %lu",totalfiles);
	
	if(refreshw)
		wrefresh(mainw);
	return;
}

/* update file name, status bar */
void scrn_updatefile(char *src,char *dest) {
	if(!use_curses)
		return;
	
	scrn_check();
	
	scrn_updatefc(0);
	wmove(mainw,2,0); wclrtoeol(mainw);
	wmove(mainw,1,0); wclrtoeol(mainw);
	wmove(mainw,1,0);
	if(src != NULL) {
		if(dest != NULL) {
			if(strcmp(pathname(src),pathname(dest)) == 0)
				wprintw(mainw, "%s",pathname(src));
			else {
				wprintw(mainw, "%s ",pathname(src));
				coloron(mainw);
				wprintw(mainw, "->");
				coloroff(mainw);
				wprintw(mainw, " %s",pathname(dest));
			}
		} else
			wprintw(mainw, "%s",pathname(src));
	}
	wmove(mainw,4,0); wclrtoeol(mainw);
	wmove(mainw,5,0); wclrtoeol(mainw);
	wmove(mainw,6,0); wclrtoeol(mainw);
	wmove(mainw,7,0); wclrtoeol(mainw);
	scrn_setsb(6,0);
	
	if(totalfiles != 1) {
		scrn_setsb(7,(float)curfile/(float)totalfiles*(float)mainwsbw);
	} else {
		scrn_setsb(7,0);
	}
	
	if(totalfiles > 1 && curfile > 0) {
		wmove(mainw,7,(mainwsbw / 2) - 2);
		wprintw(mainw," %2.0f%% ", \
			(float)((float)curfile / (float)totalfiles * 100));
	}

	wrefresh(mainw);
	return;
}
/* set the status bar */
void scrn_setsb(int y, int x) {
	wmove(mainw,y,0);
	coloron(mainw);
	waddch(mainw,'[');
	coloroff(mainw);

	wattron(mainw,A_BOLD);
	while(x > 0) {
		waddch(mainw, '=');
		x--;
	}
	wattroff(mainw,A_BOLD);
	
	wmove(mainw,y,mainww-1);
	coloron(mainw);
	waddch(mainw,']');
	coloroff(mainw);
}
