/*
 *  Copyright (C) 2006-2019, Thomas Maier-Komor
 *
 *  This is the source code of xjobs.
 *
 *  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, see <http://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "config.h"

#ifdef HAVE_CURSES_H
#include <curses.h>
#ifdef __sun		// term.h cannot be found on solaris by autoconf
#include <term.h>	// and requires curses.h as a prerequisite
#endif
#ifndef HAVE_TERMINFO
#define HAVE_TERMINFO
#endif
#endif

#define TPARM_VARARGS

#ifdef HAVE_TERM_H
#include <term.h>
#ifndef HAVE_TERMINFO
#define HAVE_TERMINFO
#endif
#endif

#ifdef HAVE_NCURSES_H
#include <ncurses.h>
#ifndef HAVE_TERMINFO
#define HAVE_TERMINFO
#endif
#endif

#ifndef ERR
#define ERR -1
#endif

#include "colortty.h"
#include "log.h"
#include "support.h"

ttymode_t TtyMode = tty_auto;

int HaveTty = 0;

color_t
	ColorStart = cyan,
	ColorDebug = noattr,
	ColorInfo = noattr,
	ColorWarn = yellow,
	ColorError = red,
	ColorFail = red,
	ColorDone = blue,
	ColorOut = noattr;

char *PfxStart = "", *PfxDone = "", *PfxFail = "", *PfxWarn = "", *PfxError = ""
	, *PfxOut = "", *PfxInfo = 0, *PfxDebug = 0;

const char *TiSave = "", *TiRestore = "", *TiClrEol = "", *TiNoAttr = "",
	*TiBlack = "", *TiBlue = "", *TiCyan = "", *TiGreen = "", *TiGrey = "",
	*TiMagenta = "", *TiRed = "", *TiWhite = "", *TiYellow = "";

unsigned TiClrEolL = 0, TiNoAttrL = 0;
int PgPid = 0;


static void init_tty_none()
{
	TiBlack = "";
	TiBlue = "";
	TiCyan = "";
	TiGreen = "";
	TiGrey = "";
	TiMagenta = "";
	TiRed = "";
	TiWhite = "";
	TiYellow = "";
	TiClrEol = "";
	TiClrEolL = 0;
	TiNoAttr = "";
	TiNoAttrL = 0;
	TiSave = "";
	TiRestore = "";
}


static void init_tty_ansi()
{
	/* background: black */
	TiBlack = "\033[30m";
	TiBlue = "\033[34m";
	TiCyan = "\033[36m";
	TiGreen = "\033[32m";
	TiGrey = "\033[90m";
	TiMagenta = "\033[35m";
	TiRed = "\033[31m";
	TiWhite = "\033[37m";
	TiYellow = "\033[33m";
	TiClrEol = "\033[K";
	TiClrEolL = strlen(TiClrEol);
	TiNoAttr = "\033[0m";
	TiNoAttrL = strlen(TiNoAttr);
	TiSave = "\033[s";
	TiRestore = "\033[r";
}


const char *colorstr(color_t c)
{
	switch (c) {
	case black:
		return TiBlack;
	case blue:
		return TiBlue;
	case cyan:
		return TiCyan;
	case green:
		return TiGreen;
	case magenta:
		return TiMagenta;
	case red:
		return TiRed;
	case white:
		return TiWhite;
	case yellow:
		return TiYellow;
	case noattr:
		return TiNoAttr;
	default:
		abort();
	}
	return 0;
}


color_t str2color(const char *str)
{
	if (0 == strcasecmp(str,"blue"))
		return blue;
	if (0 == strcasecmp(str,"black"))
		return black;
	if (0 == strcasecmp(str,"cyan"))
		return cyan;
	if (0 == strcasecmp(str,"green"))
		return green;
	if (0 == strcasecmp(str,"magenta"))
		return magenta;
	if (0 == strcasecmp(str,"red"))
		return red;
	if (0 == strcasecmp(str,"white"))
		return white;
	if (0 == strcasecmp(str,"yellow"))
		return yellow;
	if (0 == strcasecmp(str,"none"))
		return noattr;
	if (0 == strcasecmp(str,"default"))
		return noattr;
	return invalid_color;
}


static int init_pager()
{
	char *pager = getenv("PAGER");
	if (pager == 0) {
		dbug("pager not set");
		return 0;
	}
	char *pgexe = complete_exe(pager);
	if (0 == pgexe) {
		dbug("pager not found");
		return 0;
	}
	info("starting pager %s\n",pgexe);
	int p[2];
	if (pipe(p)) {
		warn("unable to create pipe for pager: %s\n",strerror(errno));
		return 0;
	}
	PgPid = fork();
	if (PgPid) {
		if (PgPid == -1) {
			warn("failed to fork pager: %s\n",strerror(errno));
			PgPid = 0;
			return 0;
		}
		dup2(p[1],STDERR_FILENO);
		dup2(p[1],STDOUT_FILENO);
		close(p[1]);
		close(p[0]);
		free(pgexe);
	} else {
		dup2(p[0],STDIN_FILENO);
		close(p[0]);
		close(p[1]);
		execl(pgexe,pgexe,NULL);
		_exit(EXIT_FAILURE);
	}
	return 1;
}


void init_terminal()
{
	int ispipe = 0;
	if (1 == isatty(STDOUT_FILENO)) {
		HaveTty = 1;
		dbug("stdout is a terminal\n");
	} else {
		dbug("stdout is not a terminal\n");
		struct stat st;
		int r = fstat(STDOUT_FILENO,&st);
		if (r == 0) {
			if (S_ISFIFO(st.st_mode)) {
				dbug("stdout is a pipe\n");
				ispipe = 1;
			}
		} else {
			warn("unable to stat output: %s\n",strerror(errno));
		}
	}
	dbug("tty mode %d\n",TtyMode);
	switch (TtyMode) {
	case tty_none:
	case tty_ansi:
		break;
	case tty_pipe:
		if (ispipe == 1)
			TtyMode = tty_ansi;
		else if (HaveTty == 1)
			TtyMode = tty_auto;
		else
			TtyMode = tty_none;
		break;
	case tty_auto:
		if (ispipe == 1)
			TtyMode = tty_ansi;
		else if (HaveTty == 0)
			TtyMode = tty_none;
		break;
	default:
		assert(0);
	}
	if (HaveTty && init_pager())
		TtyMode = tty_ansi;
	if (TtyMode == tty_none) {
		dbug("tty mode resolved to none - disabling color&status support\n");
		init_tty_none();
		return;
	}
	if (TtyMode == tty_ansi) {
		dbug("setting up for ansi terminal\n");
		init_tty_ansi();
	}
	if ((TtyMode == tty_auto) || (TtyMode == tty_pipe)) {
#ifdef HAVE_TERMINFO
		char *ts;
		int err = 0;
		if (ERR == setupterm(0,STDOUT_FILENO,&err))
			return;
		switch (err) {
		case 1:
			dbug("terminal setup ok\n");
			break;
		case 0:
			dbug("no terminal - disabling color\n");
			break;
		case -1:
		default:
			warn("unable to load terminal database - disabling color\n");
		}
		ts = tigetstr("sc");
		if ((ts != 0) && (ts != (char *)-1))
			TiSave = ts;
		ts = tigetstr("rc");
		if ((ts != 0) && (ts != (char *)-1))
			TiRestore = ts;
		ts = tigetstr("el");
		if ((ts != 0) && (ts != (char *)-1))
			TiClrEol = ts;
		TiClrEolL = strlen(TiClrEol);
		ts = tigetstr("sgr0");
		if ((ts != 0) && (ts != (char *)-1)) {
			TiNoAttr = ts;
			TiNoAttrL = strlen(TiNoAttr);
		}
		char *setaf = tigetstr("setaf");
		char *setf = tigetstr("setf");
		if (setaf && (setaf != (const char *)-1)) {
			/* ANSI terminal capabilities */
			dbug("initializing terminal with ANSI capabilities\n");
			TiBlack = Strdup(tparm(setaf,0/*BLACK*/));
			TiRed = Strdup(tparm(setaf,1/*RED*/));
			TiGreen = Strdup(tparm(setaf,2/*GREEN*/));
			TiYellow = Strdup(tparm(setaf,3/*YELLOW*/));
			TiBlue = Strdup(tparm(setaf,4/*BLUE*/));
			TiMagenta = Strdup(tparm(setaf,5/*MAGENTA*/));
			TiCyan = Strdup(tparm(setaf,6/*CYAN*/));
			TiWhite = Strdup(tparm(setaf,7/*WHITE*/));
		} else if (setf && (setf != (const char *)-1)) {
			/* NON-ANSI terminal capabilities */
			dbug("initializing terminal with non-ANSI capabilities\n");
			TiBlack = Strdup(tparm(setaf,0/*BLACK*/));
			TiBlue = Strdup(tparm(setf,1/*BLUE*/));
			TiGreen = Strdup(tparm(setf,2/*GREEN*/));
			TiCyan = Strdup(tparm(setf,3/*CYAN*/));
			TiRed = Strdup(tparm(setf,4/*RED*/));
			TiMagenta = Strdup(tparm(setf,5/*MAGENTA*/));
			TiYellow = Strdup(tparm(setf,6/*YELLOW*/));
			TiWhite = Strdup(tparm(setf,7/*WHITE*/));
		}
#else
		dbug("terminfo is missing - disabling color&status support\n");
		init_tty_none();
#endif
	}
	
	PfxDebug = concatstr(TiClrEol,colorstr(ColorDebug));
	PfxInfo = concatstr(TiClrEol,colorstr(ColorInfo));
	PfxWarn = makestr("%s%swarning: ",TiClrEol,colorstr(ColorWarn));
	PfxStart = concatstr(TiClrEol,colorstr(ColorStart));
	PfxOut = concatstr(TiClrEol,colorstr(ColorOut));
	PfxError = concatstr(TiClrEol,colorstr(ColorError));
	PfxFail = concatstr(TiClrEol,colorstr(ColorFail));
	PfxDone = concatstr(TiClrEol,colorstr(ColorDone));
}


