//	Pro_Utils.c

#ifndef __GNUC__
	#include "Types.h"
#endif

#include "String.h"
#include "ctype.h"
#include "stdio.h"
#include "IC_Errors.h"
#include "CCopyTree.h"
#include "IC_FileIO.h"
#include "Pro_Utils.h"

/****************************************************
	Volume/File name
*/

short		Pro_GetNameLength(Pro_TypeName *typeName)
{
	short	nameLenS = typeName->stnl.nameLength;
	
	if (nameLenS == 0) {
		for (nameLenS = Pro_kNameLength; nameLenS; nameLenS--) {
			if (typeName->name[nameLenS - 1] != 0) {
				break;
			}
		}
	}
	
	return nameLenS;
}

char	 *Pro_GetEntryName(
	Pro_TypeName *typeName, ushort locaseBits, char *buf)
{
	short	loop;
	short	nameLenS = Pro_GetNameLength(typeName);
	
	memcpy(buf, typeName->name, nameLenS);
	buf[nameLenS] = 0;
	
	//	and what the heck is 0x23 about??
	if (
		locaseBits 
		&& locaseBits != 0x0023
		&& (locaseBits & Pro_kUseLocaseBits) != 0	//	hi bit must be set (see tn.gsos.008)
	) for (loop = 0; loop < nameLenS; loop++) {
		 if (locaseBits & (1 << (14 - loop))) {
			if (buf[loop] == '.') {
				buf[loop] = ' ';
			} else if (buf[loop] >= 'A' && buf[loop] <= 'Z') {
				buf[loop] = tolower(buf[loop]);
			}
		}
	}
	
	return buf;
}

char		*Pro_GetDirName(Pro_DirHeader *dirHeader, char *buf)
{
	return Pro_GetEntryName(&dirHeader->typeName, GetRboShort(dirHeader->locaseBits), buf);
}

char		*Pro_GetFileName(Pro_DirEntry *dirEntry, char *buf)
{
	ushort	locaseBits;
	
	if (
		dirEntry->fileType == Pro_FileType_AWP
		|| dirEntry->fileType == Pro_FileType_AWS
		|| dirEntry->fileType == Pro_FileType_AWD
	) {
		locaseBits = *(ushort *)&dirEntry->auxType;
		locaseBits = (locaseBits >> 1) | Pro_kUseLocaseBits;
	} else {
		locaseBits = GetRboShort(dirEntry->locaseBits);
	}
	
	return Pro_GetEntryName(&dirEntry->typeName, locaseBits, buf);
}

/**************************************************/
void	 Pro_SetEntryName(
	Pro_TypeName *typeName, ushort *locaseBits, char *buf)
{
	short		loop;	
	Boolean		lower;
	ulong		nameLen = strlen(buf);
	
	*locaseBits = Pro_kUseLocaseBits;
	
	if (nameLen < 1) {
		nameLen = 1;
	} else if (nameLen > Pro_kNameLength) {
		nameLen = Pro_kNameLength;
	}

	typeName->stnl.nameLength = nameLen;

	memclr(typeName->name, Pro_kNameLength);
	memcpy(typeName->name, buf, typeName->stnl.nameLength);
	
	if (typeName->name[0] >= '0' && typeName->name[0] <= '9') {
		typeName->name[0] = 'A';	//	first char must be letter
	}

	for (loop = 0; loop < typeName->stnl.nameLength; loop++) {
		lower = FALSE;
		
		if (typeName->name[loop] == ' ') {
			lower = TRUE;
			typeName->name[loop] = '.';
		} else if (typeName->name[loop] >= 'a' && typeName->name[loop] <= 'z') {
			lower = TRUE;
			typeName->name[loop] = (char)toupper(typeName->name[loop]);
		}
		
		if (!(
			(typeName->name[loop] >= 'A' && typeName->name[loop] <= 'Z')
			|| (typeName->name[loop] >= '0' && typeName->name[loop] <= '9')
			|| (typeName->name[loop] == '.'))
		) {
			typeName->name[loop] = '.';	//	illegal chars become '.'
		}
		
		if (lower) {
			*locaseBits = (ushort)(*locaseBits | (1 << (14 - loop)));
		}
	}
}

void		Pro_SetDirName(Pro_DirHeader *dirHeader, char *buf)
{
	ushort	locaseBits;
	
	Pro_SetEntryName(&dirHeader->typeName, &locaseBits, buf);
	dirHeader->locaseBits = SetRboShort(locaseBits);
}

void		Pro_SetFileName(Pro_DirEntry *dirEntry, char *buf)
{
	ushort	locaseBits;
	
	Pro_SetEntryName(&dirEntry->typeName, &locaseBits, buf);

	if (
		dirEntry->fileType == Pro_FileType_AWP
		|| dirEntry->fileType == Pro_FileType_AWS
		|| dirEntry->fileType == Pro_FileType_AWD
	) {
		locaseBits <<= 1;
		dirEntry->auxType = *(RboShort *)&locaseBits;
	} else {
		dirEntry->locaseBits = SetRboShort(locaseBits);
	}
}
/****************************************************
	Date and Time
*/

DateTimeRec		*Pro_GetDateTime(Pro_DateTime *pro_dtP, DateTimeRec *mac_dtP)
{
	Pro_DateTimeMem		dateTimeMem;
	
	dateTimeMem.split.ymd 	= GetRboShort(pro_dtP->ymd);
	dateTimeMem.split.hm	= GetRboShort(pro_dtP->hm);
	
	//	so it works for null dates
	if (dateTimeMem.dt.month != 0) {
		dateTimeMem.dt.month--;
	}

	mac_dtP->year		= 1900 + dateTimeMem.dt.year;
	
	//	see "The Definition" TechNote.pdos.028
	if (mac_dtP->year < 1940) {
		mac_dtP->year += 100;
	}
	
	mac_dtP->month		= dateTimeMem.dt.month + 1;
	mac_dtP->day		= dateTimeMem.dt.day;
	mac_dtP->hour		= dateTimeMem.dt.hour;
	mac_dtP->minute		= dateTimeMem.dt.minute;
	mac_dtP->second		= 0;
	mac_dtP->dayOfWeek	= 0;

	return mac_dtP;
}

void		Pro_GetDateStamps(
	Pro_DirEntry	*dirEntry, 
	DateTimeRec		*creDate, 
	DateTimeRec		*modDate)
{
	Pro_GetDateTime(&dirEntry->createdTime, creDate);
	Pro_GetDateTime(&dirEntry->modifiedTime, modDate);
}

void		Pro_SetDateTime(DateTimeRec *mac_dtP, Pro_DateTime *pro_dtP)
{
	DateTimeRec		macDateTime;
	Pro_DateTimeMem	dateTimeMem;
	
	dateTimeMem.dt.unused1 = 0;
	dateTimeMem.dt.unused2 = 0;
	
	macDateTime = *mac_dtP;

	while (macDateTime.year > 1000) {
		macDateTime.year -= 1000;
	}

	while (macDateTime.year > 100) {
		macDateTime.year -= 100;
	}

	dateTimeMem.dt.year		= macDateTime.year;
	dateTimeMem.dt.month	= macDateTime.month;
	dateTimeMem.dt.day		= macDateTime.day;
	dateTimeMem.dt.hour		= macDateTime.hour;
	dateTimeMem.dt.minute	= macDateTime.minute;
	
	pro_dtP->ymd	= SetRboShort(dateTimeMem.split.ymd);
	pro_dtP->hm		= SetRboShort(dateTimeMem.split.hm);
}

void		Pro_SetDateStamps(
	Pro_DirEntry	*dirEntry, 
	DateTimeRec		*creDate, 
	DateTimeRec		*modDate)
{
	Pro_SetDateTime(creDate, &dirEntry->createdTime);
	Pro_SetDateTime(modDate, &dirEntry->modifiedTime);
}

/**********************************************/
Pro_BlockNum		Pro_GetBlocksUsed(Pro_DirEntry *entryP)
{
	ulong			eofL		= GetRbo3Bytes(entryP->eof);
	Pro_BlockNum	blocksUsedS = (Pro_BlockNum)((eofL >> 9) + ((eofL & 0x01FF) != 0));
	
	return blocksUsedS;
}

Pro_BlockNum	Pro_GetIndexBlockShort(Pro_IndexBlock *block, Pro_BlockNum index)
{
	return (Pro_BlockNum)(
		(((Pro_BlockNum)(block->high.byte[index])) << 8) 
		| ((Pro_BlockNum)(block->low.byte[index])));
}

void			Pro_SetIndexBlockShort(Pro_IndexBlock *block, ushort index, Pro_BlockNum value)
{
	block->high.byte[index]	= (unsigned char)(value >> 8);
	block->low.byte[index]	= (unsigned char)(value & 0x00FF);
}

/**********************************************/

//	get block
OSErr	Pro_GetBlock(DiskImageRec *imageRec, Pro_BlockNum blockNum, Pro_Block **blockP)
{
	OSErr		err = noErr;
	Pro_Block	*theBlock;

	if (IS_ImageRec_IN_MEMORY(imageRec)) {
		if (blockNum >= Pro_kBlocksPerDisk) {
			err = IC_Err_READ_ILLEGAL_DISK_BLOCK;
		} else {
			theBlock = &(imageRec->image.pro->block[blockNum]);
		}
	} else {
		ulong		image_offsetUL = 0;
		
		switch (ImageRec_DiskType(imageRec)) {

			case DiskType_onDisk_DiskCopy: {
				image_offsetUL = sizeof(Disk_DiskCopy_Header);
				break;
			}

			case DiskType_onDisk_2img: {
				image_offsetUL = ImageRec_VolRec(imageRec).image.header.twoimg.img_start_offset;
				break;
			}
		}
		
		theBlock = imageRec->image.proBlock;
				
		err = ReadChunk(
			imageRec, theBlock, 
			image_offsetUL + (blockNum * sizeof(Pro_Block)), 
			sizeof(Pro_Block));
		
		if (err) err = IC_Err_CANT_READ_PRODOS_BLOCK;
	}
	
	if (!err) {
		*blockP = theBlock;
	}

	return err;
}

/*
Macintosh -> ProDOS conversion

/*
	Macintosh	ProDOS
	Filetype	Filetype		Auxtype
	'BINA'		$00				$0000
	'TEXT'		$04 (TXT)		$0000
	'PSYS'		$FF (SYS)		$0000
	'PS16'		$B3 (S16)		$0000
	'XY  '		$XY				$0000
	'p'$uvwxyz	$uv				$wxyz
	(any)		$00				$0000

	Macintosh				ProDOS
	Creator	Filetype		Filetype       Auxtype
	"pdos"	"PS16"  		$B3 (S16)       $0000
	"pdos"	"PSYS"  		$FF (SYS)       $0000
	"pdos"	"XY??"  		$XY     		$0000
	"pdos"	"p" $uv $wx $yz	$uv    			$wxyz
	"dCpy"	"dImg"			$E0     		$0005
	(any)	"BINA"			$00				$0000
	(any)	"TEXT"			$04 (TXT)		$0000
	(any)	"MIDI"			$D7				$0000
	(any)	"AIFF"			$D8				$0000
	(any)	"AIFC"			$D8				$0001
	(any)	(any)			$00				$0000
	  Where X,Y are hex digits (i.e. "0"-"9" or "A"-"F"), and ? is a space
*/

void		Mac_To_Pro_FileType(OSType macType, Byte *a2TypeP, ushort *a2AuxTypeP)
{
	*a2AuxTypeP = 0x0000;
	
	switch (macType) {

		case kDragPseudoFileTypeDirectory: {
			*a2TypeP = Pro_FileType_DIR;
			break;
		}

		case 'BINA': {
			*a2TypeP = Pro_FileType_BINA;
			break;
		}

		case 'TEXT': {
			*a2TypeP = Pro_FileType_TXT;
			break;
		}

		case 'PS16': {
			*a2TypeP = Pro_FileType_S16;
			break;
		}

		case 'PSYS': {
			*a2TypeP = Pro_FileType_SYS;
			break;
		}

		default: {
//			Boolean		okayB = TRUE;
			char		char1 = (char)((macType & 0xFF000000) >> 24);
			char		char2 = (char)((macType & 0x00FF0000) >> 16);

			if (char1 == 'p') {
				*a2TypeP		= (unsigned char)((macType & 0x00FF0000) >> 16);
				*a2AuxTypeP		= (unsigned short)(macType & 0x0000FFFF);
			} else if (
				IS_HEX_DIGIT(char1)
				&& IS_HEX_DIGIT(char2)
			) {
				char			hexStrAC[3];
				unsigned int	hexValueUS;
				
				hexStrAC[0] = char1;
				hexStrAC[1] = char2;
				hexStrAC[2] = 0;
				
				sscanf(hexStrAC, "%x", &hexValueUS);

				*a2TypeP = (unsigned char)hexValueUS;
			} else {
				*a2AuxTypeP = 0x0000;
				*a2TypeP	= Pro_FileType_BINA;
			}
			break;
		}
	}
}

/*
	ProDOS -> Macintosh conversion

	ProDOS				Macintosh
	Filetype	Auxtype	Creator	Filetype
	$00			$0000	"pdos"	"BINA"
	$04 (TXT)	$0000	"pdos"  "TEXT"
	$B3 (S16)	$DByz	"pdos"  "p" $B3 $DB $yz
	$B3 (S16)	(any)   "pdos"	"PS16"
	$D7			$0000   "pdos"	"MIDI"
	$D8			$0000   "pdos"	"AIFF"
	$D8			$0001   "pdos"	"AIFC"
	$E0			$0005   "dCpy"	"dImg"
	$FF (SYS)	(any)	"pdos"	"PSYS"
	$uv			$wxyz   "pdos"	"p" $uv $wx $yz
*/
void			Pro_To_Mac_FileType(
	Byte	proType, 
	ushort	proAuxType, 
	OSType	*fileType, 
	OSType	*fileCreator)
{
	Boolean		hasTypeB	= TRUE;
	
	*fileCreator = ADFS_Creator;
	
	switch (proType) {
		
		case Pro_FileType_BINA: {
			if (proAuxType == 0) {
				*fileType	= 'BINA';
			} else {
				hasTypeB	= FALSE;
			}
			break;
		}
		
		case Pro_FileType_DIR: {
			*fileCreator	= kDragPseudoCreatorVolumeOrDirectory;
			*fileType		= kDragPseudoFileTypeDirectory;
			break;
		}

		case Pro_FileType_S16: {
			if ((proAuxType & 0xFF00) == 0xDB00) {
				*fileType = 'p' << 24 | 0x00B3DB00 | (proAuxType & 0xFF);
			} else {
				*fileType = 'PS16';
			}
			
			break;
		}
		
		case 0xD7: {
			if (proAuxType == 0) {
				*fileType	= 'MIDI';
			} else {
				hasTypeB	= FALSE;
			}
			break;
		}
		
		case 0xD8: {
			if (proAuxType == 0x0000) {
				*fileType = 'AIFF';
			} else if (proAuxType == 0x0001) {
				*fileType = 'AIFC';
			} else {
				hasTypeB	= FALSE;
			}
			break;
		}

		case 0xE0: {
			if (proAuxType == 0x0005) {
				*fileCreator	= 'dCpy';
				*fileType		= 'dImg';
			} else {
				hasTypeB	= FALSE;
			}
			break;
		}
		
		case Pro_FileType_TXT:
		case Pro_FileType_BIN:
		case Pro_FileType_AWP:
		case Pro_FileType_INT:
		case Pro_FileType_BAS: {
			if (
				proType == Pro_FileType_TXT
				|| IsCopyTranslated()
			) {
				*fileType		= 'TEXT';
				
				#ifdef DEBUG
					*fileCreator	= 'CWIE';
				#else
					*fileCreator	= 'ttxt';
				#endif
			} else {
				hasTypeB	= FALSE;
			}
			break;
		}

		case Pro_FileType_SYS: {
			*fileType	= 'PSYS';
			break;
		}
		
		default: {
			hasTypeB	= FALSE;
			break;
		}
	}
	
	if (!hasTypeB) {
		*fileType = 
			  (OSType)'p' << 24 
			| (OSType)proType << 16 
			| (OSType)proAuxType;
	}
}
