/* Copyright 2008 Jeffrey Lee
   This file is part of Pale.
   Pale is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
   Pale is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with Pale.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "preview.h"
#include "sprfile.h"
#include "editor.h"

//DEPPEND

static int xzoom(preview *p,int w)
{
	int zoom = p->zoom;
	zoom += xeig;
	if (zoom >= 0)
		return w << zoom;
	return w >> -zoom;
}

static int yzoom(preview *p,int h)
{
	int zoom = p->zoom;
	zoom += yeig;
	if (zoom >= 0)
		return h << zoom;
	return h >> -zoom;
}

static void getcoord(preview *p,int *x,int *y)
{
	if(p->zoom+xeig >= 0)
		*x = *x >> (p->zoom+xeig);
	else
		*x = *x << (p->zoom+xeig);
	if(p->zoom+yeig >= 0)
		*y = *y >> (p->zoom+yeig);
	else
		*y = *y << (p->zoom+yeig);
	regs.r[0] = 40+512;
	regs.r[1] = (int) p->file->sprs;
	regs.r[2] = (int) p->spr;
	_kernel_swi(OS_SpriteOp,&regs,&regs);
	if(*x < 0)
		*x = 0;
	else if(*x >= regs.r[3])
		*x = regs.r[3]-1;
	*y += regs.r[4];
	if(*y < 0)
		*y = 0;
	else if(*y >= regs.r[4])
		*y = regs.r[4]-1;
}

static int readpixel(preview *p,int x,int y)
{
	regs.r[0] = 41+512;
	regs.r[1] = (int) p->file->sprs;
	regs.r[2] = (int) p->spr;
	regs.r[3] = x;
	regs.r[4] = y;
	_kernel_swi(OS_SpriteOp,&regs,&regs);
	return regs.r[5] | regs.r[6];
}

static void writepixel(preview *p,int x,int y,int i)
{
	regs.r[0] = 42+512;
	regs.r[1] = (int) p->file->sprs;
	regs.r[2] = (int) p->spr;
	regs.r[3] = x;
	regs.r[4] = y;
	regs.r[5] = i;
	regs.r[6] = 0;
	_kernel_swi(OS_SpriteOp,&regs,&regs);
}

char *preview_getspritename(preview *p)
{
	static char name[16];
	strncpy(name,((char *) (p->spr))+4,12);
	name[12] = 0;
	return name;
}

void preview_redrawonzoom(preview *p)
{
	/* Calculate sprite size in OS units */
	regs.r[0] = 40+512;
	regs.r[1] = (int) p->file->sprs;
	regs.r[2] = (int) p->spr;
	_kernel_swi(OS_SpriteOp,&regs,&regs);
	LimpX_SetExtent(p->win,0,yzoom(p,-regs.r[4]),xzoom(p,regs.r[3]),0);
	limpx_window_state ws;
	ws = LimpX_GetWindowState(p->win);
	ws.vmaxx = ws.vminx+xzoom(p,regs.r[3]);
	ws.vminy = ws.vmaxy-yzoom(p,regs.r[4]);
	LimpX_OpenWindowAt(p->win,ws);
	/* Does the extent match the size we just set it to? */
	ws = LimpX_GetWindowState(p->win);
	if((ws.vmaxx-ws.vminx > xzoom(p,regs.r[3])) || (ws.vmaxy-ws.vminy > yzoom(p,regs.r[4])))
		LimpX_SetWindow_WorkBack(p->win,0);
	else
		LimpX_SetWindow_WorkBack(p->win,0xFF);
	LimpX_ForceRedraw(p->win,0,-30000,30000,0);
}

preview *preview_create1(sprfile *s,void *spr,paleditor *e)
{
	preview *p;
	p = malloc(sizeof(preview));
	p->spr = spr;
	p->win = LimpX_CreateWindow(temp_sprite);
	p->file = s;
	p->pal = e;
	p->zoom = 0;
	p->next = s->previews;
	p->prev = 0;
	if(s->previews)
		s->previews->prev = p;
	s->previews = p;
	/* Set window title, resize, open window */
	char name[16];
	memcpy(name,&(((int *) spr)[1]),12);
	name[12] = 0;
	LimpX_SetWindow_Title(p->win,name);
	preview_redrawonzoom(p);
	LimpX_OpenWindow(p->win);
	return p;
}

void preview_close(paleditor *e,void *spr)
{
	/* Close any matching preview windows */
	preview *p,*pp;
	p = e->file->previews;
	while(p)
	{
		pp = p->next;
		if((p->pal == e) && (p->spr == spr))
			preview_close2(p);
		p = pp;
	}
}

void preview_close2(preview *p)
{
	LimpX_DeleteWindow(p->win);
	if(p->prev)
		p->prev->next = p->next;
	else
		p->file->previews = p->next;
	if(p->next)
		p->next->prev = p->prev;
	free(p);
}

void preview_redraw(preview *p,limpx_redraw_obj *r,int first)
{
	static int scale_factors[4];
	rgb *highlight = 0;
	if((p->pal) && (p->pal->highlight != -1))
	{
		highlight = sprfile_getpalette(p->spr);
		highlight = &highlight[p->pal->highlight*2];
		highlight->r ^= 128;
		highlight->g ^= 128;
		highlight->b ^= 128;
	}
	if(first)
	{
		if (p->zoom >= 0)
		{
			scale_factors[0] = scale_factors[1] = 1 << p->zoom;
			scale_factors[2] = scale_factors[3] = 1;
		}
		else
		{
			scale_factors[0] = scale_factors[1] = 1;
			scale_factors[2] = scale_factors[3] = 1 << (-p->zoom);
		}
	}
	/* Draw sprite */
	regs.r[0] = 52+512;
	regs.r[1] = (int) p->file->sprs;
	regs.r[2] = (int) p->spr;
	regs.r[3] = r->vminx-r->scrollx;
	regs.r[4] = (r->vmaxy-r->scrolly)-yzoom(p,((int *) p->spr)[5]+1);
	regs.r[5] = 16;
	regs.r[6] = (int) scale_factors;
	regs.r[7] = 0;
	_kernel_swi(OS_SpriteOp,&regs,&regs);
	if(highlight)
	{
		highlight->r ^= 128;
		highlight->g ^= 128;
		highlight->b ^= 128;
	}
}

void open_preview_menu(preview *p,limpx_mouse_obj *m)
{
	if(p->zoom == ZOOM_MAX)
		LimpX_SetMenuItem_IconFlags(menu_sprite,menu_sprite_zin,0x7400021);
	else
		LimpX_SetMenuItem_IconFlags(menu_sprite,menu_sprite_zin,0x7000021);
	if(p->zoom == ZOOM_MIN)
		LimpX_SetMenuItem_IconFlags(menu_sprite,menu_sprite_zout,0x7400021);
	else
		LimpX_SetMenuItem_IconFlags(menu_sprite,menu_sprite_zout,0x7000021);
	LimpX_UpdateMenuBlock(menu_sprite);
	open_menu = MENU_SPRITE;
	open_menu_preview = p;
	LimpX_CreateMenu(menu_sprite,m->x-64,m->y+12);
}

void preview_updatehint(preview *p,limpx_mouse_obj *m)
{
	limpx_window_state ws;
	int x,y;
	if(!p->pal)
		return;
	/* First, check for doodling (mouse click events don't happen often enough for us to use those) */
	if(m->buttons & 0x4)
		preview_doodle(p,m);
	/* Now update the hint */
	ws = LimpX_GetWindowState(p->win);
	x = ws.scrollx+m->x-ws.vminx;
	y = ws.scrolly+m->y-ws.vmaxy;
	getcoord(p,&x,&y);
	char help[64];
	sprintf(help,"%d,%d #%d",x,y,readpixel(p,x,y));
	if(strcmp(help,LimpX_GetIcon_Text(LimpX_IconFromWindow(p->pal->palwin,PALICON_HINT))))
	{
		LimpX_SetIcon_Text(LimpX_IconFromWindow(p->pal->palwin,PALICON_HINT),help);
		LimpX_RedrawIcon(LimpX_IconFromWindow(p->pal->palwin,PALICON_HINT));
	}
}

void preview_doodle(preview *p,limpx_mouse_obj *m)
{
	limpx_window_state ws;
	int x,y;
	if(!p->pal)
		return;
	ws = LimpX_GetWindowState(p->win);
	x = ws.scrollx+m->x-ws.vminx;
	y = ws.scrolly+m->y-ws.vmaxy;
	getcoord(p,&x,&y);
	writepixel(p,x,y,p->pal->selstart);
	if(!p->file->modified)
	{
		p->file->modified = 1;
		sprfile_updatetitle(p->file);
	}
	/* Redraw area */
	y = ((int *) p->spr)[5]-y;
	preview *pp;
	pp = p->file->previews;
	while(pp)
	{
		if(pp->spr == p->spr)
			LimpX_ForceRedraw(pp->win,xzoom(pp,x),-yzoom(pp,y+1),xzoom(pp,x+1),-yzoom(pp,y));
		pp = pp->next;
	}
}

void preview_selectcolour(preview *p,limpx_mouse_obj *m)
{
	limpx_window_state ws;
	int x,y;
	if(!p->pal)
		return;
	ws = LimpX_GetWindowState(p->win);
	x = ws.scrollx+m->x-ws.vminx;
	y = ws.scrolly+m->y-ws.vmaxy;
	getcoord(p,&x,&y);
	editor_redrawentries(p->pal,p->pal->selstart,p->pal->selend);
	p->pal->selstart = readpixel(p,x,y);
	p->pal->selend = p->pal->selstart+1;
	editor_redrawentry(p->pal,p->pal->selstart);
}

void preview_redrawall(preview *p)
{
	LimpX_ForceRedraw(p->win,0,-30000,30000,0);
}
