//
//  TKAppSkin.m
//  ThemeKit
//
//  Created by Colin Cornaby on 2/28/06.
//  Copyright 2006 __MyCompanyName__. All rights reserved.
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.

//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#import "TKAppSkin.h"
#import "CSCheckSum.h"
#import "TKVariation.h"
#import "TKResourceFile.h"
#import "TKPXMResource.h"
#import "TKCLRResource.h"
#import "TKPPATResource.h"
#import "TKPICTResource.h"
#import "TKLAYOResource.h"
#import "TKTdatResource.h"
#import "TKTheme.h"


@implementation TKAppSkin

-(void)setName:(NSString *)theName
{
	[self setValue:theName forKey:@"skinName"];
}

-(NSString *)name{
	NSString *flavorName = [self valueForKey:@"skinName"];
	if(flavorName==nil)
		return nil;
	return flavorName;
}

-(void)setIcon:(NSImage *)theIcon
{
	[self willChangeValueForKey:@"icon"];
    [self setPrimitiveValue:[theIcon TIFFRepresentation] forKey:@"icon"];
    [self didChangeValueForKey:@"icon"];
}

-(NSData *)icon{
	[self willAccessValueForKey:@"icon"];
    NSData *n = [self primitiveValueForKey:@"icon"];
	if(n==nil)
		return nil;
    [self didAccessValueForKey:@"icon"];
    return n;
}

-(NSData *)currentDRMKey
{
	return nil;
}

-(void)setAppIdentifier:(NSString *)appIdentifier
{
	[self willChangeValueForKey:@"appIdentifier"];
    [self setPrimitiveValue:appIdentifier forKey:@"appIdentifier"];
    [self didChangeValueForKey:@"appIdentifier"];
}

-(NSString *)appIdentifier
{
	[self willAccessValueForKey:@"appIdentifier"];
    NSString *n = [self primitiveValueForKey:@"appIdentifier"];
    [self didAccessValueForKey:@"appIdentifier"];
    return n;
}

-(void)setDRMForUserName:(NSString *)username password:(NSString *)password
{
	//NSString *userAndPass = [NSString stringWithFormat:@"%@%@", username, password];
	//NSData *hash = [CSCheckSum hashForData:[userAndPass dataUsingEncoding:NSUnicodeStringEncoding]];
	//[self setMetadataForKey:@"TKDRMKey" forValue:hash];
}

-(void)removeAppSkinResource:(id)resource
{
	[[self mutableSetValueForKey:@"resources"] removeObject:resource];
	[[self managedObjectContext] deleteObject:resource];
}

-(id)addAppSkinResource:(id)resource
{
	id resourceToAdd = resource;
	if(!([resource managedObjectContext]==[self managedObjectContext])){
		resourceToAdd = [NSEntityDescription insertNewObjectForEntityForName:[[resource entity] name] inManagedObjectContext:[self managedObjectContext]];
		NSArray *attributeKeys = [[resourceToAdd entity] attributeKeys];
		NSEnumerator *enumerator = [attributeKeys objectEnumerator];
		NSString *attributeName = nil;
		while (nil != (attributeName = [enumerator nextObject]))
		{
			[resourceToAdd setValue: [resource valueForKey: attributeName] forKey: attributeName];
		}
		[resourceToAdd setValue:[NSEntityDescription insertNewObjectForEntityForName:@"TKResourceMetadata" inManagedObjectContext:[self managedObjectContext]] forKey:@"metadata"];
		[[resourceToAdd valueForKey:@"metadata"] setValue:[[resource valueForKey:@"metadata"] valueForKey:@"metadata"] forKey:@"metadata"];
	}
	[[self mutableSetValueForKey:@"resources"] addObject:resourceToAdd];
	return resourceToAdd;
}


-(NSArray *)getResourcesForType:(NSString *)resType withSortDescriptors:(NSArray *)descriptors
{
	if([resType isEqualToString:@"TKResource"]){
		NSArray *resources = [[self valueForKey:@"resources"] allObjects];
		if(descriptors!=nil)
			resources = [resources sortedArrayUsingDescriptors:descriptors];
		return resources;
	}
	NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
	NSEntityDescription *entity = [NSEntityDescription entityForName:resType inManagedObjectContext:[self managedObjectContext]];
	[request setEntity:entity];
	NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self.owner = %@", self];
	[request setPredicate:predicate];
	if(descriptors!=nil)
		[request setSortDescriptors:descriptors];
	NSError *error = nil;
	NSArray *array = [[self managedObjectContext] executeFetchRequest:request error:&error];
	return array;
}

-(NSArray *)getResourcesForType:(NSString *)resType
{
	return [self getResourcesForType:resType withSortDescriptors:nil];
}

-(void)writeExtrasFileAtPath:(NSString *)path withEndianness:(TKEndianness)endianness writeComplete:(BOOL)writeCompleteFile
{
	int b;
	TKResourceFile *myResFile;
	int i;
    OSErr theErr;
	[[NSFileManager defaultManager] removeFileAtPath:@"/tmp/Extras.rsrc" handler:nil];
	TKEndianness trueEndianness = resolveEndianness(endianness);
	NSString *extrasFilePath = nil;
	if(writeCompleteFile==YES)
	{
		if(trueEndianness==kLittleEndian)
			extrasFilePath = @"/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Resources/Extras2.rsrc";
		if(trueEndianness==kBigEndian)
			extrasFilePath = @"/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Resources/Extras.rsrc";
		if(extrasFilePath==nil)
			[NSException raise:NSGenericException format:@"No output platform could be determined for resource export"];
		[[NSFileManager defaultManager] copyPath:extrasFilePath toPath:@"/tmp/Extras.rsrc" handler:nil];
	}
	myResFile = [[TKResourceFile alloc] initForWritingAtPath:@"/tmp/Extras.rsrc"];
	[myResFile setEndiannessOfResourceFile:endianness];
    ResType resType = 'pxm#';
	NSArray *resourcesToImport = [self getResourcesForType:@"TKPXMResource"]; 
	b = [resourcesToImport count];
	for(i=0;i<b; i++){
		if([myResFile dataForType:resType ID:[[resourcesToImport objectAtIndex:i] resourceID]]){
			if( noErr != (theErr = [myResFile changeResource:[[resourcesToImport objectAtIndex:i] resourceID] forData:[[resourcesToImport objectAtIndex:i] resourceDataForPlatform:trueEndianness] forType:resType]) )
			{
				
				[NSException raise: NSGenericException format: @"Error %d in addData", theErr];
				NSLog(@"error");
			}
		}
		else
		{
			if( noErr != (theErr = [myResFile addData:[[resourcesToImport objectAtIndex:i] resourceDataForPlatform:trueEndianness] type:resType Id:[[resourcesToImport objectAtIndex:i] resourceID] name:@"" attributes:0]) )
			{
				[NSException raise: NSGenericException format: @"Error %d in addData", theErr];
				NSLog(@"error");
			}
		}
	}
	resType = 'ppat';
	resourcesToImport = [self getResourcesForType:@"TKPPATResource"]; 
	b = [resourcesToImport count];
	for(i=0;i<b; i++){
		if([myResFile dataForType:resType ID:[[resourcesToImport objectAtIndex:i] resourceID]])
		{
			if( noErr != (theErr = [myResFile changeResource:[[resourcesToImport objectAtIndex:i] resourceID] forData:[[resourcesToImport objectAtIndex:i] resourceData] forType:resType]) )
			{
				
				[NSException raise: NSGenericException format: @"Error %d in addData", theErr];
				NSLog(@"error");
			}
		}
	}
	/*
	// This new code is for writing the clrs
	resType = 'clr#';
	NSMutableData *clrData = [NSMutableData dataWithData:[myResFile dataForType:resType ID:384]];
	b = [[self getResourcesForType:TKCLRRESOURCE] count];
	for(i=0;i<b; i++){
			char r = [[[[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] resource] color] redComponent]*255;
			char g = [[[[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] resource] color] greenComponent]*255;
			char b = [[[[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] resource] color] blueComponent]*255;
			[clrData replaceBytesInRange:NSMakeRange(4+(6*([[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] ID]-1)), 1) withBytes:&r];
			[clrData replaceBytesInRange:NSMakeRange(4+(6*([[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] ID]-1))+2, 1) withBytes:&g];
			[clrData replaceBytesInRange:NSMakeRange(4+(6*([[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] ID]-1))+4, 1) withBytes:&b];	
	}
	[myResFile changeResource:384 forData:clrData forType:resType];
	*/
	//
	//	if([myResFile dataForType:resType ID:[[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] ID]]){
	//	if( noErr != (theErr = [myResFile changeResource:[[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] ID] forData:[[[[self getResourcesForType:TKCLRRESOURCE] objectAtIndex:i] data] data] forType:resType]) ) {
	//		
	//		[NSException raise: NSGenericException format: @"Error %d in addData", theErr];
	//		NSLog(@"error");
	//	}
	//	}
	//}
	/*
	resType = 'layo';
	b = [[self getResourcesForType:@"tklayoresources"] count];
	for(i=0;i<b; i++){
		//if(([[[self getResourcesForType:TKLAYORESOURCE] objectAtIndex:i] ID]==260)||([[[self getResourcesForType:TKLAYORESOURCE] objectAtIndex:i] ID]==261)||([[[self getResourcesForType:TKLAYORESOURCE] objectAtIndex:i] ID]==263)){
		if( noErr != (theErr = [myResFile changeResource:[[[self getResourcesForType:@"tklayoresources"] objectAtIndex:i] ID] forData:[[[[self getResourcesForType:@"tklayoresources"] objectAtIndex:i] resource] data] forType:resType]) ) {
			
			[NSException raise: NSGenericException format: @"Error %d in addData", theErr];
			NSLog(@"error");
		}
		//}
	}
	resType = 'tdat';
	b = [[self getResourcesForType:@"tktdatresources"] count];
	for(i=0;i<b; i++){
		//if(([[[self getResourcesForType:TKLAYORESOURCE] objectAtIndex:i] ID]==260)||([[[self getResourcesForType:TKLAYORESOURCE] objectAtIndex:i] ID]==261)||([[[self getResourcesForType:TKLAYORESOURCE] objectAtIndex:i] ID]==263)){
		if( noErr != (theErr = [myResFile changeResource:[[[self getResourcesForType:@"tktdatresources"] objectAtIndex:i] ID] forData:[[[[self getResourcesForType:@"tktdatresources"] objectAtIndex:i] resource] data] forType:resType]) ) {
			
			//[NSException raise: NSGenericException format: @"Error %d in addData", theErr];
			NSLog(@"error %i", i);
		}
		//}
	}*/
	[myResFile closeFile];
	[myResFile release];
	[[NSFileManager defaultManager] copyPath:@"/tmp/Extras.rsrc" toPath:path handler:nil];
}

-(void)writeExtrasFileAtPath:(NSString *)path withEndianness:(TKEndianness)endianness
{
	[self writeExtrasFileAtPath:path withEndianness:endianness writeComplete:YES];
}

-(void)writeExtrasFileAtPath:(NSString *)location{
	[self writeExtrasFileAtPath:location withEndianness:kNativeEndian writeComplete:YES];
}

-(void)writeFinderResourceFile:(NSString *)location{
	//currently dead method
	/*int b;
	TKResourceFile *myResFile;
    ResType resType = 'PICT';
	int i;
    OSErr theErr;
	[[NSFileManager defaultManager] removeFileAtPath:@"/tmp/Finder.rsrc" handler:nil];
	[[NSFileManager defaultManager] copyPath:@"/System/Library/CoreServices/Finder.app/Contents/Resources/Finder.rsrc" toPath:@"/tmp/Finder.rsrc" handler:nil];
	myResFile = [[TKResourceFile alloc] initForWritingAtPath:@"/tmp/Finder.rsrc"];
	b = [[self getResourcesForType:@"tkpictresources"] count];
	for(i=0;i<b; i++){
		if([myResFile dataForType:resType ID:[[[self getResourcesForType:@"tkpictresources"] objectAtIndex:i] ID]]){
		if( noErr != (theErr = [myResFile changeResource:[[[self getResourcesForType:@"tkpictresources"] objectAtIndex:i] ID] forData:[[[[self getResourcesForType:@"tkpictresources"] objectAtIndex:i] resource] data] forType:resType]) ) {
			
			[NSException raise: NSGenericException format: @"Error %d in addData (PICT)", theErr];
			NSLog(@"error");
		}
		}
	}
    resType = 'PNG ';
	b = [[self getResourcesForType:@"tkpngresources"] count];
	for(i=0;i<b; i++){
		if([myResFile dataForType:resType ID:[[[self getResourcesForType:@"tkpngresources"] objectAtIndex:i] ID]]){
		if( noErr != (theErr = [myResFile changeResource:[[[self getResourcesForType:@"tkpngresources"] objectAtIndex:i] ID] forData:[[[[self getResourcesForType:@"tkpngresources"] objectAtIndex:i] resource] data] forType:resType]) ) {
			[NSException raise: NSGenericException format: @"Error %d in addData (PNG)", theErr];
			NSLog(@"error");
		}
		}
	}

	[myResFile closeFile];
	[myResFile release];
	[[NSFileManager defaultManager] copyPath:@"/tmp/Finder.rsrc" toPath:location handler:nil];
	*/
}

-(NSArray *)pullImagesFromResourceFile:(NSString *)path forTypes:(NSArray *)types
{
	NSMutableArray *resourcesToReturn = [[NSMutableArray alloc] init];
	TKResourceFile *dataSource = [[TKResourceFile alloc] initForReadingAtPath:path];
	int i, j;
	for(i=0;i<[types count];i++){
		ResType currType = *(FourCharCode *)[[types objectAtIndex:i] cString];
		for(j=1; j<=[dataSource count:currType]; j++){
				NSData *resourceData = [dataSource dataForType:currType Index:j];
				TKPICTResource *resourceToBeAdded = [NSEntityDescription insertNewObjectForEntityForName:@"TKPICTResource" inManagedObjectContext:[self managedObjectContext]];
				[resourceToBeAdded setResourceData:resourceData];
				[resourceToBeAdded setResourceID:[dataSource resId:currType Index:j]];
				[resourceToBeAdded setResourceName:[[dataSource resName:currType Index:j] retain]];
				[resourceToBeAdded setMetadataForKey:@"TKResourceFileType" forValue:[types objectAtIndex:i]];
				[resourcesToReturn addObject:[self addAppSkinResource:resourceToBeAdded]];
		}
	}
	[dataSource release];
	return [resourcesToReturn autorelease];
}

-(void)pullFromExtrasResourceData:(NSString *)resourceFileData
{
	[self pullFromExtrasResourceData:resourceFileData withEndianness:kUnknownEndian];
}

-(void)pullFromExtrasResourceData:(NSString *)resourceFileData withEndianness:(TKEndianness)endianness
{
	TKResourceFile *dataSource;
	int j;
	dataSource = [[TKResourceFile alloc] initForReadingAtPath:resourceFileData];
	TKEndianness endiannessOfResourceFile;
	if(endianness==kUnknownEndian)
		endiannessOfResourceFile= [dataSource endiannessOfResourceFile];
	else
		endiannessOfResourceFile = endianness;
	if(endiannessOfResourceFile==kUnknownEndian)
		endiannessOfResourceFile=kBigEndian;
	for(j=1; j<=[dataSource count:'tdat']; j++){
			NSData *resourceData = [dataSource dataForType:'tdat' Index:j];
			TKTdatResource *resourceToBeAdded = [NSEntityDescription insertNewObjectForEntityForName:@"TKTdatResource" inManagedObjectContext:[self managedObjectContext]];
			[resourceToBeAdded setResourceData:resourceData dataEndianness:endiannessOfResourceFile];
			[resourceToBeAdded setOriginalResourceHash:[CSCheckSum hashForData:resourceData]];
			[resourceToBeAdded setResourceID:[dataSource resId:'tdat' Index:j]];
			[resourceToBeAdded setResourceName:[[dataSource resName:'tdat' Index:j] retain]];
			[self addAppSkinResource:resourceToBeAdded];
	}
	for(j=1; j<=[dataSource count:'layo']; j++){
			NSData *resourceData = [dataSource dataForType:'layo' Index:j];
			TKLAYOResource *resourceToBeAdded = [NSEntityDescription insertNewObjectForEntityForName:@"TKLAYOResource" inManagedObjectContext:[self managedObjectContext]];
			[resourceToBeAdded setResourceData:resourceData dataEndianness:endiannessOfResourceFile];
			[resourceToBeAdded setOriginalResourceHash:[CSCheckSum hashForData:resourceData]];
			[resourceToBeAdded setResourceID:[dataSource resId:'layo' Index:j]];
			[resourceToBeAdded setResourceName:[[dataSource resName:'layo' Index:j] retain]];
			[self addAppSkinResource:resourceToBeAdded];
	}
	for(j=1; j<=[dataSource count:'clr#']; j++){
			NSData *resourceData = [dataSource dataForType:'clr#' Index:j];
			TKCLRResource *resourceToBeAdded = [NSEntityDescription insertNewObjectForEntityForName:@"TKCLRResource" inManagedObjectContext:[self managedObjectContext]];
			[resourceToBeAdded setResourceData:resourceData dataEndianness:endiannessOfResourceFile];
			[resourceToBeAdded setOriginalResourceHash:[CSCheckSum hashForData:resourceData]];
			[resourceToBeAdded setResourceID:[dataSource resId:'clr#' Index:j]];
			[resourceToBeAdded setResourceName:[[dataSource resName:'clr#' Index:j] retain]];
			[self addAppSkinResource:resourceToBeAdded];
	}
	for(j=1; j<=[dataSource count:'pxm#']; j++){
			NSData *resourceData = [dataSource dataForType:'pxm#' Index:j];
			TKPXMResource *resourceToBeAdded = [NSEntityDescription insertNewObjectForEntityForName:@"TKPXMResource" inManagedObjectContext:[self managedObjectContext]];
			[resourceToBeAdded setResourceData:resourceData dataEndianness:endiannessOfResourceFile];
			[resourceToBeAdded setOriginalResourceHash:[CSCheckSum hashForData:resourceData]];
			[resourceToBeAdded setResourceID:[dataSource resId:'pxm#' Index:j]];
			[resourceToBeAdded setResourceName:[[dataSource resName:'pxm#' Index:j] retain]];
			[self addAppSkinResource:resourceToBeAdded];
	}
	for(j=1; j<=[dataSource count:'ppat']; j++){
			NSData *resourceData = [dataSource dataForType:'ppat' Index:j];
			TKPPATResource *resourceToBeAdded = [NSEntityDescription insertNewObjectForEntityForName:@"TKPPATResource" inManagedObjectContext:[self managedObjectContext]];
			[resourceToBeAdded setResourceData:resourceData dataEndianness:endiannessOfResourceFile];
			[resourceToBeAdded setOriginalResourceHash:[CSCheckSum hashForData:resourceData]];
			[resourceToBeAdded setResourceID:[dataSource resId:'ppat' Index:j]];
			[resourceToBeAdded setResourceName:[[dataSource resName:'ppat' Index:j] retain]];
			[self addAppSkinResource:resourceToBeAdded];
	}
	[dataSource release];
}

-(void)pullFromFinderResourceData:(NSString *)resourceFilePath{
	TKResourceFile *dataSource;
	int j;
	dataSource = [[TKResourceFile alloc] initForReadingAtPath:resourceFilePath];
	for(j=1; j<=[dataSource count:'PICT']; j++){
			TKPICTResource *resourceToBeAdded = [[TKPICTResource alloc] initWithData:[dataSource dataForType:'PICT' Index:j]];
			[resourceToBeAdded setResourceID:[dataSource resId:'PICT' Index:j]];
			[resourceToBeAdded setResourceName:[[dataSource resName:'PICT' Index:j] retain]];
			[self addAppSkinResource:resourceToBeAdded];
			[resourceToBeAdded release];
	}
	for(j=1; j<=[dataSource count:'PNG ']; j++){
			TKPICTResource *resourceToBeAdded = [[TKPICTResource alloc] initWithData:[dataSource dataForType:'PNG ' Index:j]];
			[resourceToBeAdded setResourceID:[dataSource resId:'PNG ' Index:j]];
			[resourceToBeAdded setResourceName:[[dataSource resName:'PNG ' Index:j] retain]];
			[self addAppSkinResource:resourceToBeAdded];
			[resourceToBeAdded release];
	}
	[dataSource release];
}

@end
