// MPMorph - Amiga Morphing program
// Copyright (C) © 1993  Topicsave Limited

// This program 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 2 of the License, or
// any later version.

// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

// mpaddock@cix.compulink.co.uk

// include headers if not precompiled
#ifndef MPMORPH_AMIGA_H
#include "MPMorph-amiga.h"
#endif
#ifndef MPMORPH_H
#include "MPMorph.h"
#endif

LONG OldFrame;		// Previous frame number

/* Go to the first frame
 * the return value is that used by the main message loop
 */
int
FirstFrame(void) {
	OldFrame=FrameNumber;				// Store old frame
	FrameNumber = GetNumber(MPMorphGadgets[GDX_Start]);	// get starting frame
	if (FrameNumber != OldFrame) {	// if different
		return ReopenPictures();		// try and move to new frame
	}
	return 1;
}

/* Go to the previous frame
 * See FirstFrame()
 */
int
PrevFrame(void) {
	OldFrame=FrameNumber;
	if (FrameNumber > GetNumber(MPMorphGadgets[GDX_Start])) {
		--FrameNumber;	// previous frame
		return ReopenPictures();
	}
	return 1;
}

/* Go to the previous frame
 * See FirstFrame()
 */
int
GotoFrame(void) {
	OldFrame=FrameNumber;
	GetFrameNumber();	// Request frame number
	if (FrameNumber != OldFrame) {
		return ReopenPictures();
	}
	return 1;
}

/* Go to the next frame
 * See FirstFrame()
 */
int
NextFrame(void) {
	OldFrame=FrameNumber;	// next determine last frame number
	if (FrameNumber < (GetNumber(MPMorphGadgets[GDX_Start]) + GetNumber(MPMorphGadgets[GDX_Frames]) -1)) {
		++FrameNumber;
		return ReopenPictures();
	}
	return 1;
}

/* Go to the last frame
 * See NextFrame()
 */
int
LastFrame(void) {
	OldFrame=FrameNumber;
	FrameNumber = GetNumber(MPMorphGadgets[GDX_Start]) + GetNumber(MPMorphGadgets[GDX_Frames]) - 1;
	if (FrameNumber != OldFrame) {
		return ReopenPictures();
	}
	return 1;
}

/* Request frame number
 * returns TRUE if not cancelled
 * selected frame is stored in FrameNumber
 * This could use a nice sliding gadet requester - actually uses reqtools
 */
BOOL
GetFrameNumber(void) {
	struct MPGuiHandle *MPGuiHandle;
	char *res;
	LONG 	Frames, Start;			// Number of frames and starting frame
	BOOL ret;
	char *params[3];
	char param1[6];
	char param2[6];
	char param3[6];
	struct Hook Hook = {
		0
	};

	Frames = GetNumber(MPMorphGadgets[GDX_Frames]);	// Get frames and start frame
	Start = GetNumber(MPMorphGadgets[GDX_Start]);
	if (Frames > 1) {				// No point displaying requester if 0 or 1 frame
		// Determine Current frame number in correct range, using previously held value
		FrameNumber = max(Start,FrameNumber);
		FrameNumber = min(Start+Frames-1,FrameNumber);
		DisableWindows(DI_GetFrame);	// Disable all other windows
		sprintf(param1,"%ld",Start);
		sprintf(param2,"%ld",Start+Frames-1);
		sprintf(param3,"%ld",FrameNumber);
		params[0] = param1;
		params[1] = param2;
		params[2] = param3;
		Hook.h_Entry = (HOOKFUNC)HelpHook;

		if (MPGuiHandle = AllocMPGuiHandle(MPG_RELMOUSE,TRUE,
													MPG_PUBSCREENNAME,(ULONG)PubScreenName,
													MPG_HELP,(ULONG)&Hook,
													MPG_CHELP,GHelp,
													MPG_PARAMS,(ULONG)params,
													TAG_END)) {
			res = SyncMPGuiRequest(MyGetMsg(MSG_FRAMEGUI),MPGuiHandle);
			if (res) {
				if (res == (char *)-1) {
					Error(MyGetMsg(MSG_MPG),MyGetMsg(MSG_OK),MPGuiError(MPGuiHandle),HE_MPG);
					ret = FALSE;
				}
				else {
					FrameNumber = atoi(res);
					ret = TRUE;
				}
			}
			else {
				ret = FALSE;
			}
		}
		else {
			Error(MyGetMsg(MSG_MPG),MyGetMsg(MSG_OK),MyGetMsg(MSG_OUTOFMEM),HE_MPG);
			ret = FALSE;
		}
		EnableWindows();	// enable all the windows
	}
	else {
		if (!Frames) {	// number of frames = 0 so error
			Error(MyGetMsg(MSG_MUST1F),MyGetMsg(MSG_OK),NULL,HE_OneFrame);
			ret = FALSE;
		}
		else {			// number of frames = 1 so only one choice
			FrameNumber = Start;
			ret = TRUE;
		}
	}
	return (BOOL)ret;	// Cancel gadget is 0
}

/* Closes and reopens images using new frame (in FrameNumber)
 * the return value is that used by the main message loop
 */
int
ReopenPictures(void) {
	char buffer[257];	// Work buffer for points file name
	LONG KeepFrame;	// Temporary frame number
	if (!Saved) {		// if not saved then reset frame number and suggest user saves
	 KeepFrame = FrameNumber;
	 FrameNumber = OldFrame;
	 if (!SaveRequester()) {
	  return 1;			// user cancelled
	 }
	 FrameNumber = KeepFrame;	// either saved or abandoned so go to new frame
	}
	// Disable the windows and delete all the points
	DisableWindows(DI_NextFrame);
	DeleteAllPoints();
	// Try and reopen image one and two
	if (ReopenAPicture(GetString(MPMorphGadgets[GDX_FileOne]),&Pic1)) {
		if (ReopenAPicture(GetString(MPMorphGadgets[GDX_FileTwo]),&Pic2)) {
			// if ok then set up points filename and try and open
			strcpy(TempFilename,savedfilename);
			strcat(TempFilename,".%03ld");
			sprintf(buffer,TempFilename,FrameNumber);
			MyOpen(buffer,TRUE,FALSE);	// Note! do not complain if no points file for thisframe (yet)
			// enable the windows
			EnableWindows();
			// This is nasty!! (and probably unnecessary)
			// but CWTitle is already held as the screen title,
			// so do not want to be writing whilst intuition is reading
			// Probably better to just call SetWindowTitles twice (first time to nothing)
			// But that could cause the screen to flicker?
			Forbid();
			sprintf(CWTitle,MyGetMsg(MSG_MPMFRAME),FrameNumber);
			Permit();
			SetWindowTitles(ControlWindow,(UBYTE *)-1,CWTitle);
			return 1;	// It worked
		}
	}
	EnableWindows();
	return 3;			// It did not work, so windows are closed, but keep going
}

/* Opens an image in an (already) open window
 * This is all very convoluted stuff!
 * returns	: TRUE or FALSE for sucess failure
 * filename	: Name of file
 * pic		: pointer to a structure to hold all the stuff
 */
BOOL
ReopenAPicture(char *filename,struct Picture *pic) {

 char dirname[257];			// filename storage
 char *e 			= NULL;	// first part of error message
 char *e1 			= NULL;	// 2nd part of error message
 LONG hnum			= 0;		// Help number for error
 struct BitMap *OldBitMap = NULL;	// BitMap to keep
 UWORD OldWidth, OldHeight;

 // Set up new filename and display as screen title
 // window title is done later (does not sound good?)
 sprintf(dirname,filename,FrameNumber);
 Forbid();			// Forbid whilst change window title - Nasty!!
 strcpy(pic->filename,dirname);
 Permit();
 if (pic == &Pic1) {
	 OldWidth = Pic2.MPi->Width;
	 OldHeight = Pic2.MPi->Height;
 }
 else {
	 OldWidth = Pic1.MPi->Width;
	 OldHeight = Pic1.MPi->Height;
 }
 if (EGS) {
 	EGSReopenAPicture(dirname,pic,&e,&e1,&OldWidth,&OldHeight,&hnum);
 }
 else { // !EGS
  SetWindowTitles(pic->Win,(UBYTE *)-1,pic->filename);
  // if we do not allow zoom then the super bitmap is the actual bit map
  // so initialise so we do not lose it when we unload the brush
  if (!ZoomAllowed) {
   // Zero out current bitmap picture
   OldBitMap = pic->MPi->BitMap;
   pic->MPi->BitMap = NULL;
  }
  // Unload current frame (keeping bitmap)
  FreeMPImage(pic->MPi);
  // Try and load new brush - if this fails then flag error
  if (!(pic->MPi = LoadMPImage(dirname,pic->Screen,MPIF_CLONEBITMAP))) {
   // set up error stuff
   e = MyGetMsg(MSG_FAILLOAD);
   e1 = MPImageErrorMessage();
   hnum = HE_LoadImage;
  }
  if (!e) {
   // fail if frame is not the same size as previous
   if ((pic->MPi->Width != OldWidth) ||
      (pic->MPi->Height != OldHeight)) {
    if (!RescaleMPImage(pic->MPi,OldWidth,OldHeight)) {
	  e = MyGetMsg(MSG_MPIMAGESCALE);
	  e1 = MPImageErrorMessage();
     hnum = HE_MPIScale;
    }
   }
  }
  if (e) {
   // if no zoom allowed then reset the bitmap to the original - freeing the new one
   if (!ZoomAllowed) {
    if (pic->MPi) {
     if (pic->MPi->BitMap) {
 	   FreeBitMap(pic->MPi->BitMap);
	   pic->MPi->BitMap = NULL;
	  }
	  pic->BitMap = OldBitMap;		// Hack!!!
	 }
   }
  }
  else {
   SetWindowTitles(pic->Win,FilePart(pic->filename),pic->filename);	// This refreshes the titles
   if (ZoomAllowed) {
    // If we allow zoom then reset up BitScale stuff and scale or copy
	 pic->BitScaleArgs.bsa_SrcBitMap 	= pic->MPi->BitMap;
	 /* Either scale image 2x or straight copy	*/
	 if (Zoom) {
	  BitMapScale(&(pic->BitScaleArgs));
	 }
	 else {
	  BltBitMap(pic->MPi->BitMap,0,0,
	  				pic->BitMap,0,0,
	  				pic->MPi->Width,pic->MPi->Height,
	  				0xC0,0xff,NULL);
	 }
   }
	else {
	 // Zoom is not allowed - so copy the new bit map to the old bit map
	 BltBitMap(pic->MPi->BitMap,0,0,
	           OldBitMap,0,0,
				  pic->MPi->Width,pic->MPi->Height,
	   		  0xC0,0xff,NULL);
	 // free the new bit map and set the image back
	 FreeBitMap(pic->MPi->BitMap);
	 pic->MPi->BitMap = OldBitMap;
	 // All because we can not change the bitmap of a super bitmap window
	}
	// Resync the display to the new bitmap display
	LockLayerRom(pic->Win->RPort->Layer);
	CopySBitMap(pic->Win->RPort->Layer);
	UnlockLayerRom(pic->Win->RPort->Layer);
  }
 }
 // display error (if required) and return status
 if (e) {
  Error(e,MyGetMsg(MSG_OK),e1,hnum);
  return FALSE;
 }
 else {
  return TRUE;
 }
}
