/*
 *  FILE: copystuff.c
 *  Support routines for copying (mainly intuition-type) structures.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Oct-88	Jan Sven Trabandt   split from intuistuff.c
 *				    added more functions
 */


#define I_AM_COPYSTUFF
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/copystuff.h"
#include "gimmelib/intuistuff.h"
#define GIM_BUILTIN
#include "gimmelib/macros.h"


short copyDataImage( data, image )
    USHORT  *data;
    register struct Image   *image;
{
    register struct Image   *ip;
    ULONG   size;		    /* image datasize (bytes) for copying */
    UBYTE   *idata, *srcdata;	    /* UBYTE makes additions easier */

#ifdef GIMME_WIMPY
    if( !data || !image || !image->ImageData ) {
	return( -1 );
    }
#endif
    size = GIM_IMAGESIZE(image->Depth, image->Width, image->Height);
    if( size > 0x07fffL ) {
	idata = (UBYTE *) image->ImageData;
	srcdata = (UBYTE *) data;
	for( ; size > 0L; size -= 0x07fffL ) {
	    movmem( srcdata, idata, (int)(size & 0x07fffL) );
	    srcdata += 0x07fffL;
	    idata += 0x07fffL;
	} /* for */
    } else {
	movmem( data, image->ImageData, (int) size );
    }
    return( 0 );
} /* copyDataImage */


short copyImageData( image, data )
    register struct Image   *image;
    USHORT  *data;
{
    register struct Image   *ip;
    ULONG   size;		    /* image datasize (bytes) for copying */
    UBYTE   *idata, *destdata;	    /* UBYTE makes additions easier */

#ifdef GIMME_WIMPY
    if( !data || !image || !image->ImageData ) {
	return( -1 );
    }
#endif
    size = GIM_IMAGESIZE(image->Depth, image->Width, image->Height);
    if( size > 0x07fffL ) {
	idata = (UBYTE *) image->ImageData;
	destdata = (UBYTE *) data;
	for( ; size > 0L; size -= 0x07fffL ) {
	    movmem( idata, destdata, (int)(size & 0x07fffL) );
	    idata += 0x07fffL;
	    destdata += 0x07fffL;
	} /* for */
    } else {
	movmem( image->ImageData, data, (int) size );
    }
    return( 0 );
} /* copyImageData */


struct Border *copyBorder( mh, oldbp, numbord, myflags )
    void    **mh;
    register struct Border  *oldbp;
    SHORT   numbord;
    ULONG   myflags;
{
    register struct Border  *bp;
    struct Border	    *retbp, *temp;
    ULONG		    size;
    void		    *mymh = NULL;

#ifdef GIMME_WIMPY
    if( !mh ) {
	return( NULL );
    }
#endif
    retbp = bp = NULL;
    for( ; oldbp && numbord != 0; oldbp = oldbp->NextBorder, --numbord ) {
	if( !(temp = chainAllocMem(&mymh, (ULONG)sizeof(struct Border),
				    MEMF_PUBLIC)) ) {
	    if( !(myflags & GCP_SALVAGE) ) {
		chainFreeMem( mymh );
		retbp = NULL;
	    }
	    return( retbp );
	}
	if( !bp ) {
	    retbp = temp;
	} else {
	    bp->NextBorder = temp;
	}
	bp = temp;
	*bp = *oldbp;	    /* struct copy */
	if( oldbp->XY && !(myflags & GCP_NOT_POINTS) ) {
	    size = sizeof(SHORT) * 2L  * bp->Count;
	    if( !(bp->XY = chainAllocMem(&mymh, size, MEMF_PUBLIC)) ) {
		if( !(myflags & GCP_SALVAGE) ) {
		    chainFreeMem( mymh );
		    return( NULL );
		} else {
		    bp->Count = 0;
		}
	    } else {
		movmem( oldbp->XY, bp->XY, (int)size );
	    }
	}
    } /* for */
    linkChainMem( mh, mymh );
    return( retbp );
} /* copyBorder */


struct Image *copyImage( mh, oldip, numimage, myflags )
    void    **mh;
    register struct Image   *oldip;
    SHORT   numimage;
    ULONG   myflags;
{
    register struct Image   *ip;
    struct Image	    *retip, *temp;
    ULONG		    size;
    void		    *mymh = NULL;

#ifdef GIMME_WIMPY
    if( !mh ) {
	return( NULL );
    }
#endif
    retip = ip = NULL;
    for( ; oldip && numimage != 0; oldip = oldip->NextImage, --numimage ) {
	if( !(temp = chainAllocMem(&mymh, (ULONG)sizeof(struct Image),
				    MEMF_PUBLIC)) ) {
	    if( !(myflags & GCP_SALVAGE) ) {
		chainFreeMem( mymh );
		retip = NULL;
	    }
	    return( retip );
	}
	if( !ip ) {
	    retip = temp;
	} else {
	    ip->NextImage = temp;
	}
	ip = temp;
	*ip = *oldip;	    /* struct copy */
	if( oldip->ImageData && !(myflags & GCP_NOT_BYTES) ) {
	    size = GIM_IMAGESIZE(ip->Depth, ip->Width, ip->Height);
	    if( !(ip->ImageData = chainAllocMem(&mymh, size, MEMF_PUBLIC)) ) {
		if( !(myflags & GCP_SALVAGE) ) {
		    chainFreeMem( mymh );
		    return( NULL );
		}
	    } else {
		copyImageData( oldip, ip->ImageData );
	    }
	}
    } /* for */
    linkChainMem( mh, mymh );
    return( retip );
} /* copyImage */


struct IntuiText *copyIntuiText( mh, otext, numitext, myflags )
    void    **mh;
    register struct IntuiText	*otext;
    SHORT   numitext;
    ULONG   myflags;
{
    register struct IntuiText	*itext;
    struct IntuiText		*retitext, *temp;
    ULONG			size;
    void			*mymh = NULL;

#ifdef GIMME_WIMPY
    if( !mh ) {
	return( NULL );
    }
#endif
    retitext = itext = NULL;
    for( ; otext && numitext != 0; otext = otext->NextText, --numitext ) {
	if( !(temp = chainAllocMem(&mymh, (ULONG)sizeof(struct IntuiText),
				    MEMF_PUBLIC)) ) {
	    if( !(myflags & GCP_SALVAGE) ) {
		chainFreeMem( mymh );
		retitext = NULL;
	    }
	    return( retitext );
	}
	if( !itext ) {
	    retitext = temp;
	} else {
	    itext->NextText = temp;
	}
	itext = temp;
	*itext = *otext;       /* struct copy */
	if( otext->IText && !(myflags & GCP_NOT_STRING) ) {
	    size = strlen( otext->IText );
	    if( !(itext->IText = chainAllocMem(&mymh, size, MEMF_PUBLIC)) ) {
		if( !(myflags & GCP_SALVAGE) ) {
		    chainFreeMem( mymh );
		    return( NULL );
		}
	    } else {
		/* strcpy( itext->IText, otext->IText ); */
		movmem( otext->IText, itext->IText, (int) size + 1 );
	    }
	}
	if( otext->ITextFont && !(myflags & GCP_NOT_TEXTATTR) ) {
	    if( !(itext->ITextFont = chainAllocMem(&mymh,
			(ULONG)sizeof(struct TextAttr), MEMF_PUBLIC)) ) {
		if( !(myflags & GCP_SALVAGE) ) {
		    chainFreeMem( mymh );
		    return( NULL );
		}
	    } else {
		*itext->ITextFont = *otext->ITextFont;	    /* struct copy */
	    }
	}
    } /* for */
    linkChainMem( mh, mymh );
    return( retitext );
} /* copyIntuiText */


struct MenuItem *copyMenuItem( mhptr, olditem, numitem, numsub, myflags )
    void			**mhptr;
    register struct MenuItem	*olditem;
    SHORT			numitem, numsub;
    ULONG			myflags;
{
    register struct MenuItem	*item, *temp;
    struct MenuItem		*menuitem = NULL;
    APTR			(*copyfunc)();
    void			*mymh = NULL;

#ifdef GIMME_WIMPY
    if( !mhptr ) {
	return( NULL );
    }
#endif
    item = NULL;
    for( ; olditem && numitem != 0; olditem = olditem->NextItem ) {
	if( !(temp = chainAllocMem(&mymh, (ULONG)sizeof(struct MenuItem),
					    MEMF_PUBLIC)) ) {
	    chainFreeMem( mymh );
	    return( NULL );
	}
	if( !item ) {
	    menuitem = temp;
	} else {
	    item->NextItem = temp;
	}
	item = temp;
	*item = *olditem;	/* struct copy */
	if( !(myflags & GCP_NOT_STRUCTS) ) {
	    if( item->Flags & ITEMTEXT ) {
		(APTR) copyfunc = (APTR) copyIntuiText;
	    } else {
		(APTR) copyfunc = (APTR) copyImage;
	    }
	    if( olditem->ItemFill ) {
		if( !(item->ItemFill = copyfunc(&mymh, olditem->ItemFill,
					    -1, myflags)) ) {
		    chainFreeMem( mymh );
		    return( NULL );
		}
	    }
	    if( (item->Flags & HIGHIMAGE) && olditem->SelectFill ) {
		if( !(item->SelectFill = copyfunc(&mymh, olditem->SelectFill,
					    -1, 0L)) ) {
		    chainFreeMem( mymh );
		    return( NULL );
		}
	    }
	}
	if( numsub != 0 && olditem->SubItem ) {
	    if( !(item->SubItem = copyMenuItem(&mymh,
					olditem->SubItem, numsub, 0)) ) {
		chainFreeMem( mymh );
		return( NULL );
	    }
	} else {
	    item->SubItem = NULL;
	}
    } /* for */
    item->NextItem = NULL;
    if( mymh ) {
	linkChainMem( mhptr, mymh );
    }
    return( menuitem );
} /* copyMenuItem */


struct Menu *copyMenu( mhptr, oldmenu, nummenu, numitem, numsub, myflags )
    void		    **mhptr;
    register struct Menu    *oldmenu;
    SHORT		    nummenu, numitem, numsub;
    ULONG		    myflags;
{
    register struct Menu	*menu, *temp;
    struct Menu 		*menustrip = NULL;
    ULONG			size;
    void			*mymh = NULL;

#ifdef GIMME_WIMPY
    if( !mhptr ) {
	return( NULL );
    }
#endif
    menu = NULL;
    for( ; oldmenu && nummenu != 0; oldmenu = oldmenu->NextMenu, --nummenu ) {
	if( !(temp = chainAllocMem(&mymh, (ULONG)sizeof(struct Menu),
				    MEMF_PUBLIC)) ) {
	    chainFreeMem( mymh );
	    return( NULL );
	}
	if( !menu ) {
	    menustrip = temp;
	} else {
	    menu->NextMenu = temp;
	}
	menu = temp;
	*menu = *oldmenu;	/* struct copy */
	if( menu->MenuName && !(myflags & GCP_NOT_STRING) ) {
	    size = strlen( oldmenu->MenuName );
	    if( !(menu->MenuName = chainAllocMem(&mymh, size, MEMF_PUBLIC)) ) {
		if( !(myflags & GCP_SALVAGE) ) {
		    chainFreeMem( mymh );
		    return( NULL );
		}
	    } else {
		/* strcpy( menu->MenuName, oldmenu->MenuName ); */
		movmem( oldmenu->MenuName, menu->MenuName, (int) size + 1 );
	    }
	}
	if( numitem != 0 && oldmenu->FirstItem ) {
	    if( !(menu->FirstItem = copyMenuItem(&mymh,
			    oldmenu->FirstItem, numitem, numsub, myflags)) ) {
		chainFreeMem( mymh );
		return( NULL );
	    }
	} else {
	    menu->FirstItem = NULL;
	}
    } /* for */
    menu->NextMenu = NULL;
    if( mymh ) {
	linkChainMem( mhptr, mymh );
    }
    return( menustrip );
} /* copyMenu */
