/******************************************************************************
*   This file is part of TinTin++                                             *
*                                                                             *
*   Copyright 2004-2019 Igor van den Hoven                                    *
*                                                                             *
*   TinTin++ 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 3 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
******************************************************************************/

/******************************************************************************
*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
*                                                                             *
*                          coded by Bill Reiss 1993                           *
*                     recoded by Igor van den Hoven 2004                      *
******************************************************************************/

#include "tintin.h"

DO_COMMAND(do_split)
{
	int input;

	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);

	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
	{
		show_error(ses, LIST_COMMAND, "#SYNTAX: #SPLIT [TOP BAR] [BOTTOM BAR] [LEFT BAR] [RIGHT BAR] [INPUT BAR]");

		return ses;
	}

	ses->split->sav_top_row = *arg1 ? get_number(ses, arg1) : 0;
	ses->split->sav_bot_row = *arg2 ? get_number(ses, arg2) : 1;

	if (*arg == 0)
	{
		ses->split->sav_top_col = 0;
		ses->split->sav_bot_col = 0;
	}
	else
	{
		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
		arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);

		if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
		{
			show_error(ses, LIST_COMMAND, "#SYNTAX: #SPLIT [TOP BAR] [BOTTOM BAR] [LEFT BAR] [RIGHT BAR] [INPUT BAR]");

			return ses;
		}

		ses->split->sav_top_col = *arg1 ? get_number(ses, arg1) : 1;
		ses->split->sav_bot_col = *arg2 ? get_number(ses, arg2) : 0;
	}

	if (*arg)
	{
		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
		
		input = get_number(ses, arg1);

		input *= -1;
	}
	else
	{
		input = -1;
	}

	init_input(ses, input, 1, -1, -1);

	ses->split->sav_bot_row += inputline_rows(ses) - 1;

	DEL_BIT(ses->flags, SES_FLAG_SCROLLSPLIT);
	SET_BIT(ses->flags, SES_FLAG_SPLIT);

	ses->input->str_off = 1;

	init_split(ses, ses->split->sav_top_row, ses->split->sav_top_col, ses->split->sav_bot_row, ses->split->sav_bot_col);

	return ses;
}


DO_COMMAND(do_unsplit)
{
	memset(ses->split, 0, sizeof(struct split_data));

	ses->wrap = gtd->screen->cols;

	reset_screen(ses);

	SET_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE);

	if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
	{
		if (HAS_BIT(ses->telopts, TELOPT_FLAG_NAWS))
		{
			client_send_sb_naws(ses, 0, NULL);
		}
		DEL_BIT(ses->flags, SES_FLAG_SPLIT);
		DEL_BIT(ses->flags, SES_FLAG_SCROLLSPLIT);
	}
	check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN UNSPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
	return ses;
}

void init_split(struct session *ses, int top_row, int top_col, int bot_row, int bot_col)
{
	push_call("init_split(%p,%d,%d,%d,%d)",ses,top_row,top_col,bot_row,bot_col);

	SET_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE);

	init_input(ses, ses->input->sav_top_row, ses->input->sav_top_col, ses->input->sav_bot_row, ses->input->sav_bot_col);

	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
	{
		ses->split->top_row = 1;
		ses->split->top_col = 1;
		ses->split->bot_row = gtd->screen->rows;
		ses->split->bot_col = gtd->screen->cols;
		ses->wrap = gtd->screen->cols;

		init_pos(ses, gtd->screen->rows, 1);

		if (ses->map && HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
		{
			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
		}

		pop_call();
		return;
	}

	if (HAS_BIT(ses->flags, SES_FLAG_SCROLLSPLIT))
	{
		ses->split->top_row = top_row > 0 ? top_row : top_row < 0 ? gtd->screen->rows + top_row + 1 : 1;
		ses->split->top_col = top_col > 0 ? top_col : top_col < 0 ? gtd->screen->cols + top_col + 1 : 1;
		ses->split->bot_row = bot_row > 0 ? bot_row : bot_row < 0 ? gtd->screen->rows + bot_row + 1 : gtd->screen->rows - 2;
		ses->split->bot_col = bot_col > 0 ? bot_col : bot_col < 0 ? gtd->screen->cols + bot_col + 1 : gtd->screen->cols;
	}
	else
	{
		ses->split->top_row = top_row > 0 ? top_row + 1 : top_row < 0 ? gtd->screen->rows + top_row + 1 : 1;
		ses->split->top_col = top_col > 0 ? top_col + 1 : top_col < 0 ? gtd->screen->cols + top_col + 1 : 1;
		ses->split->bot_row = bot_row > 0 ? gtd->screen->rows - bot_row - 1 : bot_row < 0 ? bot_row * -1 : gtd->screen->rows - 1;
		ses->split->bot_col = bot_col > 0 ? gtd->screen->cols - bot_col : bot_col < 0 ? bot_col * -1 : gtd->screen->cols;
	}

	ses->split->top_row = URANGE(1, ses->split->top_row, gtd->screen->rows -3);
	ses->split->top_col = URANGE(1, ses->split->top_col, gtd->screen->cols - 2);
	ses->split->bot_row = URANGE(ses->split->top_row + 1,  ses->split->bot_row, gtd->screen->rows - 1);
	ses->split->bot_col = URANGE(ses->split->top_col + 1, ses->split->bot_col, gtd->screen->cols);
/*
	ses->split->sav_top_row = ses->split->top_row - 1;
	ses->split->sav_top_col = ses->split->top_col - 1;
	ses->split->sav_bot_row = gtd->screen->rows - ses->split->bot_row - 1;
	ses->split->sav_bot_col = gtd->screen->cols - ses->split->bot_col;
*/
	ses->wrap = ses->split->bot_col - (ses->split->top_col - 1);

	scroll_region(ses, ses->split->top_row, ses->split->bot_row);

	init_pos(ses, ses->input->top_row, ses->input->top_col);

	if (HAS_BIT(ses->telopts, TELOPT_FLAG_NAWS))
	{
		SET_BIT(ses->telopts, TELOPT_FLAG_UPDATENAWS);
	}

	if (ses->map && HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
	{
		SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
	}

	check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN SPLIT FILL", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col), ntos(ses->split->sav_top_row), ntos(ses->split->sav_bot_row), ntos(ses->split->sav_top_col), ntos(ses->split->sav_bot_col));

	if (!check_all_events(ses, EVENT_FLAG_CATCH, 0, 8, "CATCH SCREEN SPLIT FILL", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col), ntos(ses->split->sav_top_row), ntos(ses->split->sav_bot_row), ntos(ses->split->sav_top_col), ntos(ses->split->sav_bot_col)))
	{
		if (ses == gtd->ses && !HAS_BIT(ses->flags, SES_FLAG_SCROLLSPLIT))
		{
			if (HAS_BIT(ses->config_flags, CONFIG_FLAG_VERBOSE) || gtd->level->verbose || gtd->level->quiet == 0)
			{
				command(ses, do_screen, "FILL DEFAULT");

			}
		}

	}

	if (HAS_BIT(ses->flags, SES_FLAG_READMUD))
	{
		goto_pos(ses, ses->split->bot_row, 1);
	}

	check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN SPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));

	pop_call();
	return;
}


/*
	unsplit
*/

void reset_screen(struct session *ses)
{
	reset_scroll_region(ses);

	init_pos(ses, gtd->screen->rows, 1);
}


/*
	refresh
*/

void dirty_screen(struct session *ses)
{
	push_call("dirty_screen(%p)",ses);

	refresh_session_terminal(ses);

	print_stdout(0, 0, "\e=");

	if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
	{
		init_split(ses, ses->split->sav_top_row, ses->split->sav_top_col, ses->split->sav_bot_row, ses->split->sav_bot_col);

		init_input(ses, ses->input->sav_top_row, ses->input->sav_top_col, ses->input->sav_bot_row, ses->input->sav_bot_col);
	}
	else if (IS_SPLIT(ses))
	{
		scroll_region(ses, ses->split->top_row, ses->split->bot_row);
	}
	else
	{
		reset_screen(ses);
	}

	if (IS_SPLIT(ses) && ses == gtd->ses)
	{
		init_pos(ses, ses->input->top_row, ses->input->top_col);
		cursor_redraw_input(ses, "");
	}

	pop_call();
	return;
}


void split_show(struct session *ses, char *prompt, char *row_str, char *col_str)
{
	char buf1[BUFFER_SIZE];
	int row, col, width, clear;

	row = 0;

	if (*row_str)
	{
		row = get_row_index_arg(ses, row_str);
	}

	if (row == 0)
	{
		row = URANGE(1, ses->input->top_row - 1, gtd->screen->rows);
	}

	col = 0;

	if (*col_str)
	{
		col = get_col_index_arg(ses, col_str);
	}

	if (col == 0)
	{
		col = 1;
		clear = 1;
	}
	else
	{
		clear = 0;
	}

	if (row < 1 || row > gtd->screen->rows)
	{
		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS OUTSIDE THE SCREEN: {%s} {%s} {%s} [%d].", prompt, row_str, col_str, row);

		return;
	}

	if (col < 0 || col > gtd->screen->cols)
	{
		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT COLUMN IS OUTSIDE THE SCREEN: {%s} {%s} {%s} [%d].", prompt, row_str, col_str, col);

		return;
	}

	if (row > ses->input->top_row && inside_scroll_region(ses, row, col))
	{
		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS INSIDE THE SCROLLING REGION: {%s} {%s} [%d].", prompt, row_str, row);

		return;
	}

	if (ses != gtd->ses)
	{
		return;
	}

	strip_vt102_width(ses, prompt, &width);

	if (col - 1 + width <= gtd->screen->cols)
	{
		sprintf(buf1, "%s", prompt);
	}
	else
	{
		snprintf(buf1, BUFFER_SIZE, "%.*s", raw_len_str(ses, prompt, 0, gtd->screen->cols - col), prompt);

		show_debug(ses, LIST_PROMPT, NULL, "#DEBUG PROMPT {%s}", prompt);
		show_debug(ses, LIST_PROMPT, NULL, "#PROMPT WIDTH %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", width, col, gtd->screen->cols);
	}

	save_pos(ses);

	if (row == ses->input->top_row)
	{
		gtd->ses->input->str_off = width + 1;

		goto_pos(ses, row, col);

		print_stdout(0, 0, "%s%s", buf1, gtd->ses->input->buf);

		// bit of a hack

		gtd->screen->sav_col[0] = inputline_cur_col();
		gtd->screen->sav_row[0] = inputline_cur_row();
	}
	else
	{
		goto_pos(ses, row, col);

		if (clear)
		{
			erase_cols(gtd->screen->cols);
		}
	
		print_stdout(0, 0, "%s", buf1);
	}

	set_line_screen(ses, buf1, row, col);

	restore_pos(ses);
}
