//
//  TeXDistributionBridge.m
//  TeXDist
//
//  Created by coder on 08/12/06.
//  Copyright 2011 Laurens'Tribune. All rights reserved.
//

#import "TeXDistCommon.h"
#import "TeXDistributionBridge.h"

@interface TeXDistributionBridge()
@property (readwrite,retain) NSURL * fileURL;
@property (readwrite,copy) NSString * displayName;
@property (readwrite,copy) NSDate * creationDate;
@property (readwrite,copy) NSDate * modificationDate;
@property (readwrite,retain) NSAttributedString * _attributedDescription;
@end

@implementation TeXDistributionBridge
@synthesize fileURL = iVarFileURL;
@synthesize displayName = iVarDisplayName;
@synthesize creationDate = iVarCreationDate;
@synthesize modificationDate = iVarModificationDate;
@synthesize architectures = iVarArchitectures;
@synthesize selectedArchitecture = iVarSelectedArchitecture;
@synthesize activeArchitecture = iVarActiveArchitecture;
@synthesize _attributedDescription = iVarAttributedDescription;
@synthesize architecturePriority = iVarArchitecturePriority;
@synthesize minimumSystemVersion = iVarMinimumSystemVersion;
@synthesize maximumSystemVersion = iVarMaximumSystemVersion;
@synthesize minimumSystemVersionsByArch = iVarMinimumSystemVersionsByArch;
@synthesize maximumSystemVersionsByArch = iVarMaximumSystemVersionsByArch;
- (BOOL)validateMinimumSystemVersion:(id *)ioResult error:(NSError **)RORef;
{
    //  We only accept a non void TeXDistSystemVersion
    if (ioResult AND [*ioResult isKindOfClass:[TeXDistSystemVersion class]]) {
        return YES;
    }
    return NO;
}
- (BOOL)validateMaximumSystemVersion:(id *)ioResult error:(NSError **)RORef;
{
    return [self validateMinimumSystemVersion:ioResult error:RORef];
}
- (BOOL)validateArchitecturePriority:(id *)ioResult error:(NSError **)RORef;
{
    //  We only accept an array of strings
    if (ioResult) {
        if ([*ioResult isKindOfClass:[NSArray class]]) {
            NSMutableArray * MRA = [NSMutableArray array];
            for (NSString * architecture in (NSArray *)*ioResult) {
                if ([architecture isKindOfClass:[NSString class]]) {
                    [MRA addObject:architecture];
                }
            }
            *ioResult = [MRA.copy autorelease];
            return YES;
        } else if (*ioResult) {
            return NO;
        } else {
            *ioResult = [NSArray array];
            return YES;
        }
    }
    return NO;
}
- (BOOL)validateMinimumSystemVersionsByArch:(id *)ioResult error:(NSError **)RORef;
{
    //  We only accept a dictionary which keys are strings and values are strings or system versions
    //  We replace it with a dictionary 
    if (ioResult) {
        if ([*ioResult isKindOfClass:[NSDictionary class]]) {
            NSMutableDictionary * MD = [NSMutableDictionary dictionary];
            for (NSString * K in [(NSDictionary *)*ioResult allKeys]) {
                id V = [*ioResult objectForKey:K];
                if ([K isKindOfClass:[NSString class]]) {
                    if ([V isKindOfClass:[NSString class]]) {
                        [MD setObject:[TeXDistSystemVersion systemVersionWithString:V error:NULL] forKey:K];
                    } else if ([V isKindOfClass:[TeXDistSystemVersion class]]) {
                        [MD setObject:V forKey:K];
                    }
                }
            }
            *ioResult = [MD.copy autorelease];
            return YES;
        } else if (*ioResult) {
            return NO;
        } else {
            *ioResult = [NSDictionary dictionary];
            return YES;
        }
    }
    return NO;
}
- (BOOL)validateMaximumSystemVersionsByArch:(id *)ioResult error:(NSError **)RORef;
{
    return [self validateMinimumSystemVersionsByArch:ioResult error:RORef];
}
- (id)initWithContentsOfURL:(NSURL *)aFileURL andReturnError:(NSError **)RORef;
{
    if ((self = [self init])) {
        self.fileURL = aFileURL;
        NSString * aPath = aFileURL.path;
		self.displayName = [[[NSFileManager defaultManager] displayNameAtPath:aPath] stringByDeletingPathExtension];
        self.architectures = [NSArray array];
        self.selectedArchitecture = self.architectures.count?
            [self.architectures objectAtIndex:0]:nil;
        [self addObserver:self forKeyPath:@"activeArchitecture" options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:NULL];
        NSDictionary * D = [[NSFileManager defaultManager] attributesOfItemAtPath:aPath error:RORef];
        self.creationDate = D.fileCreationDate;
        self.modificationDate = D.fileModificationDate;
        self.minimumSystemVersion = [TeXDistSystemVersion firstSystemVersion];
        self.maximumSystemVersion = [TeXDistSystemVersion lastSystemVersion];
    }
    return self;
}
- (void)dealloc;
{
    [self removeObserver:self forKeyPath:@"activeArchitecture"];
    self.fileURL = nil;
    self.displayName = nil;
    self.creationDate = nil;
    self.modificationDate = nil;
    self._attributedDescription = nil;
    self.architectures = nil;
    self.selectedArchitecture = nil;
    self.activeArchitecture = nil;
    self.architecturePriority = nil;
    self.minimumSystemVersion = nil;
    self.maximumSystemVersion = nil;
    self.minimumSystemVersionsByArch = nil;
    self.maximumSystemVersionsByArch = nil;
	[super dealloc];
	return;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
{
    if (object == self AND [keyPath isEqual:@"activeArchitecture"]) {
        TeXDistArchitecture * old = [change objectForKey:NSKeyValueChangeOldKey];
        TeXDistArchitecture * new = [change objectForKey:NSKeyValueChangeNewKey];
        if (NOT [old isEqual:new] AND old != new) {
            self.selectedArchitecture = new;
        }
        return;
    }
    [super observeValueForKeyPath:keyPath ofObject:keyPath change:change context:context];
}
- (NSAttributedString *)attributedDescription;
{
	if(self._attributedDescription)
		return self._attributedDescription;
    // the attributed description?
	NSBundle * bundle = [NSBundle bundleWithPath:self.fileURL.path];
	NSArray * candidates = [bundle pathsForResourcesOfType:nil inDirectory:nil];
	NSPredicate * descriptionPredicate = [NSPredicate predicateWithFormat:@"SELF contains[c] 'description'"];
	NSArray * descriptions = [candidates filteredArrayUsingPredicate:descriptionPredicate];
	NSString * descriptionPath = [descriptions lastObject];
	if (descriptionPath) {
		NSURL * theURL = [NSURL fileURLWithPath:descriptionPath];
		NSError * ROR = nil;
		if((self._attributedDescription = [[[NSAttributedString alloc]
                                    initWithURL:theURL options:nil documentAttributes:nil error:&ROR] autorelease]))
		{
			return self._attributedDescription;
		}
		if (ROR) {
			self._attributedDescription = [[[NSAttributedString alloc]
                                     initWithString:[ROR localizedDescription]] autorelease];
		}
	}
	return self._attributedDescription;
    
}
- (TeXDistArchitecture *)preferredArchitecture;
{
    return self.architectures.objectEnumerator.nextObject;
}
- (TeXDistArchitecture *)architectureWithName:(NSString *)aName;
{
    for (TeXDistArchitecture * TDA in self.architectures) {
        if ([TDA.names containsObject:aName]) {
            return TDA;
        }
    }
    return nil;
}
- (TeXDistArchitecture *)architectureWithDestinationPath:(NSString *)aPath;
{
    for (TeXDistArchitecture * TDA in self.architectures) {
        if ([TDA.destinationPath isEqual:aPath]) {
            return TDA;
        }
    }
    return nil;
}
- (NSString *)description;
{
    return [NSString stringWithFormat:@"<Distribution %@ %#x>",self.displayName,self];
}
- (NSString *)longDescription;
{
    return [NSString stringWithFormat:@"<TeX Distribution: %#x\n"
    @"Display name: %@\n"
    @"File URL: %@\n"
    @"Active architecture: %@\n"
    @"Selected architecture: %@\n"
    @"Available architectures \n%@\n>",
    self,self.displayName,self.fileURL,self.activeArchitecture,self.selectedArchitecture,self.architectures];
}
@end

#if 0
Nota bene, from http://en.wikipedia.org/wiki/X86-64#Mac_OS_X
Mac OS X v10.4.7 and higher versions of Mac OS X v10.4 run 64-bit command-line tools using the POSIX and math libraries on 64-bit Intel-based machines, just as all versions of Mac OS X v10.4 and 10.5 run them on 64-bit PowerPC machines. No other libraries or frameworks work with 64-bit applications in Mac OS X v10.4.[44] The kernel, and all kernel extensions, are 32-bit only.
Mac OS X v10.5 supports 64-bit GUI applications using Cocoa, Quartz, OpenGL and X11 on 64-bit Intel-based machines, as well as on 64-bit PowerPC machines.[45] All non-GUI libraries and frameworks also support 64-bit applications on those platforms. The kernel, and all kernel extensions, are 32-bit only.
Mac OS X v10.6 is the first version of Mac OS X that supports a 64-bit kernel. However, with its first release (v10.6.0), not all 64-bit computers are currently supported. The 64-bit kernel, like the 32-bit kernel, supports 32-bit applications; both kernels also support 64-bit applications. 32-bit applications have a virtual address space limit of 4 GB under either kernel.[46][47]
The 64-bit kernel does not support 32-bit kernel extensions, and the 32-bit kernel does not support 64-bit kernel extensions.
Mac OS X uses the universal binary format to package 32- and 64-bit versions of application and library code into a single file; the most appropriate version is automatically selected at load time. In Mac OS X 10.6, the universal binary format is also used for the kernel and for those kernel extensions that support both 32-bit and 64-bit kernels.
#endif