
#include <proto/iffparse.h>
#include "class.h"
#include <utility/pack.h>
#include <datatypes/textclass.h>
#include <dos/dostags.h>
#include <libraries/gadtools.h>
#include <stdlib.h>

/****************************************************************************/

struct data
{
    char                    url[256];
    char                    text[256];
    int                     tLen;
    struct MUI_RenderInfo   *mri;
    struct TextExtent       te;
    Object                  *menu;
    struct TextFont         *tf;
    ULONG                   flags;
    LONG                    mouseOutPen;
    LONG                    mouseOverPen;
    LONG                    visitedPen;
    LONG                    textpen;
};

enum
{
    UTFLG_Show              = 1<<0,
    UTFLG_MouseOver         = 1<<1,
    UTFLG_Active            = 1<<2,
    UTFLG_Visited           = 1<<3,
    UTFLG_DoVisitedPen      = 1<<4,
    UTFLG_Fallback          = 1<<5,
    UTFLG_Underline         = 1<<6,
    UTFLG_SetMax            = 1<<7,
    UTFLG_DoOpenURL         = 1<<8,
    UTFLG_UserDoVisitedPen  = 1<<9,
    UTFLG_UserFallback      = 1<<10,
    UTFLG_UserUnderline     = 1<<11,
    UTFLG_UserSetMax        = 1<<12,
    UTFLG_UserDoOpenURL     = 1<<13,
    UTFLG_FreeMouseOutPen   = 1<<14,
    UTFLG_FreeMouseOverPen  = 1<<15,
    UTFLG_FreeVisitedPen    = 1<<16,
    UTFLG_RejectIDCMP       = 1<<17,
    UTFLG_Disabled          = 1<<18,
    UTFLG_NoMenu            = 1<<19,
    UTFLG_UseFont           = 1<<20,
    UTFLG_CloseFont         = 1<<21,
};

#define UTFLG_Use               (UTFLG_Active|UTFLG_Fallback)
#define UTFLG_IsToShow(f)       (((ULONG)(f)) & UTFLG_Show)
#define UTFLG_IsDisabled(f)     (((ULONG)(f)) & UTFLG_Disabled)
#define UTFLG_IsToUse(f)        (((ULONG)(f)) & UTFLG_Use)
#define UTFLG_IsMouseOver(f)    (((ULONG)(f)) & UTFLG_MouseOver)
#define UTFLG_IsVisited(f)      ((((ULONG)(f)) & UTFLG_DoVisitedPen) && (((ULONG)(f)) & UTFLG_Visited))
#define UTFLG_IsUnderline(f)    (((ULONG)(f)) & UTFLG_Underline)
#define UTFLG_IsSetMax(f)       (((ULONG)(f)) & UTFLG_SetMax)
#define UTFLG_IsDoOpenURL(f)    (((ULONG)(f)) & UTFLG_DoOpenURL)

/***********************************************************************/

struct urltextPackTags
{
    STRPTR  url;
    STRPTR  text;
    BOOL    doVisitedPen;
    BOOL    fallBack;
    BOOL    underline;
    ULONG   flags;
};

ULONG utTable[] =
{
    PACK_STARTTABLE(MUIA_Urltext_Base),

    PACK_ENTRY(MUIA_Urltext_Base,MUIA_Urltext_Url,urltextPackTags,url,PKCTRL_LONG|PKCTRL_PACKONLY),
    PACK_ENTRY(MUIA_Urltext_Base,MUIA_Urltext_Text,urltextPackTags,text,PKCTRL_LONG|PKCTRL_PACKONLY),

    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_DoVisitedPen,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY,UTFLG_DoVisitedPen),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_FallBack,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY,UTFLG_Fallback),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_Underline,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY,UTFLG_Underline),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_SetMax,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY,UTFLG_SetMax),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_DoOpenURL,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY,UTFLG_DoOpenURL),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_NoMenu,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY,UTFLG_NoMenu),

    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_DoVisitedPen,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY|PSTF_EXISTS,UTFLG_UserDoVisitedPen),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_FallBack,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY|PSTF_EXISTS,UTFLG_UserFallback),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_Underline,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY|PSTF_EXISTS,UTFLG_UserUnderline),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_SetMax,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY|PSTF_EXISTS,UTFLG_UserSetMax),
    PACK_LONGBIT(MUIA_Urltext_Base,MUIA_Urltext_DoOpenURL,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY|PSTF_EXISTS,UTFLG_UserDoOpenURL),

    PACK_NEWOFFSET(MUIA_ContextMenu),
    PACK_LONGBIT(MUIA_ContextMenu,MUIA_ContextMenu,urltextPackTags,flags,PKCTRL_BIT|PKCTRL_PACKONLY|PSTF_EXISTS,UTFLG_NoMenu),

    PACK_ENDTABLE
};

static ULONG ASM
mNew(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct opSet *msg)
{
    struct urltextPackTags  ut = {0};
    register struct TagItem *attrs = msg->ops_AttrList,
                            tags[] = {MUIA_InnerBottom,0,
                                      MUIA_InnerLeft,0,
                                      MUIA_InnerRight,0,
                                      MUIA_InnerTop,0,
                                      MUIA_Weight,0,
                                      MUIA_InputMode,MUIV_InputMode_Immediate,
                                      MUIA_ShowSelState,FALSE,
                                      TAG_MORE,0};

    PackStructureTags(&ut,utTable,attrs);

    if (!ut.url) return 0;

    tags[7].ti_Data = (ULONG)attrs;
    msg->ops_AttrList = tags;

    if (obj = (Object *)DoSuperMethodA(cl,obj,(APTR)msg))
    {
        register struct data    *data = INST_DATA(cl,obj);
        register ULONG          flags = ut.flags;

        stccpy(data->url,ut.url,sizeof(data->url));

        stccpy(data->text,ut.text ? ut.text : ut.url,sizeof(data->text));
        data->tLen = strlen(data->text);

        data->mri = NULL;

        data->mouseOutPen  = -1;
        data->mouseOverPen = -1;
        data->visitedPen   = -1;
        data->textpen      = -1;
        data->menu         = NULL;
        data->tf           = NULL;

        if (!(flags & UTFLG_UserDoVisitedPen))
            if (DEFAULT_DOVISITEDPEN) flags |= UTFLG_DoVisitedPen;
            else flags &= ~UTFLG_DoVisitedPen;

        if (!(flags & UTFLG_UserFallback))
            if (DEFAULT_FALLBACK) flags |= UTFLG_Fallback;
            else flags &= ~UTFLG_Fallback;

        if (!(flags & UTFLG_UserUnderline))
            if (DEFAULT_UNDERLINE) flags |= UTFLG_Underline;
            else flags &= ~UTFLG_Underline;

        if (!(flags & UTFLG_UserSetMax))
            if (DEFAULT_SETMAX) flags |= UTFLG_SetMax;
            else flags &= ~UTFLG_SetMax;

        if (!(flags & UTFLG_UserDoOpenURL))
            if (DEFAULT_SETMAX) flags |= UTFLG_DoOpenURL;
            else flags &= ~UTFLG_DoOpenURL;

        if (OpenURLBase)
        {
            flags |= UTFLG_Active;
            if (UTFLG_IsDoOpenURL(flags))
                DoMethod(obj,MUIM_Notify,MUIA_Pressed,1,obj,2,MUIM_Urltext_OpenURL,MUIV_Urltext_OpenURL_CheckOver);
        }

        if (!(flags & UTFLG_NoMenu))
        {
            register Object *menu, *prefs, *send, *copy;
            register BPTR   lock;

            if (lock = Lock("SYS:Prefs/OpenURL",SHARED_LOCK)) UnLock(lock);

            if (menu = MenustripObject,
                MUIA_Family_Child, MenuObjectT("Urltext"),
                    MUIA_Family_Child, send = MenuitemObject,
                        MUIA_Menuitem_Title, getString(Msg_Send),
                        MUIA_Menuitem_Enabled, OpenURLBase,
                    End,
                    MUIA_Family_Child, copy = MenuitemObject,
                        MUIA_Menuitem_Title, getString(Msg_Copy),
                    End,
                    MUIA_Family_Child, MenuitemObject,
                        MUIA_Menuitem_Title, NM_BARLABEL,
                    End,
                    MUIA_Family_Child, prefs = MenuitemObject,
                        MUIA_Menuitem_Title, getString(Msg_OpenURLPrefs),
                        MUIA_Menuitem_Enabled, lock,
                    End,
                End,
            End)
            {
                DoMethod(send,MUIM_Notify,MUIA_Menuitem_Trigger,MUIV_EveryTime,obj,2,MUIM_Urltext_OpenURL,0);
                DoMethod(copy,MUIM_Notify,MUIA_Menuitem_Trigger,MUIV_EveryTime,obj,2,MUIM_Urltext_Copy,0);
                DoMethod(prefs,MUIM_Notify,MUIA_Menuitem_Trigger,MUIV_EveryTime,obj,1,MUIM_Urltext_OpenURLPrefs);
                set(obj,MUIA_ContextMenu,data->menu = menu);
            }
        }

        data->flags = flags;
    }

    msg->ops_AttrList = attrs;

    return (ULONG)obj;
}

/***********************************************************************/

static ASM ULONG
mDispose(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
    register struct data    *data = INST_DATA(cl,obj);
    register Object         *menu = data->menu;
    register ULONG          res;

    res = DoSuperMethodA(cl,obj,msg);

    if (menu) MUI_DisposeObject(menu);

    return res;
}

/***********************************************************************/

static ASM ULONG
mGet(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct opGet *msg)
{
    register struct data *data = INST_DATA(cl,obj);

    switch(msg->opg_AttrID)
    {
        case MUIA_Urltext_Url:      *msg->opg_Storage = (ULONG)data->url; return 1;
        case MUIA_Urltext_Text:     *msg->opg_Storage = (ULONG)data->text; return 1;
        case MUIA_Urltext_Active:   *msg->opg_Storage = (data->flags & UTFLG_Active); return 1;
        case MUIA_Urltext_Visited:  *msg->opg_Storage = (data->flags & UTFLG_Visited); return 1;
        case MUIA_Version:          *msg->opg_Storage = VERSION; return 1;
        case MUIA_Revision:         *msg->opg_Storage = REVISION; return 1;
        case MUIA_Urltext_Version:  *msg->opg_Storage = (ULONG)VERSTAG+7;
    }

    return DoSuperMethodA(cl,obj,msg);
}

/***********************************************************************/

static ULONG ASM
mSets(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct opSet *msg)
{
    register struct data    *data = INST_DATA(cl,obj);
    register struct TagItem *tag;
    struct TagItem          *tstate;
    register ULONG          flags, redraw, notifyUrl, over;

    flags = data->flags;
    redraw = notifyUrl = over = 0;

    for (tstate = msg->ops_AttrList; tag = NextTagItem(&tstate); )
    {
        register ULONG tidata = tag->ti_Data;

        switch (tag->ti_Tag)
        {
            case MUIA_Urltext_MouseOver:
            {
                register ULONG isOver = UTFLG_IsMouseOver(flags);

                if (!UTFLG_IsToUse(flags) || (tidata && isOver) || (!tidata && !isOver))
                    tag->ti_Tag = TAG_IGNORE;
                else
                {
                    if (tidata)
                    {
                        flags |= UTFLG_MouseOver;
                        over = 1;
                    }
                    else flags &= ~UTFLG_MouseOver;
                    redraw = notifyUrl = 1;
                }
                break;
            }

            case MUIA_Urltext_Visited:
            {
                register ULONG isVisited = flags & UTFLG_Visited;

                if ((tidata && isVisited) || (!tidata && !isVisited))
                    tag->ti_Tag = TAG_IGNORE;
                else
                {
                    if (tidata) flags |= UTFLG_Visited;
                    else flags &= ~UTFLG_Visited;
                    redraw = 1;
                }
                break;
            }

            case MUIA_Disabled:
            {
                register ULONG isDisabled = UTFLG_IsDisabled(flags);

                if ((tidata && isDisabled) || (!tidata && !isDisabled))
                    tag->ti_Tag = TAG_IGNORE;
                else
                {
                    if (tidata) flags |= UTFLG_Disabled;
                    else flags &= ~UTFLG_Disabled;
                    redraw = 1;
                }
                break;
            }

            case MUIA_Urltext_MouseOutPen:
                if (data->mri)
                {
                    register LONG pen;

                    if ((pen = MUI_ObtainPen(data->mri,(struct MUI_PenSpec *)tidata,0))!=-1)
                    {
                        if (data->flags & UTFLG_FreeMouseOutPen) MUI_ReleasePen(data->mri,data->mouseOutPen);
                        data->mouseOutPen = pen;
                        data->flags |= UTFLG_FreeMouseOutPen;
                        redraw = 1;
                    }
                }
                break;

            case MUIA_Urltext_MouseOverPen:
                if (data->mri)
                {
                    register LONG pen;

                    if ((pen = MUI_ObtainPen(data->mri,(struct MUI_PenSpec *)tidata,0))!=-1)
                    {
                        if (data->flags & UTFLG_FreeMouseOverPen) MUI_ReleasePen(data->mri,data->mouseOverPen);
                        data->mouseOverPen = pen;
                        data->flags |= UTFLG_FreeMouseOverPen;
                        redraw = 1;
                    }
                }
                break;

            case MUIA_Urltext_VisitedPen:
                if (data->mri)
                {
                    register LONG pen;

                    if ((pen = MUI_ObtainPen(data->mri,(struct MUI_PenSpec *)tidata,0))!=-1)
                    {
                        if (data->flags & UTFLG_FreeVisitedPen) MUI_ReleasePen(data->mri,data->visitedPen);
                        data->flags |= UTFLG_FreeVisitedPen;
                        data->visitedPen = pen;
                        redraw = 1;
                    }
                }
                break;

            case MUIA_Urltext_PUnderline:
                if (tidata) flags |= UTFLG_Underline;
                else flags &= ~UTFLG_Underline;
                redraw = 1;
                break;

            case MUIA_Urltext_PDoVisitedPen:
                if (tidata) flags |= UTFLG_DoVisitedPen;
                else flags &= ~UTFLG_DoVisitedPen;
                redraw = 1;
                break;

            case MUIA_Urltext_PFallBack:
                if (tidata) flags |= UTFLG_Fallback;
                else flags &= ~UTFLG_Fallback;
                redraw = 1;
                break;
        }
    }

    data->flags = flags;

    if (redraw)
    {
        MUI_Redraw(obj,MADF_DRAWOBJECT);
        if (notifyUrl) SetSuperAttrs(cl,obj,MUIA_Urltext_Url,over ? data->url : NULL,TAG_DONE);
    }

    return DoSuperMethodA(cl,obj,msg);
}


/***********************************************************************/

static ASM ULONG
mSetup(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct MUIP_Setup *msg)
{
    register struct data        *data = INST_DATA(cl,obj);
    register struct TextFont    *df;
    register ULONG              flags = data->flags, v;
    ULONG                       p;

    if (!DoSuperMethodA(cl,obj,msg)) return FALSE;

    data->mri = msg->RenderInfo;

    data->mouseOutPen     = _pens(obj)[DEFAULT_MOUSEOUT_PEN];
    data->mouseOverPen    = _pens(obj)[DEFAULT_MOUSEOVER_PEN];
    data->visitedPen = _pens(obj)[DEFAULT_VISITED_PEN];
    data->textpen    = _pens(obj)[MPEN_TEXT];

    if (DoMethod(obj,MUIM_GetConfigItem,MUIA_Urltext_MouseOutPen,&p))
        set(obj,MUIA_Urltext_MouseOutPen,p);

    if (DoMethod(obj,MUIM_GetConfigItem,MUIA_Urltext_MouseOverPen,&p))
        set(obj,MUIA_Urltext_MouseOverPen,p);

    if (DoMethod(obj,MUIM_GetConfigItem,MUIA_Urltext_VisitedPen,&p))
        set(obj,MUIA_Urltext_VisitedPen,p);

    if (!(flags & UTFLG_UserDoVisitedPen))
    {
        if (DoMethod(obj,MUIM_GetConfigItem,MUIA_Urltext_DoVisitedPen,&p)) v = *(ULONG *)p;
        else v = DEFAULT_DOVISITEDPEN;

        if (v) data->flags |= UTFLG_DoVisitedPen;
        else data->flags &= ~UTFLG_DoVisitedPen;
    }

    if (!(flags & UTFLG_UserFallback))
    {
        if (DoMethod(obj,MUIM_GetConfigItem,MUIA_Urltext_FallBack,&p)) v = *(ULONG *)p;
        else v = DEFAULT_FALLBACK;

        if (v) data->flags |= UTFLG_Fallback;
        else data->flags &= ~UTFLG_Fallback;
    }

    if (!(flags & UTFLG_UserUnderline))
    {
        if (DoMethod(obj,MUIM_GetConfigItem,MUIA_Urltext_Underline,&p)) v = *(ULONG *)p;
        else v = DEFAULT_UNDERLINE;

        if (v) data->flags |= UTFLG_Underline;
        else data->flags &= ~UTFLG_Underline;
    }

    df = _font(obj);
    if (DoMethod(obj,MUIM_GetConfigItem,MUIA_Urltext_Font,&p))
    {
        register char   buf[256], *t, *s;
        struct TextAttr ta;
        long            ys;

        strcpy(buf,(STRPTR)p);

        if (t = strchr(buf,'/'))
        {
            *t++ = 0;
            if (!stcd_l(t,&ys) || ys<=0) ys = 8;
        }
        else ys = 8;

        for (s = NULL, t = buf; *t; t++) if (*t=='.') s = t;
        if (!s || stricmp(++s,"font")) strcat(buf,".font");

        ta.ta_Name  = buf;
        ta.ta_YSize = ys;
        ta.ta_Style = 0;
        ta.ta_Flags = 0;

        if (data->tf = OpenDiskFont(&ta)) data->flags |= UTFLG_CloseFont;
        else data->tf = df;
    }
    else data->tf = df;

    if (UTFLG_IsToUse(data->flags))
    {
        MUI_RequestIDCMP(obj,IDCMP_MOUSEMOVE);
        data->flags |= UTFLG_RejectIDCMP;
    }

    return TRUE;
}

/***********************************************************************/

static ASM ULONG
mCleanup(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct MUIP_Setup *msg)
{
    register struct data *data = INST_DATA(cl,obj);

    if (data->flags & UTFLG_RejectIDCMP) MUI_RejectIDCMP(obj,IDCMP_MOUSEMOVE);
    if (data->flags & UTFLG_CloseFont) CloseFont(data->tf);
    if (data->flags & UTFLG_FreeMouseOutPen) MUI_ReleasePen(data->mri,data->mouseOutPen);
    if (data->flags & UTFLG_FreeMouseOverPen) MUI_ReleasePen(data->mri,data->mouseOverPen);
    if (data->flags & UTFLG_FreeVisitedPen) MUI_ReleasePen(data->mri,data->visitedPen);

    data->mri = NULL;
    data->flags &= ~(UTFLG_RejectIDCMP | UTFLG_CloseFont | UTFLG_FreeMouseOutPen | UTFLG_FreeMouseOverPen | UTFLG_FreeVisitedPen);

    return DoSuperMethodA(cl,obj,msg);
}

/***********************************************************************/

static ASM ULONG
mAskMinMax(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct MUIP_AskMinMax *msg)
{
    register struct data    *data = INST_DATA(cl,obj);
    struct RastPort         rp;
    register WORD           w, h;

    DoSuperMethodA(cl,obj,msg);

    InitRastPort(&rp);
    SetFont(&rp,data->tf);
    TextExtent(&rp,data->text,data->tLen,&data->te);

    w = data->te.te_Width;
    h = data->te.te_Height;

    msg->MinMaxInfo->MinWidth  += w;
    msg->MinMaxInfo->MinHeight += h;
    msg->MinMaxInfo->DefWidth  += w;
    msg->MinMaxInfo->DefHeight += h;

    if (UTFLG_IsSetMax(data->flags))
    {
        msg->MinMaxInfo->MaxWidth  += w;
        msg->MinMaxInfo->MaxHeight += h;
    }
    else
    {
        msg->MinMaxInfo->MaxWidth  += MBQ_MUI_MAXMAX;
        msg->MinMaxInfo->MaxHeight += MBQ_MUI_MAXMAX;
    }

    return 0;
}

/***********************************************************************/

static ASM ULONG
mShow(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
    register struct data    *data = INST_DATA(cl,obj);
    register ULONG          res;

    if (res = DoSuperMethodA(cl,obj,msg)) data->flags |= UTFLG_Show;

    return res;
}

/***********************************************************************/

static ASM ULONG
mHide(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
    register struct data *data = INST_DATA(cl,obj);

    data->flags &= ~UTFLG_Show;

    return DoSuperMethodA(cl,obj,msg);
}

/***********************************************************************/

static ASM ULONG
mDraw(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct MUIP_Draw *msg)
{
    register struct data    *data = INST_DATA(cl,obj);
    register ULONG          flags = data->flags;

    DoSuperMethodA(cl,obj,msg);

    if (UTFLG_IsToShow(flags) && (msg->flags & MADF_DRAWOBJECT))
    {
        register struct RastPort    *rp = _rp(obj);
        register SHORT              l = _mtop(obj)-data->te.te_Extent.MinY;

        SetAPen(rp,
            (UTFLG_IsToUse(flags) && !UTFLG_IsDisabled(flags)) ?
                (UTFLG_IsMouseOver(flags) ?
                    MUIPEN(data->mouseOverPen) :
                    (UTFLG_IsVisited(flags) ?
                        MUIPEN(data->visitedPen) :
                        MUIPEN(data->mouseOutPen))) :
                data->textpen);

        SetFont(rp,data->tf);

        Move(rp,_mleft(obj),l);
        Text(rp,data->text,data->tLen);

        if (UTFLG_IsUnderline(flags))
        {
            Move(rp,_mleft(obj),++l);
            Draw(rp,_mleft(obj)+data->te.te_Extent.MaxX,l);
        }
    }

    return 0;
}

/***********************************************************************/

#define _between(a,x,b)         ((x)>=(a) && (x)<=(b))
#define _isinobject(data,x,y)   (_between(_mleft(obj),(x),UTFLG_IsSetMax(data->flags) ? _mright(obj) : _mleft(obj)+data->te.te_Width) && _between(_mtop(obj),(y),_mbottom(obj)))

static ASM ULONG
mHandleInput(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct MUIP_HandleInput *msg)
{
    register struct data *data = INST_DATA(cl,obj);

    if (msg->imsg && msg->imsg->Class==IDCMP_MOUSEMOVE)
        set(obj,MUIA_Urltext_MouseOver,_isinobject(data,msg->imsg->MouseX,msg->imsg->MouseY));

    return DoSuperMethodA(cl,obj,msg);
}

/***********************************************************************/

static ASM ULONG
mOpenURL(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct MUIP_Urltext_OpenURL *msg)
{
    register struct data    *data = INST_DATA(cl,obj);
    register STRPTR         url = data->url;
    register ULONG          flags = data->flags, res = 0;

    if (url && *url && OpenURLBase && !UTFLG_IsDisabled(flags) &&
        ((msg->flags & MUIV_Urltext_OpenURL_CheckOver) ? UTFLG_IsMouseOver(flags) : 1))
    {
        if (URL_Open(url,URL_NewWindow,TRUE,TAG_DONE))
        {
            res = 1;
            set(obj,MUIA_Urltext_Visited,1);
        }
    }

    return res;
}

/***********************************************************************/

static ASM ULONG
mCopy(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) struct MUIP_Urltext_Copy *msg)
{
    register struct data        *data = INST_DATA(cl,obj);
    register struct IFFHandle   *iff;
    register STRPTR             url = data->url;
    register ULONG              unit = msg->unit, res = 0, len;

    if (iff = AllocIFF())
    {
        if (iff->iff_Stream = (LONG)OpenClipboard(unit))
        {
            InitIFFasClip(iff);

            if (!OpenIFF(iff,IFFF_WRITE))
            {
                res = !PushChunk(iff,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN) &&
                      !PushChunk(iff,ID_FTXT,ID_CHRS,len = strlen(url)) &&
                      (WriteChunkBytes(iff,url,len)>=0) &&
                      !PopChunk(iff);

                CloseIFF(iff);
            }

            CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
        }

        FreeIFF(iff);
    }

    return res;
}

/***********************************************************************/

static ASM ULONG
mOpenURLPrefs(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
    register BPTR in, out;

    if ((in  = Open("NIL:",MODE_OLDFILE)) &&
        (out = Open("NIL:",MODE_OLDFILE)))
    {
        SystemTags("SYS:Prefs/OpenURL",
                    SYS_Asynch, TRUE,
                    SYS_Input, in,
                    SYS_Output, out,
                    NP_StackSize, 8192,
                    TAG_DONE);
        return 1;
    }

    if (in) Close(in);

    return 0;
}

/***********************************************************************/

static SAVEDS ASM ULONG
mccDispatcher(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
    switch(msg->MethodID)
    {
        case OM_NEW:                    return mNew(cl,obj,(APTR)msg);
        case OM_DISPOSE:                return mDispose(cl,obj,(APTR)msg);
        case OM_GET:                    return mGet(cl,obj,(APTR)msg);
        case OM_SET:                    return mSets(cl,obj,(APTR)msg);
        case MUIM_Setup:                return mSetup(cl,obj,(APTR)msg);
        case MUIM_Cleanup:              return mCleanup(cl,obj,(APTR)msg);
        case MUIM_AskMinMax:            return mAskMinMax(cl,obj,(APTR)msg);
        case MUIM_Show:                 return mShow(cl,obj,(APTR)msg);
        case MUIM_Hide:                 return mHide(cl,obj,(APTR)msg);
        case MUIM_HandleInput:          return mHandleInput(cl,obj,(APTR)msg);
        case MUIM_Draw:                 return mDraw(cl,obj,(APTR)msg);
        case MUIM_Urltext_OpenURL:      return mOpenURL(cl,obj,(APTR)msg);
        case MUIM_Urltext_Copy:         return mCopy(cl,obj,(APTR)msg);
        case MUIM_Urltext_OpenURLPrefs: return mOpenURLPrefs(cl,obj,(APTR)msg);
        default:                        return DoSuperMethodA(cl,obj,msg);
    }
}

/***********************************************************************/

BOOL ASM
initMCC(REG(a0) struct UrltextBase *base)
{
    return (BOOL)(base->mcc = MUI_CreateCustomClass((struct Library *)base,MUIC_Area,NULL,sizeof(struct data),mccDispatcher));
}

/***********************************************************************/
