#import "../ImageSave.h"
#import <appkit/NXImage.h>
#import <appkit/SavePanel.h>
#import <stdio.h>
#import <libc.h>
#import <string.h>
#import "../ToyView.h"
#import "../ToyWin.h"
#import "../ColorMap.h"
#import "../strfunc.h"
#import "../common.h"
#import "save.h"
#import "GifSavePanel.h"

#define  MANY_COLORS	(-1)	/* must be < 0 */


@implementation ImageSave (SaveGIF)

/* Local Method */
- (char *)getSaveIntlName: (const char *)path
		ext: (const char *)ex interlace: (BOOL *)intp
{
	GifSavePanel *savePanel;
	char	*stmp, *sav = NULL;

	stmp = [ImageSave mk_tmpname:path ext:ex nopath:YES];
	savePanel = [[GifSavePanel new] loadNib];
	if ([savePanel runModalForDirectory: saveDir file: stmp]) {
		sav = [ImageSave mk_tmpname:
				[savePanel filename] ext:ex nopath:NO];
		if (sav == NULL || *sav == 0)
			return NULL;
		strcpy(saveDir, [savePanel directory]);
		*intp = [savePanel interlace];
	}
	return sav;
}


- (int)getPalette:(ColorMap *)colormap info:(commonInfo *)cinf
	map:(unsigned char **)map needAlpha:(BOOL)alflag err:(int *)code
{
	int cnum, err;
	BOOL hasalpha;

	err = 0;
	if (cinf->palette != NULL) {
		if ([colormap allocPalColor] == nil) {
			err = Err_MEMORY;
			goto EXIT;
		}
		cnum = [colormap regPalColorWithAlpha: alflag];
		if (cnum > FIXcount)
			err = MANY_COLORS;
		goto EXIT;
	}

	if ([colormap allocFullColor] == nil) {
		err = Err_MEMORY;
		goto EXIT;
	}
	cnum = alflag
		? [colormap getAllColor:map limit:FIXcount alpha:&hasalpha]
		: [colormap getAllColor:map limit:FIXcount];
	if (hasalpha) ++cnum;
	if (cnum > FIXcount)
		err = MANY_COLORS;
	else {
		(void)[colormap getNormalmap: &cnum];
		cinf->palette = [colormap getPalette];
		cinf->palsteps = cnum;
	}
EXIT:
	if (err) {
		*code = err;
		return 0;
	}
	return cinf->palsteps;
}


- (char *)saveAsGif: (char *)gifname
{
	char	*sav, *result = NULL;
	commonInfo *cinf;
	ColorMap *colormap = nil;
	unsigned char *map[MAXPLANE];
	int	cnum, err;
	static BOOL	interl = NO;

	cinf = [toyView commonInfo];
	if (cinf->cspace == NX_CMYKColorSpace) {
		warnAlert([toyWin filename], Err_SAV_IMPL);
		return NULL;
	}

	if (gifname) /* Called after reduction */
		sav = gifname;
	else {
		sav = [self getSaveIntlName: [toyWin filename]
				ext: "gif" interlace: &interl];
		if (sav == NULL) /* canceled */
			return NULL;
	}

	if ((err = [toyWin getBitmap:map info: &cinf]) != 0)
		goto EXIT;
	if ((err = initGetPixel(cinf)) != 0)
		goto EXIT;

	colormap = [[ColorMap alloc] init];
	cnum = [self getPalette:colormap
		info:cinf map:map needAlpha:YES err:&err];
	if (cnum == 0) {
		const char *ask, *cancel, *reduce;
		if (err != MANY_COLORS)
			goto EXIT;
		ask = NXLocalizedString(
				"Reduction Start", NULL, GIF_Reduction);
		cancel = NXLocalizedString("Cancel", NULL, Stop_SAVE);
		reduce = NXLocalizedString("Reduce", NULL, BMP_Reduce);
		if (NXRunAlertPanel("", ask, reduce, cancel, NULL))
			result = sav; /* Save after reduction */
		goto EXIT;
	}

	if (!err) {
		FILE	*fp;
		int	transp;

		transp = (cinf->alpha && cinf->palette) ? cinf->palsteps : -1;
		if ((fp = fopen(sav, "w")) == NULL) {
			errAlert(sav, Err_SAVE);
			[colormap free];
			[toyWin freeTempBitmap];
			return NULL;	// Don't goto EXIT.
		}
		GIFEncode(fp, cinf, map, cnum, transp, interl, cinf->palette);
		(void)fclose(fp);
		[toyWin resetFilename:sav];
	}

EXIT:
	if (colormap) [colormap free];
	[toyWin freeTempBitmap];
	if (err) {
		errAlert(sav, err);
		(void)unlink(sav);
	}
	/* result != NULL  -->  This method is called again after Reduction */
	return result;
}


- saveAsPng: sender
{
	commonInfo *cinf;
	commonInfo copyinf;
	FILE	*fp;
	ColorMap *colormap = nil;
	char	*sav;
	unsigned char *map[MAXPLANE];
	int	err;
	static BOOL	interl = NO;

	cinf = [toyView commonInfo];
	if (cinf->cspace == NX_CMYKColorSpace) {
		warnAlert([toyWin filename], Err_SAV_IMPL);
		return NULL;
	}
	if ((sav = [self getSaveIntlName: [toyWin filename]
		ext: "png" interlace: &interl]) == NULL) /* canceled */
		return NULL;
	if ((fp = fopen(sav, "w")) == NULL) {
		errAlert(sav, Err_SAVE);
		return self;
	}
	err = [toyWin getBitmap:map info: &cinf];
	if (!err) err = initGetPixel(cinf);
	if (err) goto EXIT;
	if (cinf->cspace != NX_RGBColorSpace) { /* Monochrome */
		copyinf = *cinf;
		copyinf.palette = NULL;	/* No need to allocate palette */
		copyinf.palsteps = 0;
		cinf = &copyinf;
	}else {
		colormap = [[ColorMap alloc] init];
		(void) [self getPalette:colormap
			info:cinf map:map needAlpha:YES err:&err];
		err = 0;	/* Error is ignored */
	}
	resetPixel(map, 0);
	pngwrite(fp, cinf, appDir, interl);
	/* fp is closed in pngwrite */
EXIT:
	if (colormap) [colormap free];
	[toyWin freeTempBitmap];
	if (err) {
		errAlert(sav, err);
		(void)unlink(sav);
	}else
		[toyWin resetFilename:sav];
	return self;
}

@end
