/*
 * remlet.c
 */

/*****************************************************************************
 * Copyright (C) 2005-2006  Remi Denis-Courmont.  All rights reserved.       *
 *                                                                           *
 * 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. Redistribution 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.   *
 *                                                                           *
 * The situation as regards scientific and technical know-how at the time    *
 * when this software was distributed did not enable all possible uses to be *
 * tested and verified, nor for the presence of any or all faults to be      *
 * detected. In this respect, people's attention is drawn to the risks       *
 * associated with loading, using, modifying and/or developing and           *
 * reproducing this software.                                                *
 * The user shall be responsible for verifying, by any or all means, the     *
 * software's suitability for its requirements, its due and proper           *
 * functioning, and for ensuring that it shall not cause damage to either    *
 * persons or property.                                                      *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.         *
 *                                                                           *
 * The author does not either expressly or tacitly warrant that this         *
 * software does not infringe any or all third party intellectual right      *
 * relating to a patent, software or to any or all other property right.     *
 * Moreover, the author shall not hold someone harmless against any or all   *
 * proceedings for infringement that may be instituted in respect of the     *
 * use, modification and redistrbution of this software.                     *
 *****************************************************************************/

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h> /* MB_CUR_MAX */
#include <locale.h> /* setlocale() */
#include <wchar.h> /* mbrtowc() */
#include <wctype.h> /* towupper() */
#include <string.h> /* memset() */
#include <limits.h> /* MB_LEN_MAX */
#include <errno.h>

#ifdef REMLET_NG
# define TOPLEFT L'╔'
# define TOP L'═'
# define TOPRIGHT L'╗'
# define LEFT L'║'
# define RIGHT L'║'
# define BOTTOMLEFT L'╚'
# define BOTTOM L'═'
# define BOTTOMRIGHT L'╝'
#else
# define TOPLEFT L'#'
# define TOP L'#'
# define TOPRIGHT L'#'
# define LEFT L'#'
# define RIGHT L'#'
# define BOTTOMLEFT L'#'
# define BOTTOM L'#'
# define BOTTOMRIGHT L'#'
#endif


int remlet (const wchar_t *str)
{
	wchar_t *buf = wcsdup (str);
	if (buf == NULL)
		return -1;

	size_t width = 2 * wcwidth (L' ');

	/* Upper case and width computation */
	for (int i = 0; str[i]; i++)
	{
		wchar_t c = buf[i] = towupper (str[i]);
		int w = wcwidth (c);

		if (w == -1)
		{
			fwprintf (stderr, L"Non printable character error\n");
			free (buf);
			return -1;
		}
		width += w;
	}

	size_t len = wcslen (buf);
	wchar_t *remlet = (wchar_t *)malloc ((2 * (width + 3) + len + 5 + 1)
					* sizeof (wchar_t));
	if (remlet == NULL)
	{
		free (buf);
		return -1;
	}

	wchar_t *ptr = remlet;
	*ptr++ = TOPLEFT;
	wmemset (ptr, TOP, width);
	ptr += width;
	*ptr++ = TOPRIGHT;
	*ptr++ = L'\n';
	*ptr++ = LEFT;
	*ptr++ = L' ';
	wcscpy (ptr, buf);
	free (buf);
	ptr += len;
	*ptr++ = L' ';
	*ptr++ = RIGHT;
	*ptr++ = L'\n';
	*ptr++ = BOTTOMLEFT;
	wmemset (ptr, BOTTOM, width);
	ptr += width;
	*ptr++ = BOTTOMRIGHT;
	*ptr++ = L'\n';
	*ptr = L'\0';

	wprintf (L"%ls", remlet);

	free (remlet);
	return 0;
}


static char *merge_words (char *const *wordv, unsigned wordc)
{
	char *str = NULL;
	size_t tlen = 0;

	for (unsigned i = 0; i < wordc; i++)
	{
		size_t len = strlen (wordv[i]);

		char *nstr = (char *)realloc (str, tlen + len + 1);
		if (nstr == NULL)
		{
			perror ("Error");
			free (str);
			return NULL;
		}

		str = nstr;
		memcpy (str + tlen, wordv[i], len);
		tlen += len;
		str[tlen] = ' ';
		tlen++;
	}
	str[tlen - 1] = '\0';

	return str;
}


extern int
main (int argc, char *argv[])
{
	setlocale (LC_ALL, "");
	fwide (stdin, 1);
	fwide (stdout, 1);
	fwide (stderr, 1);

	if (argc > 1)
	{
		char *str = merge_words (argv + 1, argc - 1);

		size_t len = mbstowcs (NULL, str, 0) + 1;
		if (len == (size_t)(-1))
		{
			errno = EILSEQ;
			perror (str);
			free (str);
			return 1;
		}

		wchar_t *wstr = (wchar_t *)malloc (len * sizeof (wchar_t));
		if (wstr == NULL)
		{
			free (str);
			return 1;
		}
		mbstowcs (wstr, str, len);
		free (str);

		remlet (wstr);
		free (wstr);
	}
	else
	while (!feof (stdin))
	{
		wchar_t buf[200];

		if (fgetws (buf, sizeof (buf), stdin) == NULL)
		{
			if (ferror (stdin))
			{
				perror ("Read error");
				return 1;
			}
			continue;
		}

		wchar_t *ptr = wcschr (buf, L'\r');
		if (ptr == NULL)
			ptr = wcschr (buf, L'\n');
		if (ptr != NULL)
			*ptr = '\0';
		remlet (buf);
	}
	return 0;
}

