/* -----------------------------------------------------------------------------

 x.api ©1999 Dietmar Eilert

 Plug-in example. This plug-in opens a container and draws a "X". Dice:

 DMAKE

 -------------------------------------------------------------------------------

*/

#include "defs.h"

/// "prototypes"

// library functions

Prototype LibCall struct APIClient *APIMountClient(__A0 struct APIMessage *, __A1 char *);
Prototype LibCall void              APICloseClient(__A0 struct APIClient  *, __A1 struct APIMessage *);
Prototype LibCall void              APIBriefClient(__A0 struct APIClient  *, __A1 struct APIMessage *);
Prototype LibCall void              APIFree       (__A0 struct APIClient  *, __A1 struct APIOrder   *);

// private functions

Prototype ULONG DispatchContainer(struct APIClient *, struct APIMessage *);

///
/// "library functions"

LibCall struct APIClient *
APIMountClient(__A0 struct APIMessage *apiMsg, __A1 char *args)
{
    struct APIClient *apiClient;

    // fill out a description of this client

    if (apiClient = (struct APIClient *)AllocVec(sizeof(struct APIClient), MEMF_ANY | MEMF_CLEAR)) {

        if (apiClient->api_Area = (struct APIArea *)AllocVec(sizeof(struct APIArea), MEMF_ANY | MEMF_CLEAR)) {

            // client description

            apiClient->api_APIVersion = API_INTERFACE_VERSION;
            apiClient->api_Version    = 1;
            apiClient->api_Name       = "X";
            apiClient->api_Info       = "Plug-in example";
            apiClient->api_Commands   = NULL;
            apiClient->api_Serial     = 0;
            apiClient->api_Classes    = API_CLASS_SYSTEM | API_CLASS_CONTAINER;

            // prepare the container request

            apiClient->api_Area->api_Width     = 20;
            apiClient->api_Area->api_Height    = 5;
            apiClient->api_Area->api_UnitsX    = API_UNITS_FONT;
            apiClient->api_Area->api_UnitsY    = API_UNITS_FONT;
            apiClient->api_Area->api_Alignment = API_ALIGN_LEFT;
            apiClient->api_Area->api_Style     = API_STYLE_STANDARD;
            apiClient->api_Area->api_IDCMP     = 0;
        }
        else {

            FreeVec(apiClient);

            apiClient = NULL;
        }
    }

    return(apiClient);
}

LibCall void
APICloseClient(__A0 struct APIClient *handle, __A1 struct APIMessage *apiMsg)
{
    // free ressources related to this client

    FreeVec(handle->api_Area);

    FreeVec(handle);
}

LibCall void
APIBriefClient(__A0 struct APIClient *handle, __A1 struct APIMessage *apiMsg)
{
    struct APIMessage *msg;

    // handle host's command notify

    for (msg = apiMsg; msg; msg = msg->api_Next) {

        if (msg->api_State == API_STATE_NOTIFY) {

            switch (msg->api_Class) {

                case API_CLASS_CONTAINER:

                    msg->api_Error = DispatchContainer(handle, msg);

                    break;

                case API_CLASS_SYSTEM:

                    msg->api_Error = API_ERROR_OK;

                    break;

                default:

                    msg->api_Error = API_ERROR_UNKNOWN;
            }
        }
    }
}


LibCall void
APIFree(__A0 struct APIClient *handle, __A1 struct APIOrder *apiOrder)
{
    // no order-related ressources to be freed (this example doesn't send orders to the host)
}

///
/// "private functions"

/* ----------------------------- DispatchContainer -----------------------------

 Handle container-related event

*/

ULONG
DispatchContainer(handle, apiMsg)

struct APIClient  *handle;
struct APIMessage *apiMsg;
{
    ULONG error = API_ERROR_OK;

    switch (apiMsg->api_Action) {

        case API_ACTION_DETACH:

            // request to detach gadgets and stop asynchronous rendering because user is about to resize the window or the container (this example doesn't use gadgets)

            break;

        case API_ACTION_ATTACH:

            // request to attach gadgets after the container or window has been resized (this example doesn't use gadgets); avoid rendering at this point (API_ACTION_REFRESH will follow soon)

            break;

        case API_ACTION_REFRESH:

            // refresh the user interface: fall through to initial display refresh function

        case API_ACTION_PAINT:

            // we should render our display; this example simply draws a big "X"

            {
                struct APIInstance  *instance;
                struct APIContainer *container;

                instance = apiMsg->api_Instance;

                if (container = instance->api_Container) {

                    // container not fully obscured ?

                    if (container->api_Clipping) {

                        struct Region   *oldregion;
                        struct RastPort *rast;
                        UWORD            x0;
                        UWORD            y0;
                        UWORD            x1;
                        UWORD            y1;
                        BOOL             clipping;

                        oldregion = (struct Region *)~0;

                        // clipping required (rendering area smaller than container) ?

                        clipping = ((container->api_Clipping->MaxX != container->api_Dimensions->MaxX) || (container->api_Clipping->MaxY != container->api_Dimensions->MaxY));

                        // install clipping rectangle

                        if (clipping) {

                            struct Region *region;

                            if (region = NewRegion()) {

                                if (OrRectRegion(region, container->api_Clipping)) {

                                    oldregion = InstallClipRegion(instance->api_Window->WLayer, region);
                                }
                                else
                                    DisposeRegion(region);
                            }
                        }

                        // rendering

                        x0 = container->api_Dimensions->MinX;
                        y0 = container->api_Dimensions->MinY;
                        x1 = container->api_Dimensions->MaxX;
                        y1 = container->api_Dimensions->MaxY;

                        rast = container->api_RPort;

                        SetAPen(rast, container->api_DrawInfo->dri_Pens[SHADOWPEN]);

                        Move(rast, x0, y0);

                        Draw(rast, x1, y1);

                        Move(rast, x1, y0);

                        Draw(rast, x0, y1);

                        // remove clipping

                        if (oldregion != (struct Region *)~0) {

                            struct Region *region;

                            if (region = InstallClipRegion(instance->api_Window->WLayer, oldregion))

                                DisposeRegion(region);
                        }

                    }
                }
            }

            break;

        case API_ACTION_INPUTEVENT:

            // input event to be handled

            break;

        default:

            error = API_ERROR_UNKNOWN;
    }

    return(error);
}

///
