#include<stdio.h>
#include"xpointer.h"
#include"display.h"

#define max(a,b) ((a)>(b) ? (a):(b))
#define min(a,b) ((a)<(b) ? (a):(b))

int TextWidth (font, chars, len)
     XFontStruct *font;
     char *chars;
     int len;

{
  register int width = 0, ch; 
  int i;

  for (i = 0; i < len; i++) {
    ch = chars[i] - font->min_char_or_byte2;
    if (ch < 0 || ch > font->max_char_or_byte2) continue;
    if (font->per_char == NULL) width += font->min_bounds.width;
    else width += font->per_char[ch].width;
  }
  return (width);
}

int DefineLine (font, rect, chars, eol,nc)
     XFontStruct *font;
     XRectangle *rect;
     char *chars, **eol;
     int *nc;

{
  register int width = 0, cp;
  int wid = rect->width, rw = 0;
  char *pos;


  pos = *eol = chars;
  while (width <= wid) {
    if (pos[0] == '\0') { 
      *eol = pos; 
      *nc = pos - chars;
      /*      printf ("%d[EOT]: %.32s\n",width,rw,chars); */
      return (width);
    }

    if (pos[0] == '\n') { 
      *eol = pos + 1; 
      *nc = *eol - chars;
      /* printf ("%d[EOl]: %.32s\n",width,rw,chars); */
      return (width);
    }

    if (pos[0] == ' ') { 
      rw = width; 
      *eol = pos + 1;
    }

    cp = pos[0] - font->min_char_or_byte2;
    if (cp >= 0 && cp <= font->max_char_or_byte2 && font->per_char != NULL) 
      width += font->per_char[cp].width;
    else width += font->min_bounds.width;
    pos++;
  }

  if (rw == 0) {
    *eol = pos;
    rw = width;
  }
  
  *nc = *eol - chars;
/*
  printf ("%d[%d] %d-- %d: %.60s\n",
	  width,rw,TextWidth(font,chars,*nc),*nc,chars);
*/
  return(rw);
}


int find_text_line (font, rect, chars, lineno, start, mx)
     XFontStruct *font;
     char *chars, **start;
     int lineno, *mx;
     XRectangle *rect;

{
  int  width = 0, lines = 0, num = 0;
  char *next;

  *start = chars;
  while (lines < lineno && (start[0] != '\0')) {
    /* printf ("FTL %d: %30s.\n", num, *start); */
    width = max (width,DefineLine (font, rect, *start, &next, &num));
    lines++;
    *start = next;
    /* printf ("    %d: %30s.\n", num, *start); */

  }
  *mx = width;
  return (lines);
}


char *find_line (font, rect, chars, ptr, maxwidth)
     XFontStruct *font;
     XRectangle *rect;
     char *chars, *ptr;
     int *maxwidth;

{
  char *current = chars, *next;
  int num;

  if (ptr < chars) return (NULL);
  while (current != NULL) {
    *maxwidth = max (*maxwidth,
		     DefineLine (font, rect, current, &next, &num));
    if (next > ptr) return (current);
    current = next;
  }
  return (NULL);
}


char **find_all_lines (font, rect, chars, maxwidth, cnt)
     XFontStruct *font;
     XRectangle *rect;
     char *chars;
     int *maxwidth, *cnt;

{
  char *next, **list;
  int num, count, i = 0;

  count = count_text_lines (font, rect, chars, maxwidth);
  *cnt = count;
  list = (char **) malloc (count * sizeof (char*));
  list[i] = chars;
  while (i < count) {
    *maxwidth = max (*maxwidth,
		     DefineLine (font, rect, list[i], &next, &num));
    list[++i] = next;
  }
  return (list);
}

  
int count_text_lines (font, rect, chars, maxwidth)
     XFontStruct *font;
     XRectangle *rect;
     char *chars;
     int *maxwidth;

{
  int lines = 0, num;
  char *current = chars, *next;

  *maxwidth = 0;
  while (*current != '\0') {
    *maxwidth = max (*maxwidth,
		     DefineLine (font, rect, current, &next, &num));
    current = next;
    lines++;
  }
  /*  printf (" COUNT TEXT LINES:[%s]:line count = %d\n",chars,lines); */
  return (lines);
}


int text_lines_in_rect (font, rect, chars, leading, end, maxwidth)
     XFontStruct *font;
     XRectangle *rect;
     char *chars, **end;
     int *maxwidth, leading;

{
  int lines = 0, yc = 0, part = 0, num,
      inc = font->ascent + font->descent + (leading/100);

  char *current = chars, *next;

  while (*current != '\0' && yc < rect->y ) {
    *maxwidth = max (*maxwidth,
		     DefineLine (font, rect, current, &next, &num));
    current = next;
    part += (leading/100);
    yc += inc + (part%100);
    lines++;
  }
  *end = current;
  /* printf ("TL IN RECT [%s]:line count = %d\n",chars,lines); */
  return (lines);
}


int blit_text (dpy, win, text, font, rect, chars, len, mode, width)
     Display *dpy;
     Window win;
     GC text;
     XFontStruct *font;
     XRectangle *rect;
     char *chars;
     int len, mode, width;

{
  int yc = rect->y + font->ascent + 1;

  if (!width) width = TextWidth (font, chars, len);

  switch (mode) {
  case CENTER_JUSTIFIED: 
    XDrawString (dpy, win, text, (rect->x + ((rect->width - width)/2)), yc, 
		 chars, len);
    break;
  case RIGHT_JUSTIFIED: 
    XDrawString (dpy, win, text, (rect->x + rect->width - width), yc,
		 chars, len);
    break;
  default: /* LEFT_JUSTIFIED */
    XDrawString (dpy, win, text, rect->x, yc, chars,len);
  }
  return (width);
}


char *
justify_text (dpy, win, text, font, rect, chars, mode, leading, nl,maxwidth)
     Display *dpy;
     Window win;
     GC text;
     XFontStruct *font;
     XRectangle *rect;
     char *chars;
     int mode, leading, nl, *maxwidth;

{
  int  width, numchars, yc, lead_part = 0, w, h, b, d, x, y, num;
  Window rootret;
  char *current_line, *line;
  XRectangle nrect;

  nrect.x = rect->x;
  nrect.y = rect->y;
  
  if (rect->width == 0 && rect->height == 0) {
    XGetGeometry (dpy, win, &rootret, &x, &y, &w, &h, &b, &d); 
    nrect.width = w - nrect.x;
    nrect.height = h - nrect.y;
  } else {
    nrect.height = rect->height;
    nrect.width = rect->width;
  }

  if (nl == 0) 
    nl = nrect.height*100 / ((font->ascent + font->descent)*100+leading);

  current_line = chars;
  while ((*current_line != '\0') && nl) {
    nl--;
    width = DefineLine (font, &nrect, current_line, &line, &numchars);
    /*printf ("JUSTIFY blitting %d chars [%d]\n",numchars, width); */
    *maxwidth = max(*maxwidth,width);

    blit_text (dpy, win, text, font, &nrect,
	       current_line, numchars, mode, width);
    lead_part += (leading%100);
    nrect.y += font->ascent + font->descent + 
      (leading / 100) + (lead_part / 100);
    current_line = line;
  }
  return (current_line);
}

char *display_text (dpy, win, text, font, rect, chars, mode, leading,
		    maxwidth)
     Display *dpy;
     Window win;
     GC text;
     XFontStruct *font;
     XRectangle *rect;
     char *chars;
     int mode, leading, *maxwidth;

{
  XRectangle new_rect;
  int x,y, w,h, b,d;
  Window rootret;
  int text_height, new_leading, line_count,
  spread_mode = (mode & SPREAD_MASK);
  
  if (rect->width == 0 && rect->height == 0) {
    XGetGeometry (dpy, win, &rootret, &x, &y, &w, &h, &b, &d); 
    rect->x = 0;
    rect->y = 0;
    rect->width = w;
    rect->height = h;
  }
  new_rect.x = rect->x;
  new_rect.y = rect->y;
  new_rect.height = rect->height;
  new_rect.width = rect->width;
  /* printf ("DISPLAY begin rect = %d,%d  %d,%d; mode = %d, leading = %d\n",
	  rect->x, rect->y, rect->width, rect->height, spread_mode, leading); 
  */
  line_count = count_text_lines (font, rect, chars, maxwidth);

  text_height = ((font->ascent + font->descent) * 100 + leading) *
    line_count/100;

  switch (spread_mode) {
  case CENTER_TEXT: 
    new_leading = leading;
    if (text_height < rect->height) {
      new_rect.y = rect->y + (rect->height - text_height)/2;
      new_rect.height = text_height;
    }
    break;
  case SPREAD_TEXT: 
    if (text_height < rect->height)
      new_leading = leading +
	(((((rect->height - text_height)*100)<<8) / line_count)>>8);
    else new_leading = leading;
    break;
  case SQUEEZE_TEXT: 
    if (text_height > rect->height)
      new_leading = leading +
	(((((rect->height - text_height)*100)<<8) / line_count)>>8);
    else new_leading = leading;
    break;
  case SPREAD_SQUEEZE_TEXT: 
    new_leading = leading +
      (((((rect->height - text_height)*100)<<8) / line_count)>>8);
    break;
  case BOTTOM_TEXT: 
    new_leading = leading;
    if (text_height <= rect->height) {
      new_rect.height = text_height;
      new_rect.y = rect->y + rect->height - text_height;
    }
    break;
  default:
    new_leading = leading;
  }

  /* printf ("DISPLAY end rect = %d,%d  %d,%d; leading = %d\n",
	  new_rect.x, new_rect.y, 
	  new_rect.width, new_rect.height, new_leading); */
  return (justify_text (dpy, win, text, font, &new_rect, chars,
			(mode & JUSTIFY_MASK),	new_leading, 0, maxwidth));
}


