/* Copyright (c) 2005 krzYszcz and others.
 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
 * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

/* This is a prototype of an active comment.  It might be replaced with
   a new core object type, T_LINK (te_type bitfield would have to be
   extended then). */

#include "pddplink.h"

#include <stdio.h>
#include <string.h>
#ifdef _WIN32
# include <io.h>
#else
# include <unistd.h>
#endif

#include "m_imp.h" /* required for glob_evalfile() */

/* this isn't in any header, but its declared in s_path.c */
void open_via_helppath(const char *name, const char *dir);

typedef struct _pddplink t_helplink;

static t_class *helplink_class;

static void helplink_getrect(t_gobj *z, t_glist *glist,
                             int *xp1, int *yp1, int *xp2, int *yp2)
{
    t_helplink *x = (t_helplink *)z;
    int width, height;
    int x1, y1, x2, y2;
    if (glist->gl_editor && glist->gl_editor->e_rtext)
    {
        if (x->x_rtextactive)
        {
            t_rtext *y = _glist_getrtext(glist, (t_text *)x);
            _getrect_dimen(y, &width, &height);
            height -= 2;
        }
        else
        {
            int font = glist_getfont(glist);
            width = x->x_vislength * sys_fontwidth(font) + 2;
            height = sys_fontheight(font) + 2;
        }
    }
    else width = height = 10;

    x1 = text_xpix(&x->x_ob, glist);
    y1 = text_ypix(&x->x_ob, glist) + 1;
    x2 = x1 + width;
    y2 = y1 + height + 1;
    *xp1 = x1;
    *yp1 = y1;
    *xp2 = x2;
    *yp2 = y2;

}

static void helplink_displace(t_gobj *z, t_glist *glist, int dx, int dy)
{
    t_text *t = (t_text *)z;
    t->te_xpix += dx;
    t->te_ypix += dy;
    if (glist_isvisible(glist))
    {
        t_rtext *y = _glist_getrtext(glist, t);
        rtext_displace(y, dx, dy);
    }
}

static void helplink_select(t_gobj *z, t_glist *glist, int state)
{
    t_helplink *x = (t_helplink *)z;
    t_rtext *y = _glist_getrtext(glist, (t_text *)x);
    rtext_select(y, state);
    if (glist_isvisible(glist) && glist->gl_havewindow)
    {
        if (state)
          pdgui_vmess(0, "crs rk", glist, "itemconfigure", rtext_gettag(y)
                      , "-fill", 0x0000FF
            );
        else
          pdgui_vmess(0, "crs rs rk rk", glist, "itemconfigure", rtext_gettag(y)
                      , "-text", x->x_vistext
                      , "-fill", 0x0000DD
                      , "-activefill", 0xE70000
            );
    }
}

static void helplink_activate(t_gobj *z, t_glist *glist, int state)
{
    t_helplink *x = (t_helplink *)z;
    t_rtext *y = _glist_getrtext(glist, (t_text *)x);
    rtext_activate(y, state);
    x->x_rtextactive = state;
}

static void helplink_vis(t_gobj *z, t_glist *glist, int vis)
{
    t_helplink *x = (t_helplink *)z;
    t_rtext *y;
    if (vis)
    {
        if ((glist->gl_havewindow || x->x_isgopvisible)
            && (y = _glist_getrtext(glist, (t_text *)x)))
        {
            rtext_draw(y);
            pdgui_vmess(0, "crs rs rk rk", glist_getcanvas(glist), "itemconfigure", rtext_gettag(y)
                  , "-text", x->x_vistext
                  , "-fill", 0x0000DD
                  , "-activefill", 0xE70000
              );
        }
    } else {
        if ((glist->gl_havewindow || x->x_isgopvisible)
            && (y = _glist_getrtext(glist, (t_text *)x)))
            rtext_erase(y);
    }
}

static void helplink_doclick(t_helplink *x)
{
    const char* objectname = x->x_ulink->s_name;
    char dirbuf[MAXPDSTRING], *nameptr;
    int fd = canvas_open(x->x_glist, objectname, "-help.pd",
                         dirbuf, &nameptr, MAXPDSTRING, 0);

    if (fd < 0) {
        /* if canvas_open() failed try open_via_helppath() */
        open_via_helppath(objectname, canvas_getdir(x->x_glist)->s_name);
    } else {
        /* if canvas_open() gave us a filehandle, then we have a helppatch to
         * open in dirbuf and nameptr, but we don't need the filehandle */
        close(fd);
        glob_evalfile(NULL, gensym(nameptr), gensym(dirbuf));
    }
}

static int helplink_click(t_gobj *z, t_glist *glist, int xpix, int ypix,
                            int shift, int alt, int dbl, int doit)
{
    (void)xpix;(void)ypix;(void)shift;(void)alt;(void)dbl;
    t_helplink *x = (t_helplink *)z;
    if (glist->gl_havewindow || x->x_isgopvisible)
    {
        if (doit)
            helplink_doclick(x);
        return (1);
    }
    else
        return (0);
}

static void helplink_free(t_helplink *x)
{
    if (x->x_vistext)
        freebytes(x->x_vistext, x->x_vissize);
}

static void *helplink_new(t_symbol *s)
{
    t_helplink *x = (t_helplink *) pd_new(helplink_class);

    x->x_isgopvisible = 0;
    x->x_vistext = 0;
    x->x_vissize = 0;
    x->x_vislength = (x->x_vistext ? strlen(x->x_vistext) : 0);
    x->x_rtextactive = 0;
    x->x_glist = canvas_getcurrent();
    if (s == &s_)
        x->x_ulink = gensym("helplink"); /* default to helplink help patch */
    else
        x->x_ulink = s;

    /* do we need to set ((t_text *)x)->te_type = T_TEXT; ? */
    if (!x->x_vistext)
    {
      x->x_vislength = strlen(x->x_ulink->s_name);
      x->x_vissize = x->x_vislength + 1;
      x->x_vistext = getbytes(x->x_vissize);
      strcpy(x->x_vistext, x->x_ulink->s_name);
    }
    return (x);
}

static void helplink_delete(t_gobj *z, t_glist *glist)
{
    canvas_deletelinesfor(glist, (t_text *)z);
}
static t_widgetbehavior helplink_widgetbehavior =
{
    helplink_getrect,
    helplink_displace,
    helplink_select,
    helplink_activate,
    helplink_delete,
    helplink_vis,
    helplink_click,
};

void helplink_setup(void)
{
    if(!pddplink_compatfuns())
      return;

    helplink_class = class_new(gensym("helplink"),
                               (t_newmethod)helplink_new,
                               (t_method)helplink_free,
                               sizeof(t_helplink),
                               CLASS_PATCHABLE,
                               A_DEFSYMBOL, 0);

    class_addbang(helplink_class, helplink_doclick);
    class_setwidget(helplink_class, &helplink_widgetbehavior);
}
