//	Zinc Application Framework - M_IMAGE.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#if defined(_SUNOS4)
#include <z_stdlib.hpp>
#endif
#include <z_image.hpp>
#include <z_file.hpp>
#include <z_string.hpp>
#include <z_ctype.hpp>
#if !defined(_SUNOS4)
#include <z_stdlib.hpp>
#endif
#include "m_utils.hpp"
#include <xpm.h>

// ----- ZafImage -----------------------------------------------------------

void ZafImage::DestroyImageHandle(void)
{
	// Destroy the image handle.
	if (imageBuffer)
		XFreePixmap(((ZafScreenDisplay *)display)->xDisplay, imageBuffer);
	imageBuffer = 0;
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafImage::Draw(const ZafEventStruct &, ZafEventType ccode)
{
	// Check for draw errors.
	if (!screenID)
		return (S_ERROR);

	// Compute the actual draw region.
	ZafPaletteState state = PaletteState();
	ZafRegionStruct drawRegion = BeginDraw();

	// Draw the imageBuffer.
	OSDisplayContext xDisplay = XtDisplay(screenID);
	Drawable xDrawable = XtWindow(screenID);
	ZafPaletteStruct background = LogicalPalette(ZAF_PM_BACKGROUND, state);
	if (!imageBuffer)
	{
		display->SetPalette(background);
		display->Rectangle(drawRegion, 0, true);
	}
	else if (Tiled())
	{
		// Tile the imageBuffers.
		for (int row = drawRegion.top; row < drawRegion.bottom; row += height)
		{
			for (int column = drawRegion.left; column < drawRegion.right; column += width)
				XCopyArea(xDisplay, imageBuffer, xDrawable,
					background.osPalette, 0, 0, width, height, column, row);
		}
	}
	else if (Scaled())
		XCopyArea(xDisplay, imageBuffer, xDrawable, background.osPalette,
			0, 0, width, height, zafRegion.left, zafRegion.top);
	else
		XCopyArea(xDisplay, imageBuffer, xDrawable, background.osPalette,
			0, 0, width, height, drawRegion.left, drawRegion.top);
	
	// Return the control code.
	EndDraw();
	return (ccode);
}
#endif

ZafEventType ZafImage::Event(const ZafEventStruct &event)
{
	// Check for zinc events.
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	case S_COMPUTE_SIZE:
		// Defer to the base class.
		ccode = ZafWindowObject::Event(event);

		// Check for an auto-size button.
		if (!SupportObject() && AutoSize())
		{
			if (width == 0)
				width = 1;
			if (height == 0)
				height = 1;
			zafRegion.right = zafRegion.left + width - 1;
			zafRegion.bottom = zafRegion.top + height - 1;
		}
		break;

	case S_REGISTER_OBJECT:
		if (SystemObject() && !SupportObject())
			ccode = ZafWindowObject::Event(event);
		else if (parent && imageBuffer)
			XtVaSetValues(parent->OSScreenID(ZAF_CLIENTID), XmNbackgroundPixmap, imageBuffer, 0);
		break;

	// ----- Unknown or error messages -----
	default:
		ccode = ZafWindowObject::Event(event);
		break;
	}

	// Return the control code.
	return (ccode);
}

bool ZafImage::LoadImageFromApplication(void)
{
	// No motif system imageBuffers exist.
	return (imageBuffer ? true : false);
}

bool ZafImage::LoadImageFromFile(void)
{
	static ZafIChar _xbm[] = ZAF_ITEXT(".xbm");
	static ZafIChar _xpm[] = ZAF_ITEXT(".xpm");

	// Check for a valid file name.
	if (!pathName || !pathName[0])
		return (false);

	// Load the xbm or xpm bitmap.
	OSDisplayContext xDisplay = ((ZafScreenDisplay *)zafDisplay)->xDisplay;
	Drawable xDrawable = RootWindow(((ZafScreenDisplay *)zafDisplay)->xDisplay, ((ZafScreenDisplay *)zafDisplay)->xScreenNumber);
	if (strstr(pathName, _xbm))
	{
		int xHotReturn, yHotReturn;
		unsigned int twidth, theight;
		Pixmap tempImage; 
		char *osText = zafCodeSet->ConvertToOSString(pathName);
        if (XReadBitmapFile(xDisplay, xDrawable, osText,
			&twidth, &theight, &tempImage, &xHotReturn, &yHotReturn))
			error = ZAF_ERROR_FILE_READ;
		else
		{
			int pixDepth = XDefaultDepth(xDisplay, XDefaultScreen(xDisplay));	
			imageBuffer = XCreatePixmap(xDisplay, xDrawable, twidth, theight, 
				pixDepth);
			XCopyPlane(xDisplay, tempImage, imageBuffer, ((ZafScreenDisplay *)zafDisplay)->xGC,
				0, 0, twidth, theight, 0, 0, 1);
			error = ZAF_ERROR_NONE;
			width = twidth;
			height = theight;
		}
		delete []osText;
	}
	else
	{
		// Determine the proper file name.
		ZafIChar fileName[ZAF_MAXPATHLEN];
		strcpy(fileName, pathName);
		ZafIChar *extension = strrchr(fileName, '.');
		if (!extension)
			strcat(fileName, _xpm);

		// Load the image.
		XpmAttributes info;
		info.valuemask = XpmCloseness | XpmExactColors;
		info.closeness = 40000;
		info.exactColors = false;
		char *osText = zafCodeSet->ConvertToOSString(fileName);
		if (XpmReadFileToPixmap(xDisplay, xDrawable, osText,
			&imageBuffer, 0, &info))
			error = ZAF_ERROR_FILE_READ;
		else
		{
			error = ZAF_ERROR_NONE;
			width = info.width;
			height = info.height;
		}
		delete []osText;
	}

	// Return the status.
	return (imageBuffer ? true : false);
}

ZafError ZafImage::SetPathID(int newPathID)
{
	// Reset the pathID although not used in Motif.
	pathID = newPathID;
	return (ZAF_ERROR_NONE);
}

ZafError ZafImage::SetPathName(const ZafIChar *newPathName)
{
	// Reset the path name.
	if (pathName)
		delete pathName;
	pathName = newPathName ? strdup(newPathName) : ZAF_NULLP(ZafIChar);

	// Make sure image gets resized.
	if (!newPathName || *newPathName == 0)
		width = height = 0;

	// Re-read the image information.
	DestroyImageHandle();

	// Level 1 - Load the image from the application resources.
	if (!LoadImageFromApplication())

	// Level 2 - Load the image from the native file.
		if (!LoadImageFromFile())
			error = ZAF_ERROR_INVALID_NAME;

	// Update the image with Motif.
	if (SystemObject() && !SupportObject())
		RedisplayData();
	else if (parent && parent->screenID && imageBuffer)
		XtVaSetValues(parent->OSScreenID(ZAF_CLIENTID), XmNbackgroundPixmap, imageBuffer, 0);

	// Return the error status.
	return (Error());
}

// ----- OS Specific Functions ----------------------------------------------

ZafEventType ZafImage::OSEvent(const ZafEventStruct &)
{
	return (S_ERROR);
}

void ZafImage::OSRegisterObject(void)
{
	// Defer creation to the base class.
	ZafWindowObject::OSRegisterObject();

	// Add edit mode overrides.
	ZafEditModeRegister(this);
}

