#ifndef _plan9_
#include <string.h>
#include <fconfig.h>
#include <assert.h>
#ifdef NO_MALLOC_H
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#include <stdio.h>
#else
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include <fconfig.h>
#endif
#include <filter.h>
void flipgeneric(struct image *img)
{
    pixel_t **line;
    assert(img->nimages == 2);
    img->currimage ^= 1;
    line = img->currlines;
    img->currlines = img->oldlines;
    img->oldlines = line;
}

int bytesperpixel(int type)
{
    switch (type) {
    case MBITMAP:
    case LBITMAP:
    case LIBITMAP:
    case MIBITMAP:
	return 0;
    case SMALLITER:
    case FIXEDCOLOR:
    case GRAYSCALE:
    case C256:
	return 1;
    case LARGEITER:
    case TRUECOLOR16:
	return 2;
    case TRUECOLOR24:
	return 3;
    case TRUECOLOR:
	return 4;
    default:
	assert(0);
	return 0;
    }
}

struct image *create_image_lines(int width, int height,
				 int nimages, pixel_t ** lines1,
				 pixel_t ** lines2,
				 struct palette *palette,
				 void (*flip) (struct image * img),
				 int flags, float pixelwidth,
				 float pixelheight)
{
    int i;
    static int version = 1;
    struct image *img = (struct image *) calloc(1, sizeof(*img));
    if (img == NULL)
	return NULL;
    if (flip == NULL)
	flip = flipgeneric;
    img->width = width;
    img->height = height;
    img->nimages = nimages;
    img->bytesperpixel = bytesperpixel(palette->type);
    img->palette = palette;
    img->currimage = 0;
    img->flip = flip;
    img->flags = flags;
    img->version = version;
    version += 65535;
    img->currlines = lines1;
    img->oldlines = lines2;
    img->pixelwidth = pixelwidth;
    img->pixelheight = pixelheight;
    if (lines1 != NULL && (nimages != 2 || lines2 != NULL)) {
	img->scanline = (int) (lines1[1] - lines1[0]);
	if (img->scanline < 0)
	    img->scanline = -1;
	else {
	    for (i = 0; i < height; i++) {
		if (lines1[0] - lines1[i] != img->scanline * i) {
		    img->scanline = -1;
		    break;
		}
		if (nimages == 2
		    && lines2[0] - lines2[i] != img->scanline * i) {
		    img->scanline = -1;
		    break;
		}
	    }
	}
    } else
	img->scanline = -1;
    return (img);
}

struct image *create_image_cont(int width, int height, int scanlinesize,
				int nimages, pixel_t * buf1,
				pixel_t * buf2, struct palette *palette,
				void (*flip) (struct image * img),
				int flags, float pixelwidth,
				float pixelheight)
{
    struct image *img =
	create_image_lines(width, height, nimages, NULL, NULL, palette,
			   flip,
			   flags, pixelwidth, pixelheight);
    int i;
    if (img == NULL) {
	return NULL;
    }
    if ((img->currlines =
	 (pixel_t **) malloc(sizeof(*img->currlines) * height)) == NULL) {
	free(img);
	return NULL;
    }
    if (nimages == 2) {
	if ((img->oldlines =
	     (pixel_t **) malloc(sizeof(*img->oldlines) * height)) == NULL)
	{
	    free(img->currlines);
	    free(img);
	    return NULL;
	}
    }
    for (i = 0; i < img->height; i++) {
	img->currlines[i] = buf1;
	buf1 += scanlinesize;
    }
    if (nimages == 2)
	for (i = 0; i < img->height; i++) {
	    img->oldlines[i] = buf2;
	    buf2 += scanlinesize;
	}
    img->flags |= FREELINES;
    img->scanline = scanlinesize;
    img->data = NULL;
    img->driver = NULL;
    return (img);
}

struct image *create_image_mem(int width, int height, int nimages,
			       struct palette *palette, float pixelwidth,
			       float pixelheight)
{
    unsigned char *data =
	(unsigned char *) calloc(((width + 3) & ~3) * height,
				 bytesperpixel(palette->type));
    unsigned char *data1 =
	(unsigned char *) (nimages ==
			   2 ? calloc(((width + 3) & ~3) * height,
				      bytesperpixel(palette->
						    type)) : NULL);
    struct image *img;
    if (data == NULL) {
#ifdef DEBUG
	printf("Image:out of memory\n");
#endif
	return (NULL);
    }
    if (nimages == 2 && data1 == NULL) {
	free(data);
#ifdef DEBUG
	printf("Image:out of memory2\n");
#endif
	return NULL;
    }
    img =
	create_image_cont(width, height,
			  ((width +
			    3) & ~3) * bytesperpixel(palette->type),
			  nimages, data, data1, palette, NULL, 0,
			  pixelwidth, pixelheight);
    if (img == NULL) {
	free(data);
	if (data1 != NULL)
	    free(data1);
	return NULL;
    }
    img->flags |= FREEDATA;
    return (img);
}

struct image *create_subimage(struct image *simg, int width, int height,
			      int nimages, struct palette *palette,
			      float pixelwidth, float pixelheight)
{
    int size = height * bytesperpixel(palette->type);
    int i;
    int shift1 = 0, shift2 = 0;
    struct image *img;
    if (size > simg->height * simg->bytesperpixel || height > simg->height
	|| (nimages == 2 && simg->nimages == 1))
	return (create_image_mem
		(width, height, nimages, palette, pixelwidth,
		 pixelheight));
    nimages = simg->nimages;
    img =
	create_image_lines(width, height, nimages, NULL, NULL, palette,
			   NULL, 0, pixelwidth, pixelheight);
    if (img == NULL)
	return NULL;
    if ((img->currlines =
	 (pixel_t **) malloc(sizeof(*img->currlines) * height)) == NULL) {
	free(img);
	return NULL;
    }
    if (nimages == 2) {
	if ((img->oldlines =
	     (pixel_t **) malloc(sizeof(*img->oldlines) * height)) == NULL)
	{
	    free(img->currlines);
	    free(img);
	    return NULL;
	}
    }
    shift1 = simg->height - img->height;
    shift2 =
	simg->width * simg->bytesperpixel -
	img->width * img->bytesperpixel;
    for (i = 0; i < img->height; i++) {
	img->currlines[i] = simg->currlines[i + shift1] + shift2;
    }
    if (nimages == 2)
	for (i = 0; i < img->height; i++) {
	    img->oldlines[i] = simg->oldlines[i + shift1] + shift2;
	}
    img->flags |= FREELINES;
    img->currimage = simg->currimage;
    return (img);
}

void destroy_image(struct image *img)
{
    if (img->flags & FREEDATA) {
	free(*img->currlines);
	if (img->nimages == 2)
	    free(*img->oldlines);
    }
    if (img->flags & FREELINES) {
	free(img->currlines);
	if (img->nimages == 2)
	    free(img->oldlines);
    }
    free(img);
}

void clear_image(struct image *img)
{
    int i;
    int color = img->palette->pixels[0];
    int width = img->width * img->bytesperpixel;
    if (img->palette->npreallocated)
	color = img->palette->index[0];
    if (!width) {
	width = (img->width + 7) / 8;
	if (color)
	    color = 255;
    }
    for (i = 0; i < img->height; i++)
	memset(img->currlines[i], color, width);
}
