/*===========================================================================
  Copyright (C) 1986-2009 European Southern Observatory (ESO)
 
  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, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

.TYPE		Module
.IDENTIFICATION txjustify.c
.AUTHOR    	Francois Ochsenbein [ESO-IPG]
.LANGUAGE  	C
.KEYWORDS	Window Management
.ENVIRONMENT	TermWindows
.COMMENTS	This module provides justification utilities for the window 
		functions,
		without any physical i/o. Only for TermDisplay use.
\begin{TeX}
\end{TeX}

.VERSION  1.0	14-Aug-1986:	Creation

.VERSION  2.0	03-Dec-1986	New terminal-independant graphic characters
			with output buffering version.
.VERSION  2.1	25-Jun-1987: Version '2'
.VERSION 3.0	20-Mar-1988: Version '3'
.VERSION 3.1	31-Jan-1989: Modif tx_crosses to avoid corners at top/bottom
.VERSION 3.2	29-Jun-1989: Removed tx_crosses.

 090901         last modif
----------------------------------------------------------------------------*/

#define		DEBUG		0	/* For debugging only		*/

#define PM_LEVEL 	LEVEL_STR

#define  TW_import	0	/* Do not use macro window definitions	*/
#include <twset.h>

#if 	DEBUG
#define ENTER_DEBUG(x)	ENTER(x)
#define EXIT_DEBUG(x)	EXIT(x)
#else
#define ENTER_DEBUG(x)	
#define EXIT_DEBUG(x)	return(x)
#endif

#define VBar 	GraphicAchar(_VERTICAL_)
#define HBar 	GraphicAchar(_HORIZONTAL_)
#define Corner	GraphicAchar(_CORNER_+_CROSS_)

#define V	_VERTICAL_
#define H	_HORIZONTAL_
#define UL	(_CORNER_+_UPLEFT_)
#define UR	(_CORNER_+_UPRIGHT_)
#define DL	(_CORNER_+_DOWNLEFT_)
#define DR	(_CORNER_+_DOWNRIGHT_)
#define HV	(_CORNER_+_CROSS_)
#define TL	(_TEE_+_LEFT_)
#define TR	(_TEE_+_RIGHT_)
#define TU	(_TEE_+_UP_)
#define TD	(_TEE_+_DOWN_)

	/* MONITOR(TXJUSTIFY); */

/*==========================================================================
 *			tx_jl
 *==========================================================================*/
int tx_jl (str, len, blank)
/*+++
.PURPOSE Justify to the left (suppress blanks) the string made of `ACHAR's.
.RETURNS OK
.REMARKS 
---*/
	ACHAR	*str;		/* IN: string to justify	*/
	int 	len;		/* IN: Length of str		*/
	ACHAR	blank;		/* IN: The `blank' ACHAR	*/
{
	register ACHAR	*p1, *p2, *pe;

  ENTER_DEBUG("tx_jl");

#if DEBUG
	TRACE_ED_STR2("Before left justify", str, sizeof(ACHAR)*(len+1));
#endif

  for (p1 = str, pe = p1 + len; (p1 < pe) && (*p1 == blank); p1++)	;

  for (p2 = str; p1 < pe; p1++, p2++)	*p2 = *p1;
  for (; p2 < pe; p2++)			*p2 = blank;

#if DEBUG
	TRACE_ED_STR2(" After left justify", str, sizeof(ACHAR)*(len+1));
#endif

  EXIT_DEBUG(OK);
}

/*==========================================================================
 *			tx_jr
 *==========================================================================*/
int tx_jr (str, len, blank)
/*+++
.PURPOSE Justify to the right (insert blanks at the left) the string made 
	of `ACHAR's.
.RETURNS OK
.REMARKS 
---*/
	ACHAR	*str;		/* IN: string to justify	*/
	int 	len;		/* IN: Length of str		*/
	ACHAR	blank;		/* IN: The `blank' ACHAR		*/
{
	register ACHAR	*p1, *p2;

  ENTER_DEBUG("tx_jr");

  for (p1 = str + len, p2 = p1 - 1; (--p1 >= str) && (*p1 == blank); )	;

  for (; p1 >= str; p1--, p2--)	*p2 = *p1;
  for (; p2 >= str; p1--, p2--)	*p2 = blank;

  EXIT_DEBUG(OK);
}

/*==========================================================================
 *			tx_jc
 *==========================================================================*/
int tx_jc (str, len, blank)
/*+++
.PURPOSE Center the string made of `ACHAR's.
.RETURNS OK
.REMARKS 
---*/
	ACHAR	*str;		/* IN: string to justify	*/
	int 	len;		/* IN: Length of str		*/
	ACHAR	blank;		/* IN: The `blank' ACHAR		*/
{
	register ACHAR	*p;
	register int nb;

  ENTER_DEBUG("tx_jc");

  tx_jl(str, len, blank);		/* First, push to left	*/

	/* ... and count trailing blanks. Put half of them at left	*/

  for (p = str + len, nb = 0; (--p >= str) && (*p == blank); nb++)	;

  EXIT_DEBUG(tx_jr(str, len - nb/2, blank));
}

/*==========================================================================
 *			tx_justify
 *==========================================================================*/
int tx_justify (str, len, blank)
/*+++
.PURPOSE Justify (left & right) the string made of `ACHAR's.
.RETURNS OK
.REMARKS 
---*/
	ACHAR	*str;		/* IN: string to justify	*/
	int 	len;		/* IN: Length of str		*/
	ACHAR	blank;		/* IN: The `blank' ACHAR		*/
{
	register ACHAR	*p1, *p2;
	register int ls;
	int	 sb, rb, pb, i, nb;

  ENTER_DEBUG("tx_justify");

#if DEBUG
	TRACE_ED_STR2("Before justification", str, sizeof(ACHAR)*(len+1));
#endif

	/* First, start at first non-blank char */

  while ( (*str == blank) && (len > 0))	  { str++; len--; }
  
	/* ... and count trailing blanks. 
	 *	This gives the length ls of the source string 	*/

  for (p1 = str + len, nb = 0; (--p1 >= str) && (*p1 == blank); nb++)	;
  if (nb == 0)			FINISH;
  ls = len - nb;

	/* Now, count existing blanks in the string	*/

  nb = 0;
  while (--p1 >= str)
	if (*p1 == blank)  nb++;

  if (nb == 0)		FINISH;		/* Can't be justified...	*/


  sb = (len - ls)/nb;			/* Systematic blanks		*/
  rb = (len - ls)%nb;			/* Random blanks		*/

  pb = 0;				/* Periodic blanks		*/
  if (rb)		pb = nb / rb;

  for (nb=0, p1=str+ls, p2=str+len; --p1>=str; )
  {	*(--p2) = *p1;
	if (*p1 == blank)
	{	nb++;
		for (i=sb; --i>=0; )	*(--p2) = blank;
		if (rb>0)
		{	if (nb%pb == 0) { *(--p2) = blank; rb--; }
		}
	}
  }

#if DEBUG
	TRACE_ED_STR2(" After justification", str, sizeof(ACHAR)*(len+1));
#endif
  FIN:
  EXIT_DEBUG(OK);
}

#if 0
/*==========================================================================
 *			tx_crosses
 *==========================================================================*/
int tx_crosses(w, tab_lim)
/*+++
.PURPOSE Modifies the crosses / tees in a table between lines[0] and lines[1]
.RETURNS OK
.REMARKS To be called at end of table environment.
---*/
	WINDOW *w;		/* IN: The concernced window */
	short int tab_lim[2];	/* IN: Line limits of table, limits INCLUSIVE */
{	
	MID_STATIC ACHAR An[2] = {' ', ' '};
	ACHAR 	*pa, *pad;
	int 	j;
	int 	i,k,c, dir;
	MID_STATIC 	 ACHAR *pn[4];
	MID_RSTATIC  ACHAR as = ' ';
	MID_RSTATIC unsigned char mod_tees[5][4][11] = {
			/* First index = kind of char
			 * Second index = kind of neighbour char
			 * Third = neighbour char
			 */
   /*	  |  --  UL  DL  DR  UR  +   TU  TD  TL  TR			*/
	{						/* Crosses	*/
	{HV, TU, HV, TU, TU, HV, HV, HV, TU, HV, HV},	/* UP	char	*/
	{HV, TD, TD, HV, HV, TD, HV, TD, HV, HV, HV},	/* DOWN char	*/
	{TL, HV, HV, HV, TL, TL, HV, HV, HV, HV, TL},	/* LEFT	char	*/
	{TR, HV, TR, TR, HV, HV, HV, HV, HV, TR, HV}	/* Right char	*/
	}, {						/* Up Tee	*/
	{TU, TU, TU, TU, TU, TU, TU, TU, TU, TU, TU},	/* UP	char	*/
	{TU,  H,  H, TU, TU,  H, TU,  H, TU, TU, TU},	/* DOWN char	*/
	{UL, TU, TU, TU, UL, UL, TU, TU, TU, TU, UL},	/* LEFT	char	*/
	{UR, TU, UR, UR, TU, TU, TU, TU, TU, UR, TU}	/* Right char	*/
	}, {						/* Down Tee	*/
	{TD,  H, TD,  H,  H, TD, TD, TD,  H, TD, TD},	/* UP	char	*/
	{TD, TD, TD, TD, TD, TD, TD, TD, TD, TD, TD},	/* DOWN char	*/
	{DL, TD, TD, TD, DL, DL, TD, TD, TD, TD, DL},	/* LEFT	char	*/
	{DR, TD, DR, DR, TD, TD, TD, TD, TD, DR, TD}	/* Right char	*/
	}, {						/* Left Tee	*/
	{TL, UR, TL, UR, UR, TL, TL, TL, UR, TL, TL},	/* UP	char	*/
	{TL, DR, DR, TL, TL, DR, TL, DR, TL, TL, TL},	/* DOWN char	*/
	{TL, TL, TL, TL, TL, TL, TL, TL, TL, TL, TL},	/* LEFT	char	*/
	{ V, TL,  V,  V, TL, TL, TL, TL, TL,  V, TL}	/* Right char	*/
	}, {						/* Right Tee	*/
	{TR, UR, TR, UR, UR, TR, TR, TR, UR, TR, TR},	/* UP	char	*/
	{TR, DR, DR, TR, TR, DR, TR, DR, TR, TR, TR},	/* DOWN char	*/
	{ V, TR, TR, TR,  V,  V, TR, TR, TR, TR,  V},	/* LEFT	char	*/
	{TR, TR, TR, TR, TR, TR, TR, TR, TR, TR, TR}	/* Right char	*/
	} };

  ENTER("tx_crosses");

  if (tab_lim[0] < 0)
  	tab_lim[0] = 0, An[_UP_] = Corner;
  else	An[_UP_] = ' ';

  if (tab_lim[1] >= w->dim[0])
  	tab_lim[1] = w->dim[0] - 1, An[_DOWN_] = Corner;
  else	An[_DOWN_] = ' ';

  for (i = tab_lim[0]; i <= tab_lim[1]; i++)
  {	for (j=0, pa = Aij(w, i, 0); j < w->dim[1]; pa++, j++)
	{	if (!(isGraphic(*pa)))		continue;
		c = *pa & 0xff;
		if (c < CornerChar(_CROSS_)) 	continue;
		if (c >= RubbishChar())		continue;
		pn[_UP_] 	= (i == tab_lim[0] ? 
			&An[_UP_]   : Aij(w, i-1, j));
		pn[_DOWN_] 	= (i >= tab_lim[1] ? 
			&An[_DOWN_] : Aij(w, i+1, j));
		pn[_LEFT_] 	= (j == 0          ? &as : pa-1);
		pn[_RIGHT_] 	= (j >= w->dim[1] - 1 ? &as : pa+1);

		for (dir=0; dir<4; dir++)
		{	c = (*pa & 0xff) - CornerChar(_CROSS_);
			if (c < 0)			break;
			k = -1;
			pad = pn[dir];
			if (isGraphic(*pad))	
				k = ((*pad) & 0xff) - GraphicChar(0);
			if( (k<0) || (k >= 11))		k = (dir >> 1) ^ 1;
			*pa = (*pa & 0xff00) | GraphicChar(mod_tees[c][dir][k]);
		}
		switch(*pa & 0xff)
		{ case CornerChar(_UPLEFT_): case CornerChar(_DOWNLEFT_):
			pad = pn[_RIGHT_];
			if_not(isGraphic(*pad))	/* If no rule at top / bottom */
				*pa = (*pa & 0xff00) | GraphicChar(V);
			continue;
		  case CornerChar(_UPRIGHT_): case CornerChar(_DOWNRIGHT_):
			pad = pn[_LEFT_];
			if_not(isGraphic(*pad))	/* If no rule at top / bottom */
				*pa = (*pa & 0xff00) | GraphicChar(V);
	    	  default:
			continue;
		}
	}
  }

  EXIT(OK);
}
#endif
