#include "stdafx.h"
//#include "p4win.h"
#include "ImageList.h"
#include "P4Image.h"
#include "resource.h"

///////////////////////////////////////////////////////////////////////////
// CP4ToolBarImageList 

bool CP4WinToolBarImageList::Create()
{
	return CP4ToolBarImageList::Create(18, 16, 
		IDB_TOOLBAR4, IDB_BITMAPDIS, IDB_TOOLBAR32,
		RGB(255, 0, 255));
}

///////////////////////////////////////////////////////////////////////////
// CP4ViewIconsImageList 

// SrcImages represents the actual images in TreeIcons?.bmp
// it must be kept in sync with the bitmap.

// note: for built up images, base images are mixed in with badges, 
// but must precede badge images so that they will be drawn first 
// and badges drawn on top of them

enum SrcImages
{
	SI_LAST_SIMPLE = 19,

	// base images
	SI_CLIENT,
	SI_USER,
	SI_GHOST,
	SI_TEXT,
	SI_BINARY,

	// badge images
	SI_RED_DOC_BORDER,
	SI_YOUR_EDIT,
	SI_YOUR_DELETE,
	SI_YOUR_ADD,
	SI_THEIR_ADD,
	SI_THEIR_EDIT,
	SI_THEIR_DELETE,
	SI_YOUR_LOCK,
	SI_THEIR_LOCK,
	SI_SYNCED,
	SI_NOT_SYNCED,
	SI_CUR,
	SI_DEF,
	SI_BLANK,

	// more simple images
	SI_OPENFOLDER,
};

// convert from CUSB enum flag to image index
static int CUSBToImage(int badge)
{
	static int map[][2] =
	{
		{CP4ViewImageList::CUSB_USER, SI_USER},
		{CP4ViewImageList::CUSB_CLIENT, SI_CLIENT},
		{CP4ViewImageList::CUSB_DEF,	SI_DEF},
		{CP4ViewImageList::CUSB_CUR, SI_CUR},
		{-1,-1}
	};

	for(int i = 0; map[i][0] != -1; i++)
		if(map[i][0] == badge)
			return map[i][1];
	ASSERT(0);
	return 0;
}

// convert from FSB enum flag to image index
static int FSBToImage(int badge)
{
	static int map[][2] =
	{
		{CP4ViewImageList::FSB_GHOST,		SI_GHOST},
		{CP4ViewImageList::FSB_TEXT,		SI_TEXT},
		{CP4ViewImageList::FSB_BINARY,		SI_BINARY},
		{CP4ViewImageList::FSB_YOUR_EDIT,	SI_YOUR_EDIT},
		{CP4ViewImageList::FSB_YOUR_DELETE,	SI_YOUR_DELETE},
		{CP4ViewImageList::FSB_YOUR_ADD,	SI_YOUR_ADD},
		{CP4ViewImageList::FSB_THEIR_EDIT,	SI_THEIR_EDIT},
		{CP4ViewImageList::FSB_THEIR_DELETE,SI_THEIR_DELETE},
		{CP4ViewImageList::FSB_THEIR_ADD,	SI_THEIR_ADD},
		{CP4ViewImageList::FSB_YOUR_LOCK,	SI_YOUR_LOCK},
		{CP4ViewImageList::FSB_THEIR_LOCK,	SI_THEIR_LOCK},
		{CP4ViewImageList::FSB_SYNCED,		SI_SYNCED},
		{CP4ViewImageList::FSB_NOT_SYNCED,	SI_NOT_SYNCED},
		{-1,-1}
	};

	for(int i = 0; map[i][0] != -1; i++)
		if(map[i][0] == badge)
			return map[i][1];
	ASSERT(0);
	return 0;
}

// lookup tables for finding an icon given it's state mask
static unsigned short fileMap[2 << CP4ViewImageList::FSB_NUM_BITS];
static unsigned short cuMap[2 << CP4ViewImageList::CUSB_NUM_BITS];

// return composite image index for client/user (CUSB) state flags
int CP4ViewImageList::GetCUIndex(int state)
{
	int result = cuMap[state];
	ASSERT(result);	// illegal combination state bits
	return result;
}

// return image index for client with specified attributes
int CP4ViewImageList::GetClientIndex(bool isCurrent, bool isDefault)
{
	return GetCUIndex(CUSB_CLIENT |
		(isDefault ? CUSB_DEF : 0) |
		(isCurrent ? CUSB_CUR : 0));
}

// return image index for user with specified attributes
int CP4ViewImageList::GetUserIndex(bool isCurrent, bool isDefault)
{
	return GetCUIndex(CUSB_USER |
		(isDefault ? CUSB_DEF : 0) |
		(isCurrent ? CUSB_CUR : 0));
}

// return composite image index for file state (FSB) flags
int CP4ViewImageList::GetFileIndex(int state)
{
	int result = fileMap[state];
	ASSERT(result);	// illegal combination state bits
	return result;
}

// create a composite client or user image
static void AddCUImage(CP4Image &dst, CP4Image &src, int &x, int layers)
{
	ASSERT(layers);
	ASSERT(x/24 < 0x10000);
	cuMap[layers] = (unsigned short)(x / 24);
	int mask = 1;
	while(layers)
	{
		if(layers & 1)
		{
			int img = CUSBToImage(mask);
			dst.BlendImage(x/24, src, img);
		}
		layers >>= 1;
		mask <<= 1;
	}
	x += 24;
}

// create a composite file image
static void AddFileImage(CP4Image &dst, CP4Image &src, int &x, int layers)
{
	ASSERT(layers);
	ASSERT(x/24 < 0x10000);
	fileMap[layers] = (unsigned short)(x / 24);
	bool red = (layers & CP4ViewImageList::FSB_YOUR_ADD) && 
		(layers & CP4ViewImageList::FSB_THEIR_ADD);
	int mask = 1;
	while(layers)
	{
		if(layers & 1)
		{
			int img = FSBToImage(mask);
			dst.BlendImage(x/24, src, img);
			// special case to get red border when you're not the
			// only one to have a file open for add
			if(red)
				dst.BlendImage(x/24, src, SI_RED_DOC_BORDER);
			red = false;
		}
		layers >>= 1;
		mask <<= 1;
	}
	x += 24;
}

// add a group of file images with non-add actions

static void AddFileImageSync(CP4Image &dst, CP4Image &src, int &x, int base)
{
	AddFileImage(dst, src, x, base);
	AddFileImage(dst, src, x, base | CP4ViewImageList::FSB_SYNCED);
	AddFileImage(dst, src, x, base | CP4ViewImageList::FSB_NOT_SYNCED);
}

static void AddFileImageLock(CP4Image &dst, CP4Image &src, int &x, int base)
{
	AddFileImageSync(dst, src, x, base);
	AddFileImageSync(dst, src, x, base | CP4ViewImageList::FSB_YOUR_LOCK);
	AddFileImageSync(dst, src, x, base | CP4ViewImageList::FSB_THEIR_LOCK);
}

static void AddFileImageTheirAction(CP4Image &dst, CP4Image &src, int &x, int base)
{
	AddFileImageLock(dst, src, x, base);
	AddFileImageLock(dst, src, x, base | CP4ViewImageList::FSB_THEIR_DELETE);
	AddFileImageLock(dst, src, x, base | CP4ViewImageList::FSB_THEIR_ADD);
	AddFileImageLock(dst, src, x, base | CP4ViewImageList::FSB_THEIR_EDIT);
}

static void AddFileImageYourAction(CP4Image &dst, CP4Image &src, int &x, int base)
{
	AddFileImageTheirAction(dst, src, x, base);
	AddFileImageTheirAction(dst, src, x, base | CP4ViewImageList::FSB_YOUR_DELETE);
	AddFileImageTheirAction(dst, src, x, base | CP4ViewImageList::FSB_YOUR_ADD);
	AddFileImageTheirAction(dst, src, x, base | CP4ViewImageList::FSB_YOUR_EDIT);
}

static void AddFileImageType(CP4Image &dst, CP4Image &src, int &x, int base)
{
	AddFileImageYourAction(dst, src, x, base | CP4ViewImageList::FSB_BINARY);
	AddFileImageYourAction(dst, src, x, base | CP4ViewImageList::FSB_TEXT);
}

// create the bitmap containing both simple and composite images
void CP4ViewImageList::MakeBitmap(CP4Image &dst, CP4Image &src, COLORREF bg)
{
	// first, set the whole thing to the background color
	dst.FillImage(bg);

	// next, just copy over the first segment of simple images
	int i;
	for(i = 0; i <= SI_LAST_SIMPLE; i++)
		dst.BlendImage(i, src, i);

	// add open folder icon
	dst.BlendImage(i++, src, SI_OPENFOLDER);

	// create the unresolved pending chglist ones
	dst.BlendImage(i,   src, CP4ViewImageList::VI_YOURCHANGE);
	dst.BlendImage(i++, src, SI_NOT_SYNCED);
	dst.BlendImage(i,   src, CP4ViewImageList::VI_YOUROTHERCHANGE);
	dst.BlendImage(i++, src, SI_NOT_SYNCED);

	int x = i * 24;

	// copy client, plus badges
	AddCUImage(dst, src, x, CUSB_CLIENT);
	AddCUImage(dst, src, x, CUSB_CLIENT | CUSB_CUR);
	AddCUImage(dst, src, x, CUSB_CLIENT | CUSB_DEF);
	AddCUImage(dst, src, x, CUSB_CLIENT | CUSB_CUR | CUSB_DEF);

	// copy user, plus badges
	AddCUImage(dst, src, x, CUSB_USER);
	AddCUImage(dst, src, x, CUSB_USER | CUSB_CUR);
	AddCUImage(dst, src, x, CUSB_USER | CUSB_DEF);
	AddCUImage(dst, src, x, CUSB_USER | CUSB_CUR | CUSB_DEF);

	// create all file images except the wierd one
	AddFileImageType(dst, src, x, 0);

	// create the wierd file one
	AddFileImage(dst, src, x, FSB_GHOST | FSB_SYNCED);
}

bool CP4ViewImageList::Create()
{
	// determine width required for bitmap
	int w = 24 * 
		(SI_LAST_SIMPLE + 1 +	// simple (non-composite) images
		4 +			// user + cur/def
		4 +			// client + cur/def
		2 *			// file types: binary, text
		4 *			// your action: none, add, edit, delete
		4 *			// their action: none, add, edit, delete
		3 *			// lock states: none, yours, theirs
		3 +			// sync states: none, synced, not synced
		1 +			// wierd ghost combo
		1 +			// open folder
		2 );		// 2 unresolved pending chglists

	CDC dc;
	dc.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
	m_colorDepth = dc.GetDeviceCaps(BITSPIXEL);
	if (m_colorDepth >= 16 && !m_use256ColorIcons)
	{
		// at least 16-bit color, so create a device dependent bitmap
		// using 32-bit rgba source bitmap
		if(!CImageList::Create(24, 16, ILC_COLOR32|ILC_MASK, 5, 0))
			return false;


		CP4ImageDib src(24);
		CP4ImageDib dst(24);
		if(src.Load(IDB_VIEWICONS32))
		{
			src.PreMultiplyAlpha();
			dst.Create(w, 16);

			MakeBitmap(dst, src, GetSysColor(COLOR_WINDOW));
			CBitmap *bmp = dst.CreateDDB(dc);
			if(bmp)
				Add(bmp, GetSysColor(COLOR_WINDOW));
			return true;
		}
		// something didn't work out, so fall through and use 16 colors
	}

	// 256 or fewer colors device, so use 16 color bitmap
	if(!CImageList::Create(24, 16, ILC_COLOR4|ILC_MASK, 5, 0))
		return false;

	// use magenta for background; it will be transparent
	// (using non-transparent COLOR_WINDOW background fails 
	// sometimes in 256 color mode)
	COLORREF magenta = RGB(255,0,255);
	CP4Image16 src(magenta, 24);
	CP4Image16 dst(magenta, 24);
	if(src.Load(IDB_VIEWICONS4) && dst.Create(dc, w, 16))
	{
		src.StartBlendingSource();
		dst.StartBlendingDest(dc);

		MakeBitmap(dst, src, magenta);

		dst.EndBlendingDest();
		src.EndBlendingSource();

		CBitmap *bmp = dst.CreateDDB(dc);
		if(bmp)
			Add(bmp, magenta);
		m_colorDepth = 4;
		return true;
	}
	return false;
}