/* Copyright (c) 1997 The Regents of the University of California.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "m_imp.h"
#include "g_canvas.h"
#include "t_tk.h"

#define LMARGIN 1
#define RMARGIN 1
#define TMARGIN 3
#define BMARGIN 2

#define SEND_FIRST 1
#define SEND_UPDATE 2
#define SEND_CHECK 0

static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp);

struct _rtext
{
    char *x_buf;
    int x_bufsize;
    int x_selstart;
    int x_selend;
    int x_height;
    t_text *x_text;
    t_glist *x_glist;
    char x_tag[50];
    struct _rtext *x_next;
};

t_rtext *rtext_new(t_glist *glist, t_text *who, t_rtext *next)
{
    t_rtext *x = (t_rtext *)getbytes(sizeof *x);
    int w, h;
    x->x_height = -1;
    x->x_text = who;
    x->x_glist = glist;
    x->x_next = glist->gl_editor->e_rtext;
    binbuf_gettext(who->te_binbuf, &x->x_buf, &x->x_bufsize);
    glist->gl_editor->e_rtext = x;
    sprintf(x->x_tag, ".x%x.t%x", glist_getcanvas(x->x_glist), x);
    rtext_senditup(x, SEND_FIRST, &w, &h);
    return (x);
}

static t_rtext *rtext_entered;

void rtext_free(t_rtext *x)
{
    sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist), 
    	x->x_tag);
    if (x->x_glist->gl_editor->e_textedfor == x)
    	x->x_glist->gl_editor->e_textedfor = 0;
    if (x->x_glist->gl_editor->e_rtext == x)
    	x->x_glist->gl_editor->e_rtext = x->x_next;
    else
    {
    	t_rtext *e2;
    	for (e2 = x->x_glist->gl_editor->e_rtext; e2; e2 = e2->x_next)
    	    if (e2->x_next == x)
    	{
    	    e2->x_next = x->x_next;
    	    break;
    	}
    }
    if (rtext_entered == x) rtext_entered = 0;
    freebytes(x->x_buf, x->x_bufsize);
    freebytes(x, sizeof *x);
}

char *rtext_gettag(t_rtext *x)
{
    return (x->x_tag);
}

void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
{
    *buf = x->x_buf;
    *bufsize = x->x_bufsize;
}


/* LATER deal with tcl-significant characters */
/* LATER fix for arbitrary size */

static int firstone(char *s, int c, int n)
{
    char *s2 = s + n;
    int i = 0;
    while (s != s2)
    {
    	if (*s == c) return (i);
    	i++;
    	s++;
    }
    return (-1);
}

static int lastone(char *s, int c, int n)
{
    char *s2 = s + n;
    while (s2 != s)
    {
    	s2--;
    	n--;
    	if (*s2 == c) return (n);
    }
    return (-1);
}

    /* LATER get this and sys_vgui to work together properly,
    	breaking up messages as needed.  As of now, there's
    	a limit of 1950 characters. */
#define UPBUFSIZE 10000
#define BOXWIDTH 60

static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp)
{
    float dispx, dispy;
    char tempbuf[UPBUFSIZE], *tp = tempbuf, *bp = x->x_buf;
    int outchars, inchars = x->x_bufsize, nlines = 0, ncolumns = 0,
    	pixwide, pixhigh;
    int font = glist_getfont(x->x_glist);
    while (inchars)
    {
    	int maxindex = (inchars > BOXWIDTH ? BOXWIDTH : inchars);
    	int eatchar = 1;
    	int foundit = firstone(bp, '\n', maxindex);
    	if (foundit < 0)
    	{
    	    if (inchars > BOXWIDTH)
    	    {
    		foundit = lastone(bp, ' ', maxindex);
    		if (foundit < 0)
    		{
    	    	    foundit = maxindex;
    	    	    eatchar = 0;
    		}
   	    }
   	    else
   	    {
   	    	foundit = inchars;
   	    	eatchar = 0;
   	    }
   	}
   	strncpy(tp, bp, foundit);
    	tp += foundit;
    	bp += (foundit + eatchar);
    	inchars -= (foundit + eatchar);
    	if (inchars) *tp++ = '\n';
    	if (foundit > ncolumns) ncolumns = foundit;
    	nlines++;
    }
    outchars = tp - tempbuf;
    if (outchars > 1950) outchars = 1950;
    
    dispx = x->x_text->te_xpos;
    dispy = x->x_text->te_ypos;
    if (nlines < 1) nlines = 1;
    if (ncolumns < 3) ncolumns = 3;
    pixwide = ncolumns * sys_fontwidth(font) + (LMARGIN + RMARGIN);
    pixhigh = nlines * sys_fontheight(font) + (TMARGIN + BMARGIN);

    if (action == SEND_FIRST)
    	sys_vgui("pdtk_text_new .x%x.c %s %f %f {%.*s} %d %s\n",
	    glist_getcanvas(x->x_glist), x->x_tag,
	    dispx + LMARGIN, dispy + TMARGIN,
	    outchars, tempbuf, font,
	    (glist_isselected(x->x_glist,
	    	&x->x_glist->gl_gobj)? "blue" : "black"));
    else if (action == SEND_UPDATE)
    {
    	sys_vgui("pdtk_text_set .x%x.c %s {%.*s}\n",
    	    glist_getcanvas(x->x_glist), x->x_tag, outchars, tempbuf);
    	text_drawborder(x->x_text, x->x_glist, x->x_tag,
	    pixwide, pixhigh, 0);
    }
    *widthp = pixwide;
    *heightp = pixhigh;
}

void rtext_retext(t_rtext *x)
{
    int w, h;
    t_freebytes(x->x_buf, x->x_bufsize);
    binbuf_gettext(x->x_text->te_binbuf, &x->x_buf, &x->x_bufsize);
    rtext_senditup(x, SEND_UPDATE, &w, &h);
}

/* find the rtext that goes with a text item */
t_rtext *glist_findrtext(t_glist *gl, t_text *who)
{
    t_rtext *x = gl->gl_editor->e_rtext;
    while (x && x->x_text != who) x = x->x_next;
    if (!x) bug("glist_findrtext");
    return (x);
}

int rtext_width(t_rtext *x)
{
    int w, h;
    rtext_senditup(x, SEND_CHECK, &w, &h);
    return (w);
}

int rtext_height(t_rtext *x)
{
    int w, h;
    rtext_senditup(x, SEND_CHECK, &w, &h);
    return (h);
}

void rtext_displace(t_rtext *x, int dx, int dy)
{
    sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist), 
    	x->x_tag, dx, dy);
}

void rtext_select(t_rtext *x, int state)
{
    t_glist *glist = x->x_glist;
    t_canvas *canvas = glist_getcanvas(glist);
    sys_vgui(".x%x.c itemconfigure %s -fill %s\n", canvas, 
    	x->x_tag, (state? "blue" : "black"));
    canvas_editing = canvas;
}

void rtext_activate(t_rtext *x, int state)
{
    t_glist *glist = x->x_glist;
    t_canvas *canvas = glist_getcanvas(glist);
    if (state)
    {
    	sys_vgui(".x%x.c select from %s 0\n", canvas, 
    	    x->x_tag);
    	sys_vgui(".x%x.c select to %s end\n", canvas, 
    	    x->x_tag);
    	glist->gl_editor->e_textedfor = x;
    	glist->gl_editor->e_textdirty = 0;
    }
    else
    {
    	sys_vgui("selection clear .x%x.c\n", canvas);
    	if (glist->gl_editor->e_textedfor == x)
    	    glist->gl_editor->e_textedfor = 0;
    }
}

void rtext_key(t_rtext *x, int n)
{
    int w, h;
    if (n == '\r') n = '\n';
    if (n == '\b')
    {
    	if (!x->x_glist->gl_editor->e_textdirty)
    	{
    	    glist_delete(x->x_glist, &x->x_text->te_g);
    	    return;
    	}
    	else if (x->x_bufsize)
    	{
    	    x->x_buf = resizebytes(x->x_buf, x->x_bufsize, x->x_bufsize-1);
    	    x->x_bufsize = x->x_bufsize - 1;
    	    rtext_senditup(x, SEND_UPDATE, &w, &h);
    	}
    }
    else if (n == '\n' || isprint(n))
    {
    	if (!x->x_glist->gl_editor->e_textdirty)
    	    x->x_buf = resizebytes(x->x_buf, x->x_bufsize, 1),
    	    	x->x_bufsize = 0;
    	else x->x_buf = resizebytes(x->x_buf, x->x_bufsize, x->x_bufsize+1);
    	x->x_buf[x->x_bufsize] = n;
    	x->x_bufsize = x->x_bufsize + 1;
    	rtext_senditup(x, SEND_UPDATE, &w, &h);
    }
    x->x_glist->gl_editor->e_textdirty = 1;
}
