#import <appkit/appkit.h>

#import "Controller.h"
#import "PhotoWinProcs.h"
#import "ImageView.h"
#import "Overviews.subproj/OV_Window.h"
#import "Photo_CD.subproj/photoCD_Rdr.h"

#define IMG  0
#define WIN  1	

#define TIFF 0
#define EPS  1
#define JPG  2

@implementation Controller

- appDidInit:sender
{
	int	tempInt;
	char	tempStr[30];
	PrintInfo  *pInfo;
	enum _NXWindowDepth depthPref;
	NXDefaultsVector defs =
	    {
	    {"GammaCorrection","NeXT"},
	    {"OpenImageSize","base"},
	    {"OpenImageResolution","72"},
	    {"OpenImageWindowDepth","24_Bit_RGB"},
	    {"OverviewLayout","6x7"},
	    {"PrintPagination","ScaleToFit"},
	    {"pCDdebug_MaxOverview","0"},
	    {"SharpenImage","NO"},
	    {NULL,NULL}
	    };
	
	// defaults processing
	NXRegisterDefaults([NXApp appName], defs);

	globImageSize = is_Base_TAG;
	if ( NXGetDefaultValue([NXApp appName],"OpenImageSize") ) {
	    strcpy( tempStr, NXGetDefaultValue([NXApp appName],
			    "OpenImageSize"));
	    if ( !strcmp(tempStr, "base/16") ) globImageSize = is_Base16_TAG;
	    if ( !strcmp(tempStr, "base/4") )  globImageSize = is_Base4_TAG;
	    if ( !strcmp(tempStr, "base") )    globImageSize = is_Base_TAG;
	    if ( !strcmp(tempStr, "4base") )   globImageSize = is_4Base_TAG;
	    if ( !strcmp(tempStr, "16base") )  globImageSize = is_16Base_TAG;
	    }
	
	globImageResolution = 72;
	if ( NXGetDefaultValue([NXApp appName],"OpenImageResolution") ) {
	    strcpy( tempStr, NXGetDefaultValue([NXApp appName],
			    "OpenImageResolution"));
	    /* probably should just accept this as an integer, but... */
	    if ( !strcmp(tempStr,  "72") ) globImageResolution = 72;
	    if ( !strcmp(tempStr, "144") ) globImageResolution = 144;
	    if ( !strcmp(tempStr, "150") ) globImageResolution = 150;
	    if ( !strcmp(tempStr, "180") ) globImageResolution = 180;
	    if ( !strcmp(tempStr, "200") ) globImageResolution = 200;
	    if ( !strcmp(tempStr, "300") ) globImageResolution = 300;
	    if ( !strcmp(tempStr, "360") ) globImageResolution = 360;
	    if ( !strcmp(tempStr, "400") ) globImageResolution = 400;
	    }
	
	overviewLayoutTag = ov_6x7_TAG;
	if ( NXGetDefaultValue([NXApp appName],"OverviewLayout") ) {
	    strcpy( tempStr, NXGetDefaultValue([NXApp appName],
			    "OverviewLayout"));
	    if ( ! strcmp(tempStr, "10x2") ) overviewLayoutTag = ov_10x2_TAG;
	    if ( ! strcmp(tempStr, "6x7") )  overviewLayoutTag = ov_6x7_TAG;
	    if ( ! strcmp(tempStr, "2x12") ) overviewLayoutTag = ov_2x12_TAG;
	    }
	[self loadOverviewNib:overviewLayoutTag andSave:NO];
	
	depthPref = NX_TwentyFourBitRGBDepth;
	if ( NXGetDefaultValue([NXApp appName],"OpenImageWindowDepth") ) {
	    strcpy( tempStr, NXGetDefaultValue([NXApp appName],
			    "OpenImageWindowDepth"));
	    if ( ! strcmp(tempStr, "DefaultDepth") ) 
	    				depthPref = NX_DefaultDepth;
	    if ( ! strcmp(tempStr, "2_Bit_Grey") ) 
	    				depthPref = NX_TwoBitGrayDepth;
	    if ( ! strcmp(tempStr, "8_Bit_Grey") ) 
	    				depthPref = NX_EightBitGrayDepth;
	    if ( ! strcmp(tempStr, "12_Bit_RGB") ) 
	    				depthPref = NX_TwelveBitRGBDepth;
	    if ( ! strcmp(tempStr, "24_Bit_RGB") ) 
	    				depthPref = NX_TwentyFourBitRGBDepth;
	    }
	[photoWindow setDepthOfNewWindows:depthPref];
	
	globSharpenImage = NO;
	if ( NXGetDefaultValue([NXApp appName],"SharpenImage") ) {
	    strcpy( tempStr, NXGetDefaultValue([NXApp appName],
			    "SharpenImage"));
	    if ( ! strcmp(tempStr, "Yes") ) 
	    				globSharpenImage = YES;
	    if ( ! strcmp(tempStr, "YES") ) 
	    				globSharpenImage = YES;
	    }
	[pCD_Reader setDoSharp:globSharpenImage];
	
	globNextGamma = YES;
	if ( NXGetDefaultValue([NXApp appName],"GammaCorrection") ) {
	    strcpy( tempStr, NXGetDefaultValue([NXApp appName],
			    "GammaCorrection"));
	    if ( ! strcmp(tempStr, "2.2") ) 
	    				globNextGamma = YES;
	    if ( ! strcmp(tempStr, "NeXT") ) 
	    				globNextGamma = YES;
	    if ( ! strcmp(tempStr, "None") ) 
	    				globNextGamma = NO;
	    if ( ! strcmp(tempStr, "Linear") ) 
	    				globNextGamma = NO;
	    }
	[pCD_Reader setNextGammaCorrection:globNextGamma];
	
	printPagination = NX_FITPAGINATION;
	if ( NXGetDefaultValue([NXApp appName],"PrintPagination") ) {
	    strcpy( tempStr, NXGetDefaultValue([NXApp appName],
			    "PrintPagination"));
	    if ( ! strcmp(tempStr, "SplitAcrossPages") ) 
	    				printPagination = NX_AUTOPAGINATION;
	    if ( ! strcmp(tempStr, "ScaleToSinglePage") ) 
	    				printPagination = NX_FITPAGINATION;
	    if ( ! strcmp(tempStr, "ClipToSinglePage") ) 
	    				printPagination = NX_CLIPPAGINATION;
	    }

	//  The following preference is useful when debugging, so the
	//      program only reads part of overview.pcd. 
	overviewReadMax = ovImageMax;
	if ( NXGetDefaultValue([NXApp appName],"pCDdebug_MaxOverview") ) {
	    tempInt = atoi( NXGetDefaultValue([NXApp appName],
			    "pCDdebug_MaxOverview"));
	    if ((tempInt > 0) && (tempInt < ovImageMax))
	    				overviewReadMax = tempInt;
	    }
	
	//  should printWhich and saveTo be preferences too?
	printWhich = IMG;
	
	//  Try to make sure each paste operation gets a window
	//     with a unique title.
	pasteCounter = 0;

	sp = [SavePanel new];
	[sp setAccessoryView:saveAccessory];
	[sp setRequiredFileType:"tiff"]; saveTo = TIFF;
	
	pp = [PrintPanel new];
	[pp setAccessoryView:printAccessory];
	pInfo = [[PrintInfo alloc] init];
	[pInfo setVertPagination:printPagination];
	[pInfo setHorizPagination:printPagination];
	[NXApp setPrintInfo:pInfo];
	saveTo = TIFF;

	// initialize overview panel
	volumeDir = NULL;
	for( ovImageCount=0; ovImageCount < ovImageMax; ovImageCount++ ) {
	    ovImageIds[ovImageCount] = nil;
	}
	ovImageCount = 0;

// Start out by requesting Photo CD volume.
// For now, ask for the appropriate directory.

	[self openPCD:self];

	return self;
}

- (int)nextPasteCounter
{
    // called from ImageView objects by a rather dubious route...
    
    return ++pasteCounter;
}

- showInfoPanel:sender
{
    if ( ! infoPanel )
	infoPanel = [NXApp loadNibSection:"pCD_Info.nib" owner:self];
    [infoPanel makeKeyAndOrderFront:self];

    return self;
}

- showOverviewWindow:sender
{
    if ( overviewId ) {
        [overviewId showOverview];
	}
    
    return self;
}

- showPrefsPanel:sender
{
    int		paginationTag;
    
    paginationTag = ppag_ScaleToSinglePage;
    if ( printPagination == NX_AUTOPAGINATION )
    			paginationTag = ppag_SplitAcrossPages;
    if ( printPagination == NX_CLIPPAGINATION )
    			paginationTag = ppag_ClipToSinglePage;
    [prefsPaginationMatrix selectCellWithTag:paginationTag ];
    
    [prefsResolutionMatrix selectCellWithTag:globImageResolution ];
    [prefsSizeMatrix selectCellWithTag:globImageSize ];
    [prefsLayoutMatrix selectCellWithTag:overviewLayoutTag ];

    [prefsSharpenSwitch setState:globSharpenImage ];
    [prefsNGammaSwitch setState:globNextGamma ];

    [prefsPanel makeKeyAndOrderFront:self];    
    return self;
}

- setPrefImageResolution:sender
{
    char	tempStr[20];
    
    globImageResolution = [sender selectedTag];
    sprintf(tempStr, "%d", globImageResolution);
    NXWriteDefault([NXApp appName], "OpenImageResolution", tempStr);

    return self;
}

- setPrefImageSize:sender
{
    globImageSize = [sender selectedTag];
    switch ( globImageSize ) {
       case is_Base16_TAG:
	    NXWriteDefault([NXApp appName], "OpenImageSize", "base/16");
	    break;
       case is_Base4_TAG:  
	    NXWriteDefault([NXApp appName], "OpenImageSize", "base/4");
	    break;
       case is_4Base_TAG:
	    NXWriteDefault([NXApp appName], "OpenImageSize", "4base");
	    break;
       case is_16Base_TAG:
	    NXWriteDefault([NXApp appName], "OpenImageSize", "16base");
	    break;
       default:
	    NXWriteDefault([NXApp appName], "OpenImageSize", "base");
	    break;
       }

    return self;
}

- setPrefNextGamma:sender
{
    char	tempStr[20];
    
    globNextGamma = [sender state];
    if ( globNextGamma ) strcpy(tempStr, "NeXT");
    else                 strcpy(tempStr, "Linear");
    NXWriteDefault([NXApp appName], "GammaCorrection", tempStr);

    [pCD_Reader setNextGammaCorrection:globNextGamma];
    return self;
}

- setPrefOverviewLayout:sender
{
    // if an overview layout is set, close it
    if ( overviewId ) {
	[overviewId closeOverviewPanel:self];
	overviewId = nil;
	}

    [self loadOverviewNib:[sender selectedTag] andSave:YES];
    [overviewId setImageArray:&ovImageIds imageCount:ovImageCount];
    [self showOverviewWindow:self];

    return self;
}

- setPrefPagination:sender
{
    int		pagTag;
    char	strValue[20];
    PrintInfo	*pInfo;
    
    pagTag = [sender selectedTag];
    switch ( pagTag ) {
       case ppag_SplitAcrossPages:
	    printPagination = NX_AUTOPAGINATION;
	    strcpy(strValue, "SplitAcrossPages");
	    break;
       case ppag_ClipToSinglePage:
	    printPagination = NX_CLIPPAGINATION;
	    strcpy(strValue, "ClipToSinglePage");
	    break;
       default:		/* assumed to be ppag_ScaleToSinglePage */
	    printPagination = NX_FITPAGINATION;
	    strcpy(strValue, "ScaleToSinglePage");
	    break;
       }

    pInfo = [NXApp printInfo];
    [pInfo setVertPagination:printPagination];
    [pInfo setHorizPagination:printPagination];
    NXWriteDefault([NXApp appName], "PrintPagination", strValue);
    return self;
}

- setPrefSharpen:sender
{
    char	tempStr[20];
    
    globSharpenImage = [sender state];
    if ( globSharpenImage ) strcpy(tempStr, "Yes");
    else                    strcpy(tempStr, "No");
    NXWriteDefault([NXApp appName], "SharpenImage", tempStr);

    [pCD_Reader setDoSharp:globSharpenImage];
    return self;
}

/*  sample:  [self loadOverviewNib:overviewLayoutTag andSave:NO]; */

- loadOverviewNib:(enum ov_Tags)overviewTag andSave:(BOOL)saveDefault
{
    char	prefString[10];
    
    overviewLayoutTag = overviewTag;
    
    switch ( overviewLayoutTag ) {
       case ov_10x2_TAG:
	    strcpy(prefString, "10x2");
	    if ( ! ov_10x2_Id )
		[NXApp loadNibSection:"Overview_10x2.nib" owner:self
			    withNames:YES];
	    overviewId = ov_10x2_Id;
	    break;
       case ov_2x12_TAG:
	    strcpy(prefString, "2x12");
	    if ( ! ov_2x12_Id )
		[NXApp loadNibSection:"Overview_2x12.nib" owner:self
			    withNames:YES];
	    overviewId = ov_2x12_Id;
	    break;
       default:
	    strcpy(prefString, "6x7");
	    if ( ! ov_6x7_Id )
		[NXApp loadNibSection:"Overview.nib" owner:self
			    withNames:YES];
	    overviewId = ov_6x7_Id;
	    break;
       }
    
    if ( saveDefault ) {
	NXWriteDefault([NXApp appName], "OverviewLayout", prefString);
	}
    
    return self;
}

- openPCD:sender
{
    id		op;
    char	*lastSlash;
    char	*openDir = "/";
    const char	*types[] = {"pcd", NULL};
	
    op = [OpenPanel new];
    [op setPrompt:"Photo CD:"];
    [op setTitle:"Photo CD Volume"];

    /* note that really odd things happen if you set chooseDirectories
     * to YES and then the user chooses a file (such as overview.pcd)
    */
    [op chooseDirectories:YES];
    
    if( volumeDir ) openDir = volumeDir;

    if( [op runModalForDirectory:openDir file:"" types:types]) {
	if( volumeDir ) free(volumeDir);
	volumeDir = malloc( strlen([op filename]) + 10 + 1 );
	strcpy(volumeDir, [op filename] );
	
	/* crude parsing of the file/directory the user selected,
	   which makes things a little nicer for the average user
	   who is trying to open up a real photo CD
	   
	   programming note: In NS3.0, if "chooseDirectories" is YES
	   and the user selects a file, then "filename" returned is
	   apparently *missing* a directory.  So if the user selects
	   "/PCD1909/photo_cd/overview.pcd", then the filename the
	   program sees is "/PCD1909/overview.pcd" !!!
	   
	   The order of the following checks happens to fix that well
	   enough for the purposes of this program.  Sounds like a
	   pretty weird bug to me though!
	*/
	lastSlash = strrchr(volumeDir, '/');
	if ( lastSlash ) {
	    if ( ! strcmp(lastSlash, "/overview.pcd") ) {
		*lastSlash = '\0';
		lastSlash = strrchr(volumeDir, '/');
		}
	    if ( 0 != strcmp(lastSlash, "/photo_cd") ){
		strcat(volumeDir, "/photo_cd");
		}
	    }

	if ( [self readOverview] ) {
	    [overviewId setImageArray:&ovImageIds imageCount:ovImageCount];
	    [self showOverviewWindow:self];
	    }
	}
    
    return self;
}

- readOverview
{
	char	*ovFil;

	ovFil = malloc(strlen(volumeDir) + strlen("/overview.pcd") + 1);
	strcpy(ovFil, volumeDir);
	strcat(ovFil, "/overview.pcd");
	
	ovImageCount = [pCD_Reader readOverviewFromFile:ovFil
			curImageCount:ovImageCount
			ImageArray:&ovImageIds
			MaxEntries:overviewReadMax];

	free(ovFil);
	[readStatusPanel close];

	return self;
}

- showImage:(int)pictNumber atSize:(enum is_Tags)imageSizeWanted
			     atRes:(int)imageResolutionWanted
{
    NXBitmapImageRep  *bm;
    char	*imDir, *title, tmpStr[10];
    char	*imFile = malloc( strlen("/images/imgxxxx.pcd ") +1 );
	    
    imDir = malloc(strlen(volumeDir) + malloc_size(imFile) + 1);
    strcpy(imDir, volumeDir);
    strcat(imDir, "/images");
    sprintf(imFile, "/img%04d.pcd", pictNumber );
    strcat(imDir, imFile);
    
    if ( imageSizeWanted == is_GlobalPref_TAG )
    			imageSizeWanted = globImageSize;
    bm = [pCD_Reader readBitmapFromFile:imDir atSize:imageSizeWanted];

    //	the window title name will include information on the
    //  image size and resolution.
    title = malloc(strlen(volumeDir) + malloc_size(imFile) + 10);
    strcpy(title, volumeDir);
    sprintf(imFile, "/img%04d.", pictNumber );
    strcat(title, imFile);

    switch ( imageSizeWanted ) {
	case is_Base16_TAG:	strcat(title, "base16");  break;
	case is_Base4_TAG:	strcat(title, "base4");  break;
	case is_Base_TAG:	strcat(title, "base"); break;
	case is_4Base_TAG:	strcat(title, "4base"); break;
	case is_16Base_TAG:	strcat(title, "16base"); break;
	default:		strcat(title, "?base?"); break;
	}

    if ( imageResolutionWanted == ir_GlobalPref_TAG )
    			imageResolutionWanted = globImageResolution;
    sprintf(tmpStr, "_@%03ddpi", imageResolutionWanted);
    strcat(title, tmpStr);

    [photoWindow displayImage:bm withName:title
				 atResolution:imageResolutionWanted];
		
    free(imFile);
    free(imDir);
    return self;
}

- changeSaveType:sender
{
    switch ([sender selectedRow]) {
	case 0: [[sender window] setRequiredFileType:"tiff"]; saveTo = TIFF; break;
	case 1: [[sender window] setRequiredFileType:"eps"]; saveTo = EPS; break;
	case 2: [[sender window] setRequiredFileType:"jpg"]; saveTo = JPG; break;
    }
    return self;
}

- changePrintType:sender
{
    switch ([sender selectedRow]) {
	   case 0: printWhich = IMG; break;
	   case 1: printWhich = WIN; break;
    }
    return self;
}

- saveTo:sender
{
	NXStream   *st;
	int  status;
	
	if( status = [sp runModalForDirectory:"." file:"Untitled"]) {
	   st = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	   switch( saveTo ) {
	      case TIFF:
	         [[[[NXApp mainWindow] contentView] image] writeTIFF:st];
		     break;
		  case EPS:
		     [[[NXApp mainWindow] contentView] copyPSCodeInside:NULL to:st];
			 break;
		  case JPG:
		     [[[[NXApp mainWindow] contentView] image]
			           writeTIFF:st usingCompression:NX_TIFF_COMPRESSION_JPEG];
			 break;
	   }
	   NXSaveToFile(st, [sp filename]);
	   NXCloseMemory(st, NX_FREEBUFFER);
	}
	return self;
}

- printSel:sender
{
	int exitTag;
	
	exitTag = [pp runModal];
	[pp orderOut:self];
	if( exitTag != NX_CANCELTAG ) {
	   [pp finalWritePrintInfo];
	   switch ( printWhich ) {
	      case IMG:
	         [[[NXApp mainWindow] contentView] printPSCode:self];
	         break;
	      case WIN:
	         [[NXApp mainWindow] printPSCode:self];
	         break;
	   }
	}
	return self;
}

- (BOOL)shouldRunPrintPanel:aView
{
	return NO;
}

@end
