/*----------------------------------------------------------------------*
   ibank.c Version 3.0 - © 1990-91 Jaba Development

   Author : Jan van den Baard
   Purpose: Image sharing (shorter source!)
 *----------------------------------------------------------------------*/
/*---------------------------------------------------*
  Gadgets created with GadgetEd V2.4
  which is (c) Copyright 1990-91 by Jaba Development
  written by Jan van den Baard
 *---------------------------------------------------*/

static SHORT Border0_pairs[] = {
  -1,-1,314,-1,314,196,-1,196,-1,-1 };
static SHORT Border1_pairs[] = {
  -1,-1,314,-1,314,10,-1,10,-1,-1 };
static SHORT Border2_pairs[] = {
  -1,-1,314,-1,314,14,-1,14,-1,-1 };

static struct Border Border_bord[] = {
  3,2,0,0,JAM1,5,(SHORT *)&Border0_pairs,&Border_bord[1],
  3,2,0,0,JAM1,5,(SHORT *)&Border1_pairs,&Border_bord[2],
  3,184,0,0,JAM1,5,(SHORT *)&Border2_pairs,NULL };

static struct IntuiText Render_text = {
  0,1,JAM1,112,3,NULL,(UBYTE *)"Image Bank",NULL };

static SHORT CNT_pairs0[] = {
  -1,-1,93,-1,93,9,-1,9,-1,-1 };

static struct Border CNT_bord = {
  0,0,0,0,JAM1,5,(SHORT *)&CNT_pairs0,NULL };

static struct IntuiText CNT_text = {
  0,1,JAM1,15,1,NULL,(UBYTE *)"CONTINUE",NULL };

#define CNT_ID       6

static struct Gadget CNT = {
  NULL,217,186,93,9,
  GADGHCOMP,
  RELVERIFY,
  BOOLGADGET,
  (APTR)&CNT_bord,NULL,
  &CNT_text,NULL,NULL,CNT_ID,NULL };

static SHORT CANCEL_pairs0[] = {
  -1,-1,58,-1,58,9,-1,9,-1,-1 };

static struct Border CANCEL_bord = {
  0,0,0,0,JAM1,5,(SHORT *)&CANCEL_pairs0,NULL };

static struct IntuiText CANCEL_text = {
  0,1,JAM1,3,1,NULL,(UBYTE *)"CANCEL",NULL };

#define CANCEL_ID    5

static struct Gadget CANCEL = {
  NULL,252,186,58,9,
  GADGHCOMP,
  RELVERIFY,
  BOOLGADGET,
  (APTR)&CANCEL_bord,NULL,
  &CANCEL_text,NULL,NULL,CANCEL_ID,NULL };

static SHORT OKIDOKI_pairs0[] = {
  -1,-1,25,-1,25,9,-1,9,-1,-1 };

static struct Border OKIDOKI_bord = {
  0,0,0,0,JAM1,5,(SHORT *)&OKIDOKI_pairs0,NULL };

static struct IntuiText OKIDOKI_text = {
  0,1,JAM1,4,1,NULL,(UBYTE *)"OK",NULL };

#define OKIDOKI_ID    4

static struct Gadget OKIDOKI = {
  &CANCEL,217,186,25,9,
  GADGHCOMP,
  RELVERIFY,
  BOOLGADGET,
  (APTR)&OKIDOKI_bord,NULL,
  &OKIDOKI_text,NULL,NULL,OKIDOKI_ID,NULL };

static SHORT PREV_pairs0[] = {
  -1,-1,39,-1,39,9,-1,9,-1,-1 };

static struct Border PREV_bord = {
  0,0,0,0,JAM1,5,(SHORT *)&PREV_pairs0,NULL };

static struct IntuiText PREV_text = {
  0,1,JAM1,3,1,NULL,(UBYTE *)"PREV",NULL };

#define PREV_ID    3

static struct Gadget PREV = {
  NULL,168,186,39,9,
  GADGHCOMP,
  RELVERIFY,
  BOOLGADGET,
  (APTR)&PREV_bord,NULL,
  &PREV_text,NULL,NULL,PREV_ID,NULL };

static SHORT NEXT_pairs0[] = {
  -1,-1,39,-1,39,9,-1,9,-1,-1 };

static struct Border NEXT_bord = {
  0,0,0,0,JAM1,5,(SHORT *)&NEXT_pairs0,NULL };

static struct IntuiText NEXT_text = {
  0,1,JAM1,4,1,NULL,(UBYTE *)"NEXT",NULL };

#define NEXT_ID    2

static struct Gadget NEXT = {
  &PREV,119,186,39,9,
  GADGHCOMP,
  RELVERIFY,
  BOOLGADGET,
  (APTR)&NEXT_bord,NULL,
  &NEXT_text,NULL,NULL,NEXT_ID,NULL };

static SHORT REM_pairs0[] = {
  -1,-1,54,-1,54,9,-1,9,-1,-1 };

static struct Border REM_bord = {
  0,0,0,0,JAM1,5,(SHORT *)&REM_pairs0,NULL };

static struct IntuiText REM_text = {
  0,1,JAM1,3,1,NULL,(UBYTE *)"Remove",NULL };

#define REM_ID    1

static struct Gadget REM = {
  &NEXT,56,186,54,9,
  GADGHCOMP,
  RELVERIFY,
  BOOLGADGET,
  (APTR)&REM_bord,NULL,
  &REM_text,NULL,NULL,REM_ID,NULL };

static SHORT LOAD_pairs0[] = {
  -1,-1,39,-1,39,9,-1,9,-1,-1 };

static struct Border LOAD_bord = {
  0,0,0,0,JAM1,5,(SHORT *)&LOAD_pairs0,NULL };

static struct IntuiText LOAD_text = {
  0,1,JAM1,3,1,NULL,(UBYTE *)"Load",NULL };

#define LOAD_ID    0

static struct Gadget LOAD = {
  &REM,7,186,39,9,
  GADGHCOMP,
  RELVERIFY,
  BOOLGADGET,
  (APTR)&LOAD_bord,NULL,
  &LOAD_text,NULL,NULL,LOAD_ID,NULL };

static struct NewWindow nw_ibank = {
  0,0,320,200,0,1,
  GADGETUP,
  NOCAREREFRESH+SMART_REFRESH+ACTIVATE+RMBTRAP+BORDERLESS,
  NULL,NULL,
  NULL,NULL,NULL,
  150,50,320,256,CUSTOMSCREEN };

/*
 * imported data.
 */
extern struct FileSelector *IODir;
extern struct Gadget       *Gadget;
extern struct Screen       *MainScreen;
extern struct MemoryChain   Memory;
extern struct SharedList    Images;
extern ULONG                Class;
extern USHORT               WDBackFill, BackFill;
extern BOOL                 REQUESTER, Saved, WBSCREEN;
extern UBYTE                name[256];
extern UWORD                Colors[32];

struct Window       *iwin;
struct Image        *active = NULL;
struct SharedImage  *freeit;

UWORD  old_colors[32];

/*
 * find the "SharedImage" from "image"
 */
struct SharedImage *get_sim( struct Image *image )
{
    struct SharedImage  *sim;

    for(sim = Images.Head; sim->Succ; sim = sim->Succ) {
        if(sim->Image == image)
            return(sim);
    }
    return(NULL);
}

/*
 * Add a user to the image
 */
void add_user( struct Image *image )
{
    struct SharedImage  *sim;

    if(NOT(sim = get_sim(image))) return;

    sim->UseCount++;
}

/*
 * Remove a user from the image.
 */
void rem_user( struct Image *image )
{
    struct SharedImage  *sim;

    if(NOT(sim = get_sim(image))) return;

    if(sim->UseCount) sim->UseCount--;
}

/*
 * Deallocate an image.
 */
void free_image( struct Image *image, long force )
{
    struct SharedImage  *sim;

    if(NOT force) {
        if(NOT(sim = get_sim(image))) return;
        Remove((void *)sim);
    } else
        sim = freeit;

    if(image->ImageData) FreeMem(image->ImageData,(ULONG)RASSIZE(image->Width,image->Height)*image->Depth);
    FreeItem(&Memory,image,(long)sizeof(struct Image));
    FreeItem(&Memory,sim,(long)sizeof(struct SharedImage));
}

/*
 * clear the image output field with the current background color.
 */
void clear_field( void )
{
    if(REQUESTER)
        SetAPen(iwin->RPort,BackFill);
    else
        SetAPen(iwin->RPort,WDBackFill);

    RectFill(iwin->RPort,3,13,317,182);
}

/*
 * Refresh the image bank window if it's damaged
 * by an image bigger than the output field.
 */
void refresh_ibank( void )
{
    SetAPen(iwin->RPort,1);
    RectFill(iwin->RPort,0,184,320,200);
    RectFill(iwin->RPort,318,0,320,200);
    DrawBorder(iwin->RPort,&Border_bord[0],0,0);
    PrintIText(iwin->RPort,&Render_text,0,0);
    RefreshGList(&LOAD,iwin,NULL,-1L);
    ShadowGList(iwin,&LOAD,NULL,0,-1L);
}

/*
 * draw the image in the output field.
 */
void display( void )
{
    struct SharedImage  *sim;

    clear_field();

    if(NOT(sim = get_sim(active))) return;

    if(active) {
        if(NOT WBSCREEN)
            LoadRGB4(&MainScreen->ViewPort,&sim->Colors[0],(1<<active->Depth));
        active->LeftEdge = active->TopEdge = 0;
        DrawImage(iwin->RPort,active,4,13);
    }
    refresh_ibank();
}

/*
 * display the previous image in the bank if available
 * otherwise flash the screen.
 */
void display_prev( void )
{
    struct SharedImage  *sim;

    if(NOT(sim = get_sim(active))) return;

    if((sim != Images.Head) AND sim) {
        active = sim->Pred->Image;
        display();
    } else
        DisplayBeep(MainScreen);
}

/*
 * display the next image in the bank if available
 * otherwise flash the screen.
 */
void display_next( void )
{
    struct SharedImage  *sim;

    if(NOT(sim = get_sim(active))) return;

    if((sim != Images.TailPred) AND sim) {
        active = sim->Succ->Image;
        display();
    } else
        DisplayBeep(MainScreen);
}

/*
 * deallocate all images from the image bank.
 */
void free_all( void )
{
    struct SharedImage *sim,*sim1;
    struct Image       *image;

    sim = Images.Head;

    while((sim = (struct SharedImage *)RemHead((void *)&Images))) {
        freeit = sim;
        free_image(sim->Image,TRUE);
    }

    NewList((void *)&Images);
}

/*
 * Check if an image with the "sum" checksum
 * is already in the bank.
 */
ULONG   check_sum( ULONG sum )
{
    register struct SharedImage *sim;

    for(sim = Images.Head; sim; sim = sim->Succ) {
        if(sim->CheckSum == sum)
            return(TRUE);
    }
    return(FALSE);
}

/*
 * load in an IFF brush in the image bank.
 */
void load_image( void )
{
    struct SharedImage  *sim;
    struct Image        *image, *ReadImage();
    UBYTE               *data;
    ULONG                ps, rc, i;

    strcpy((char *)IODir->fr_HeadLine,"Load IFF Image");

    IODir->fr_Screen = MainScreen;
    IODir->fr_Caller = iwin;
    IODir->fr_Flags |= FR_NoInfo;

    rc = FileRequest(IODir);

    strcpy((char *)&name,(char *)IODir->fr_DirName);
    strcat((char *)&name,(char *)IODir->fr_FileName);

    if(rc == FREQ_CANCELED) return;
    else if(rc) {
        Error("FileRequester Won't Open !");
        return;
    }

    Saved = FALSE;
    disable_window();
    if(NOT(image = ReadImage(name))) {
        enable_window();
        return;
    }

    if(NOT(sim = Alloc(&Memory,sizeof(struct SharedImage)))) {
        enable_window();
        Error("Out of memory !");
        return;
    }

    ReadCMAP(name,&sim->Colors[0]);

    sim->Image    = image;
    sim->UseCount = 0;
    sim->CheckSum = NULL;

    ps   = (ULONG)(RASSIZE(image->Width,image->Height) * image->Depth);
    data = (UBYTE *)image->ImageData;

    for(i = 0; i < ps; i++)
        sim->CheckSum += *(data++);

    if(check_sum(sim->CheckSum)) {
        enable_window();
        if(Ask("Image already in the bank!","Keep it ?") == FALSE) {
            freeit = sim;
            free_image(image,TRUE);
            disable_window();
            goto noShow;
        }
        disable_window();
    }
    AddTail((void *)&Images,(void *)sim);
    active        = image;
noShow:
    enable_window();
    display();
    return;
}

/*
 * remove a single image from the image bank.
 */
void remove_image( void )
{
    struct SharedImage  *sim;
    struct Image        *tofree = active;

    if(NOT(sim = get_sim(active))) return;

    if(sim->UseCount) {
        Error("Image still in use !");
        return;
    }

    if(sim) {
        if(sim->Pred != (struct SharedImage *)&Images)
            active = sim->Pred->Image;
        else if(sim->Succ)
            active = sim->Succ->Image;
        else
            active = NULL;
        free_image(tofree,FALSE);
    }
    display();
}

ULONG bank_account( struct Image *image )
{
    struct SharedImage  *sim;
    ULONG                i;

    for(sim = Images.Head, i = 0; sim->Succ; sim = sim->Succ, i++) {
        if(image == sim->Image)
            return(i);
    }
}

struct Image *withdraw( ULONG acount )
{
    struct SharedImage  *sim;
    ULONG                i;

    for(sim = Images.Head, i = 0; sim->Succ; sim = sim->Succ, i++) {
        if(i == acount)
            return(sim->Image);
    }
}

/*
 * put up the image bank main window.
 */
struct Image *image_bank( long get )
{
    BOOL            running = TRUE;
    UWORD           id,i;

    for(i = 0; i < 32; i++)
        old_colors[i] = (UWORD)GetRGB4(MainScreen->ViewPort.ColorMap,i);

    if(get)
        PREV.NextGadget = &OKIDOKI;
    else
        PREV.NextGadget = &CNT;

    nw_ibank.Screen = MainScreen;

    if(NOT(iwin = OpenWindow(&nw_ibank)))
        close_up("    - ERROR: Can't open the Image Bank !");

    draw(iwin,&LOAD,&Border_bord[0],&Render_text);

    display();

    while(running == TRUE) {
        Wait(1<<iwin->UserPort->mp_SigBit);
        while(read_msg(iwin)) {
            id = Gadget->GadgetID;
            if(Class == GADGETUP) {
                switch(id) {
                    case    LOAD_ID:
                                load_image();
                                break;
                    case    REM_ID:
                                remove_image();
                                break;
                    case    NEXT_ID:
                                display_next();
                                break;
                    case    PREV_ID:
                                display_prev();
                                break;
                    case    OKIDOKI_ID:
                                running = FALSE;
                                break;
                    case    CANCEL_ID:
                                running = FALSE;
                                break;
                    case    CNT_ID:
                                running = FALSE;
                                break;
                    default:
                                break;
                }
            }
        }
    }
    CloseWindow(iwin);

    if(id == OKIDOKI_ID) {
        if(NOT WBSCREEN) {
            if(NOT Ask("Do you want the Image colors set ?",NULL))
                LoadRGB4(&MainScreen->ViewPort,&old_colors[0],(1<<active->Depth));
        }
        return(active);
    } else if(id == CANCEL_ID) {
        if(NOT WBSCREEN)
            LoadRGB4(&MainScreen->ViewPort,&old_colors[0],(1<<active->Depth));
        refresh();
        return(NULL);
    }
    if(NOT WBSCREEN)
        LoadRGB4(&MainScreen->ViewPort,&old_colors[0],(1<<active->Depth));
}
