/*	$NetBSD: console.c,v 1.7 2021/05/04 21:09:16 khorben Exp $	*/

/*
 * Copyright (c) 2017-2020 The NetBSD Foundation, Inc. All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Maxime Villard.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 "prekern.h"

extern vaddr_t atdevbase;
#define CONS_WID 80
#define CONS_HEI 25

static char *cons_start;
static size_t cons_x, cons_y;
static char cons_buffer[CONS_WID * 2 * CONS_HEI];

void init_cons(void)
{
	cons_start = (char *)atdevbase + (0xB8000 - IOM_BEGIN);
	cons_x = 0;
	cons_y = 0;
}

static void check_scroll(void)
{
	char *src, *dst;
	size_t i;

	if (cons_y != CONS_HEI)
		return;

	for (i = 0; i < CONS_HEI-1; i++) {
		dst = &cons_buffer[0] + i * (CONS_WID * 2);
		src = &cons_buffer[0] + (i + 1) * (CONS_WID * 2);
		memcpy(dst, src, (CONS_WID * 2));
	}
	memset(&cons_buffer[0] + (CONS_WID * 2) * (CONS_HEI-1), 0,
	    (CONS_WID * 2));
	cons_y--;
	memcpy(cons_start, &cons_buffer[0], CONS_WID * 2 * CONS_HEI);
}

static void putc(int color, char c)
{
	char *ptr, *scr;

	if (c == '\n') {
		cons_x = 0;
		cons_y++;
		check_scroll();
	} else {
		if (cons_x + 1 == CONS_WID) {
			cons_x = 0;
			cons_y++;
			check_scroll();
		}
		ptr = (cons_start + 2 * cons_x + 160 * cons_y);
		scr = (cons_buffer + 2 * cons_x + 160 * cons_y);
		ptr[0] = scr[0] = c;
		ptr[1] = scr[1] = color;
		cons_x++;
	}
}

void print_ext(int color, char *buf)
{
	size_t i;

	for (i = 0; buf[i] != '\0'; i++) {
		putc(color, buf[i]);
	}
}

void print(char *buf)
{
	print_ext(WHITE_ON_BLACK, buf);
}

void print_state(state_t state, char *buf)
{
	print("[");
	switch (state)
	{
		case STATE_NORMAL:
			print_ext(GREEN_ON_BLACK, "+");
			break;
		case STATE_ERROR:
			print_ext(RED_ON_BLACK, "!");
			break;
		case STATE_WARNING:
			print_ext(YELLOW_ON_BLACK, "*");
			break;
		default:
			print_ext(WHITE_ON_BLACK, "?");
			break;
	}
	print("] ");
	print(buf);
	print("\n");
}

void print_banner(void)
{
	char *banner =
		"           __________                 __                        \n"
		"           \\______   \\_______   ____ |  | __ ___________  ____  \n"
		"            |     ___/\\_  __ \\_/ __ \\|  |/ // __ \\_  __ \\/    \\ \n"
		"            |    |     |  | \\/\\  ___/|    <\\  ___/|  | \\/   |  \\\n"
		"            |____|     |__|    \\___  >__|_ \\\\___  >__|  |___|  /\n"
		"                                   \\/     \\/    \\/           \\/    Version 1.0\n"
	;
	print(banner);
}
