/*
   Project: Gpkg

   Copyright (C) 2004 Frederico Munoz

   Author: Frederico S. Munoz

   Created: 2004-06-22 15:45:21 +0100 by fsmunoz

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This application 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
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#import "Gpkg.h"

@interface Gpkg (Private)

- (BOOL) atomicallyCopyPath: (NSString *) sourcePath toPath: (NSString *) destinationPath ofType: (NSString *)fileType  withAttributes: (NSDictionary *) attributes;
- getAllInfo;
- uncompressPackage;

@end

@implementation Gpkg (Private)
- uncompressPackage
{

  NSLog(@"Hello uncompressPackage");
  NSArray *args;
  NSTask *task;
  NSData *data;
  NSString *lstr;
  NSString *gstr;
  NSString *lic;
  NSPipe *pipe = [NSPipe pipe];
  NSFileHandle *fileHandle;
  NSFileManager *manager = [NSFileManager defaultManager];
  
  NSString *tempDir = [NSTemporaryDirectory() stringByAppendingPathComponent: [[NSProcessInfo processInfo] processName]];
  
  NSLog (@"1");
  //packageTempDir is: TMP/Installer.app/
  //  packageTempDir = [NSString stringWithString: [[NSTemporaryDirectory() stringByAppendingPathComponent: [[NSProcessInfo processInfo] processName]] stringByAppendingPathComponent: appDirectoryName]];

  //  NSString *installerTempDir = [NSString stringWithString: [packageTempDir stringByDeletingLastPathComponent]];
  NSString *command;
  installerTempDir = [NSString stringWithString: [NSTemporaryDirectory() stringByAppendingPathComponent: [[NSProcessInfo processInfo] processName]]];
  packageTempDir = [installerTempDir stringByAppendingPathComponent:  [descriptionPlist objectForKey:@"IFPkgDescriptionTitle"]];

  NSLog (@"2");
  // Create the $TMP/Installer
  if (![manager fileExistsAtPath: installerTempDir])
    {
      NSLog (@"Created %@", installerTempDir);
      [manager createDirectoryAtPath: installerTempDir
	       attributes: [manager fileAttributesAtPath: NSTemporaryDirectory() traverseLink: NO]];
      //      [manager enforceMode: 0700  atPath: aString];
    }
  // Create the $TMP/Installer/SomePackage.app
  if (![manager fileExistsAtPath: packageTempDir])
    {
      NSLog (@"Created %@", packageTempDir);
      [manager createDirectoryAtPath: packageTempDir
	       attributes: [manager fileAttributesAtPath: installerTempDir traverseLink: NO]];
      //      [manager enforceMode: 0700  atPath: compressedPath];
    }
    
  //  NSLog (@"Copying %@ to %@", packageArchivePath, packageTempDir);
  NSLog (@"3");
  packageTempArchivePath = [packageTempDir stringByAppendingPathComponent: [paxArchivePath lastPathComponent]];
  if ([manager copyPath: paxArchivePath toPath: packageTempArchivePath  handler:nil])
    NSLog (@"Success!!!");
  else
    NSLog (@"Some weird error...");
  /*
  packageArchivePath = [packageTempDir stringByAppendingPathComponent: [packageArchivePath lastPathComponent]]; 
  if ([archiveFormat isEqualToString: @"TAR"])
    {
      command = [NSString stringWithString: @"tar"];
      args = [NSArray arrayWithObjects: @"-zxvf", packageArchivePath, nil];
    }
  if ([archiveFormat isEqualToString: @"PAX"])
    {
      command = [NSString stringWithString: @"pax"];
      args = [NSArray arrayWithObjects: @"-zrvf", packageArchivePath, nil];
    }
  //  appDir =  [compressedPath stringByAppendingPathComponent: [appDirPath lastPathComponent]];
  */
  command = [NSString stringWithString: @"pax"];
  args = [NSArray arrayWithObjects: @"-zrvf", paxArchivePath, nil];
  task = [NSTask new];
  [task setLaunchPath: command];
  [task setArguments: args];
  [task setStandardOutput: pipe];
  [task setCurrentDirectoryPath: packageTempDir];
  fileHandle = [pipe fileHandleForReading];
  [task launch];
  data = [fileHandle readDataToEndOfFile];
  [fileHandle closeFile];
  lstr = [[NSString alloc] initWithData: data
			   encoding: [NSString defaultCStringEncoding]];
  NSLog(@"This is lstr: %@", lstr);
  

}

- getAllInfo
{
  
  NSFileManager *aFileManager;
  NSArray *allFiles;
  NSString *inputString = [NSString new];
  NSString *sizesFileContents = [NSString new];
  NSMutableDictionary *sizesValues = [NSMutableDictionary new];
  //  NSString *contentsPath = [[NSString alloc]initWithString: packagePath];
  NSString *contentsPath = [NSString stringWithString: [packagePath stringByAppendingPathComponent:@"Contents"]];
  //  NSString *bomContents;
  int j;
  
  //  [contentsPath setStringValue: [packagePa
  NSLog (@"Contents at: %@",contentsPath);


  aFileManager = [NSFileManager defaultManager];

  //  bundlesPath =  [NSString stringWithString: @"./Gpkg.subproj"];
  //[bundlesPath initWithString: filename];
  //  appDir = [NSString new];

  
  allFiles = [aFileManager directoryContentsAtPath: packagePath];
  NSString *descriptionPlistPath = [NSBundle pathForResource:@"Description" 
					     ofType:@"plist"
					     inDirectory: contentsPath];
  NSString *infoPlistPath = [NSBundle pathForResource:@"Info" 
				      ofType:@"plist"
				      inDirectory: contentsPath];
  paxArchivePath = [NSBundle pathForResource:@"Archive" 
				       ofType:@"pax.gz"
				       inDirectory: contentsPath];
  NSString *bomPath = [NSBundle pathForResource:@"Archive" 
				ofType:@"bom"
				inDirectory: contentsPath];
  NSString *licensePath = [NSBundle pathForResource:@"License" 
				    ofType: nil
				    inDirectory: contentsPath];
  NSString *readmePath = [NSBundle pathForResource:@"ReadMe" 
				   ofType: nil
				   inDirectory: contentsPath];
  NSString *welcomePath = [NSBundle pathForResource:@"Welcome" 
				    ofType: nil
				    inDirectory: contentsPath];
  
  license = [NSString stringWithContentsOfFile: licensePath];
  welcome = [NSString stringWithContentsOfFile: welcomePath];

  NSLog (@"Description: %@", descriptionPlistPath);  
  NSLog (@"Info: %@", infoPlistPath);
  NSLog (@"Archive: %@", paxArchivePath);  
  NSLog (@"BOM: %@", bomPath);  
  NSLog (@"License: %@", licensePath);  
  NSLog (@"Readme: %@", readmePath);  
  NSLog (@"Welcome: %@", welcomePath);  
  
  //  NSMutableDictionary *infoPlist = [NSMutableDictionary new];
  infoPlist = [NSPropertyListSerialization propertyListFromData: [[NSData dataWithContentsOfFile: infoPlistPath]retain]
					   mutabilityOption: NSPropertyListImmutable 
					   format:  0
					   errorDescription: 0];
  
  [infoPlist retain];

  descriptionPlist = [NSPropertyListSerialization propertyListFromData: [[NSData dataWithContentsOfFile: descriptionPlistPath]retain]
					   mutabilityOption: NSPropertyListImmutable 
					   format:  0
					   errorDescription: 0];
  
  [descriptionPlist retain];

  bom = [NSPropertyListSerialization propertyListFromData: [[NSData dataWithContentsOfFile: bomPath]retain]
					   mutabilityOption: NSPropertyListImmutable 
					   format:  0
					   errorDescription: 0];
  [bom retain];

  //  packageVersion = [infoPlist objectForKey:@"CFBundleShortVersionString"];
  //  exit(0);
  installLocation=[infoPlist objectForKey:@"IFPkgFlagDefaultLocation"];  
  [installLocation retain];
  [paxArchivePath retain];
  [packageTempDir retain];
  //  installerTempDir = [NSString stringWithString: [NSTemporaryDirectory() stringByAppendingPathComponent: [[NSProcessInfo processInfo] processName]]];
  //  packageTempDir = [installerTempDir stringByAppendingPathComponent:  [descriptionPlist objectForKey:@"IFPkgDescriptionTitle"]];
  NSLog (@"Temp dir for package: %@", packageTempDir);
}

-(BOOL) atomicallyCopyPath: (NSString *) sourcePath 
		    toPath: (NSString *) destinationPath 
		    ofType: (NSString *)fileType 
	    withAttributes: (NSDictionary *) attributes 
{
  
  NSFileManager *manager = [NSFileManager defaultManager];
  
  if ([fileType isEqualToString: NSFileTypeDirectory] == NO)
    {
      // Processing regular file
      NSLog (@"Processing file %@", sourcePath );
      
      if ([manager copyPath: sourcePath toPath: destinationPath handler: nil] != NO)
	{
	  return YES;
	}
      else
	{
	  NSLog (@"Failed installing a file %@", sourcePath);
	  return NO;
	}
    } //end File processing
  else
    {
      //Processing Directories
      //	  NSLog (@"Processing dir %@", key);
      NSLog (@"Processing dir %@", sourcePath);
      
      if ([manager createDirectoryAtPath: destinationPath
		   attributes: attributes] != NO)
	{
	  return YES;
	}
      else
	{
	  NSLog (@"Failed creating a directory %@", destinationPath);
	  return NO;
	} 
      
    } //end Dir processing
} // end while 

@end

@implementation Gpkg
- int 
{
  [super init];
  //  totalSteps = [NSString new];
  return self;
}




- (BOOL) handlesPackage: (NSString *)pkgPath;
{
  NSLog (@"Entered Gpkg handlesPackage");
  if ([[pkgPath pathExtension] isEqualToString: @"pkg"])
    {
      NSLog (@"Returning YES");
      // packagePath = [NSString stringWithString: [pkgPath stringByAppendingPathComponent:@"Contents"]];
      packagePath = [NSString stringWithString: pkgPath];
      [packagePath retain];
      [self getAllInfo];
      return YES;

    }  
  return NO;
}
- (NSString *) packageName
{
  //  return @"Test";
  //  return [infoValues objectForKey: @"Title"];
  return  [descriptionPlist objectForKey:@"IFPkgDescriptionTitle"];
}
- (NSString *) packageVersion
{
  //  return @"2.3";
  //  return [infoValues objectForKey: @"Version"];
  return  [descriptionPlist objectForKey:@"IFPkgDescriptionVersion"];
  //  return  [infoPlist objectForKey:@"CFBundleShortVersionString"];
}
- (BOOL) isInstalled
{
  NSArray *paths;
  BOOL isDir;
  //  NSString *receiptsFolder;
  NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath: packagePath];
  NSFileManager *manager = [NSFileManager defaultManager];

  id key;
  
  paths = NSSearchPathForDirectoriesInDomains (NSLibraryDirectory, NSUserDomainMask, YES);
  
  //    NSString  *receiptsFolder = [[NSString alloc] initWithString: [[[paths objectAtIndex: 0] stringByAppendingPathComponent:@"Receipts"] stringByAppendingPathComponent: [packagePath lastPathComponent]]];  

  if (([manager fileExistsAtPath: [[[paths objectAtIndex: 0] stringByAppendingPathComponent:@"Receipts"] stringByAppendingPathComponent: [packagePath lastPathComponent]] isDirectory: &isDir] && isDir )!= NO)
    {
      NSLog (@"File exists");
    }
  else
    {
      NSLog (@"File doesn't exist");
    }
  //  NSString *receiptsFolder = [NSString stringWithString: @"ADB"];  
  
  return NO;
}
- (NSString *) packageDescription
{
  //  return @"Application to test Installer.app";
  //  return [infoValues objectForKey: @"Description"];
  return welcome;

}
- (NSString *) packageAuthor
{
  return @"Frederico Muņoz";
}

- (NSString *) packageLocation
{

  //  return @"Testing...";
  //  return [infoValues objectForKey: @"DefaultLocation"];
  return  installLocation;
}
- (NSString *) packageLicence
{
  return license;
  //  return @"Testing...";
}
- (NSImage *) packageIcon
{

  //  NSImage *icon = [NSImage new];
  //  [icon  initWithContentsOfFile: @"/home/fsmunoz/Code/AClock-0.2.3.pkg/AClock.tiff"];

  return icon;


}
- (NSString *) packageSizes
{

  packageSizes = [NSString stringWithFormat: @"%d installed, %i packaged", 
			   [[[bom objectForKey:@"Sizes"] objectForKey:@"GSTotalSize"] intValue], 14];
  return packageSizes;
}
- (NSString *) packagePlatform
{
  return @"i386 GNU/Linux";
  //  return [infoValues objectForKey: @"Description"];
}

- (NSString *) packageContents
{

  return [[[bom objectForKey:@"Files"] allKeys]componentsJoinedByString:@"\n"];
}

- (BOOL) installPackage: (id) sender
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSLog (@"InstallPackage received");
  NSMutableDictionary *receiptBom = [NSMutableDictionary new];
  NSMutableDictionary *installedFiles = [NSMutableDictionary new];
  NSMutableArray *newFileOrder = [NSMutableArray new];
  NSArray *fileOrder = [NSArray new];
  NSData *receiptData;
  NSString *destination = [[[NSHomeDirectory() stringByAppendingPathComponent:@"GNUstep"]
			     stringByAppendingPathComponent:@"Applications"]
			    //			    stringByAppendingPathComponent: appDirectoryName];
			    stringByAppendingPathComponent: @"123"];

  //  NSLog (@"Install Location: %i",[installLocation retainCount]);
  [self preInstall];
  NSFileManager *manager = [NSFileManager defaultManager];
  /*    
  //NSString *appDir = [packageTempDir stringByAppendingPathComponent: appDirectoryName];
  NSString *appDir = [packageTempDir stringByAppendingPathComponent: @"123"];
  */
//  NSLog(@"Testing appdir: %@", appDir);
  NSLog (@"moo");
  
  [self uncompressPackage];

  if ([manager changeCurrentDirectoryPath: packageTempDir] != NO)
    NSLog (@"Chdir OK");
  else
    NSLog (@"Chdir FAILED");

  //NSEnumerator *enumerator = [[bom objectForKey: @"Files"] keyEnumerator];
  //  fileOrder = [bom objectForKey: @"Order"];
  //NSLog (@"Order: %@",[fileOrder description]);
  NSEnumerator *enumerator = [[bom objectForKey: @"Order"] objectEnumerator];
  id key;
  while (key = [enumerator nextObject]) 
    {
      if ([self atomicallyCopyPath: [packageTempDir stringByAppendingPathComponent: key] 
		toPath: [installLocation stringByAppendingPathComponent: key]
		ofType: [[[bom objectForKey: @"Files"] objectForKey: key] valueForKey:@"NSFileType"]
		withAttributes: [bom objectForKey: key]] != NO)
	{
	  // Add copied file to the receipt bom
	  [installedFiles setObject: [[bom objectForKey: @"Files"] objectForKey: key] 
			  forKey: [installLocation stringByAppendingPathComponent: key]];	  
	  // Update progress indicator
	  [newFileOrder addObject: key];
	  [sender performSelectorOnMainThread: @selector(updateProgressWithFile:)
		  withObject: nil waitUntilDone: YES];
	}
      else
	{
	  NSLog (@"Failed installing a file %@", [installLocation stringByAppendingPathComponent: key]);	      
	}
    }
  
  [receiptBom setObject: installedFiles forKey:@"Files"];
  [receiptBom setObject: newFileOrder forKey:@"Order"];

  receiptData = [NSData dataWithData: [NSPropertyListSerialization dataFromPropertyList: receiptBom  
								   //format: NSPropertyListGNUstepBinaryFormat 
								   format: NSPropertyListXMLFormat_v1_0  
								   errorDescription: 0]];
  
  if ([receiptData writeToFile: @"/tmp/TI.bom" atomically: YES])
    NSLog (@"Success");
  
  [self installReceipt: receiptData];
  [self postInstall];
  exit (0);
  
  [pool release];
}

- (BOOL) installReceipt: (NSData *) receiptData;
{
  NSArray *paths;
  NSString *receiptsFolder = [NSString new];
  NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath: packagePath];
  NSFileManager *manager = [NSFileManager defaultManager];
  id key;

  paths = NSSearchPathForDirectoriesInDomains (NSLibraryDirectory, NSUserDomainMask, YES);
  receiptsFolder = [[paths objectAtIndex: 0] stringByAppendingPathComponent:@"Receipts"];

  NSLog (@"Receipts are in %@", receiptsFolder);
    
  // Create the package top directory for the receipt

  if ([manager createDirectoryAtPath: [receiptsFolder stringByAppendingPathComponent: [packagePath lastPathComponent]]
	       attributes: nil] != NO)
    {
      NSLog (@"Created top receipt dir");
    }
  else
    {
      NSLog (@"Failed to create top receipt dir");
    }
  
  while (key = [dirEnum nextObject]) 
    {
      if (([[key lastPathComponent]isEqualToString: @"Archive.pax.gz"] 
	   ||[[key lastPathComponent]isEqualToString: @"Archive.bom"]) == NO)
	{ 
	  if ([self atomicallyCopyPath: [packagePath stringByAppendingPathComponent: key]
		    toPath: [[receiptsFolder stringByAppendingPathComponent: [packagePath lastPathComponent]] 
			      stringByAppendingPathComponent: key]
		    ofType: [[manager fileAttributesAtPath: [packagePath stringByAppendingPathComponent: key] traverseLink: NO] valueForKey: NSFileType]
		    withAttributes: [bom objectForKey: key]] != NO)
	    {
	      NSLog (@"Copied to receipt %@", key);
	    }
	  else
	    {
	      NSLog (@"Error in copying file to receipt: %@", key);
	    }
	}
      else
	{
	  if ([[key lastPathComponent]isEqualToString: @"Archive.bom"] != NO)
	    {
	      NSLog (@"Copying the new BOM");
	      if ([receiptData writeToFile:  [[receiptsFolder stringByAppendingPathComponent: [packagePath lastPathComponent]]stringByAppendingPathComponent: key]
			       atomically: YES])
		{
		  NSLog (@"Created new BOM!");
		}
	      else
		{
		  NSLog (@"Failed to create new BOM");
		}
	    }
	  else
	    {
	      NSLog (@"Skipping archive or BOM in the receipt");
	      
	    }
	}
    }	  
  
      /*
      if ([manager copyPath:[packagePath stringByAppendingPathComponent: key] toPath: [[receiptsFolder stringByAppendingPathComponent: [packagePath lastPathComponent]] stringByAppendingPathComponent: key] handler: nil] != NO)
	{
	  NSLog (@"Copying receipt %@", key);
	}
      else
	{
	  NSLog (@"Copying receipt ERRORfrom %@ to %@", [packagePath stringByAppendingPathComponent: key], [receiptsFolder stringByAppendingPathComponent: [packagePath lastPathComponent]]);
	}
      */

  return YES;
}

  - (BOOL) preInstall
{

    NSLog (@"preInstall: %@ , %@", packagePath, installLocation);

  return YES;
}
- (BOOL) postInstall
{
  //  NSLog (@"*** postInstall: %@, %@", packagePath, [self packageLocation]);
  return YES;
}


- (int) currentStep
{
  NSLog (@"Doing step");
  return 1;
}

- (int) totalSteps
{
  totalSteps = [[bom objectForKey: @"Files"] count];
  return totalSteps;
  //  return 10;
}

- (BOOL) isRelocatable
{
 
  NSLog (@"Rel: %@",[infoPlist objectForKey: @"IFPkgFlagRelocatable"]);
  if ([infoPlist objectForKey: @"IFPkgFlagRelocatable"] != NO )
    return NO;
  else
    return YES;
}

- (BOOL) setPackageLocation: (NSString *) packageLocation
{
  /*
  if ([installLocation initWithString: packageLocation] != nil)
    return YES;
  else
    return NO;
  */
  ASSIGN (installLocation, packageLocation);
  return YES;
}
@end
