#import "WindowDepth.h"
#import "MyNXBrowserCell.h"
#import "common.h"

#define MAX_LINE_LEN 2048	// Maximum length of one preferences entry

/* Used to store temporary information */
typedef struct {
    NXAtom owner;		// The name of the application
    int value;			// The WindowDepthLimit
    BOOL test;			// YES if using Test prefix
} appInfo;

/* Names used in defaults database (non-test mode) */
static char *defaultnames[] = {
    "TwoBitGray",
    "EightBitGray",
    "TwelveBitRGB",
    "TwentyFourBitRGB"
};

/* Names used in defaults database (test mode) */
static char *defaulttestnames[] = {
    "TestTwoBitGray",
    "TestEightBitGray",
    "TestTwelveBitRGB",
    "TestTwentyFourBitRGB"
};


@interface WindowDepth(Private)
- setBrowserCell:(appInfo *)set withMatrix:matrix atRow:(int)row;
@end

@implementation WindowDepth(Private)

/*=========================================================================
 * NAME        : setBrowserCell:withMatrix:
 * DESCRIPTION : Insert a new cell in the browser.
 *=========================================================================*/
- setBrowserCell:(appInfo *)set withMatrix:matrix atRow:(int)row
{
    id cell;
    
    [matrix addRow];
    cell = [matrix cellAt:row :0];	
    [cell setStringValue:set->owner];
    [cell setTag:row];
    [cell setLoaded:YES];
    [cell setLeaf:YES];
    [cell setOwner:set->owner];
    [cell setDepth:set->value];
    [cell setTestMode:set->test];
    return self;
}

@end

@implementation WindowDepth

/*=========================================================================
 * NAME        : + new
 * DESCRIPTION : Called first time this section's button is clicked.
 *=========================================================================*/
+ new
{
    self = [super new];
    
    if (![NXApp loadNibForLayout: "WindowDepth" owner: self])
	return nil;
	
    // 'window' is an interface builder outlet.
    view = [window contentView];	// 'view' MUST be initialized
    [view removeFromSuperview];
    [window setContentView: 0];		// Don't need the window for anything
    [window free];			// So free it.
    
    // When multiple items (or none) are selected, no radio button is set
    [appRadio setEmptySelectionEnabled:YES];
    [appRadio clearSelectedCell];

    // Browser uses a custom Cell
    [browser setCellClass:[MyNXBrowserCell class]];
    
    return self;
}

/*=========================================================================
 * NAME        : willSelect:
 * DESCRIPTION : Before the view is added via addSubview.
 *=========================================================================*/
- willSelect: sender
{
    return self;
}

/*=========================================================================
 * NAME        : didSelect:
 * DESCRIPTION : After the view is added via addSubview.
 *=========================================================================*/
- didSelect: sender
{
    // Enable relevant menu items
    [NXApp enableEdit:COPY_ITEM];
    [NXApp enableWindow:CLOSE_ITEM];
    
    // Rebuild the list of apps and preferences
    [self rescanPrefs:self];
    
    return self;
}


/*=========================================================================
 * NAME        : willUnselect:
 * DESCRIPTION : Before removeFromSuperview
 *=========================================================================*/
- willUnselect: sender
{
    // Make sure that we aren't editing any text fields.
    [[NXApp appWindow] endEditingFor:self];  
    return self;
}

/*=========================================================================
 * NAME        : didUnselect:
 * DESCRIPTION : Before removeFromSuperview
 *=========================================================================*/
- didUnselect: sender
{
    // Hide our info panel
    [infoPanel orderOut:self];
    
    // Disable all Edit and Window menu items
    [NXApp enableEdit: NO];
    [NXApp enableWindow: NO];
    return self;
}

/*=========================================================================
 * NAME        : didHide:
 * DESCRIPTION : Application was just hidden.
 *=========================================================================*/
- didHide: sender
{
    return self;
}

/*=========================================================================
 * NAME        : didUnhide:
 * DESCRIPTION : Application was just unhidden.
 *=========================================================================*/
- didUnhide: sender
{
    return self;
}

/*=========================================================================
 * NAME        : rescanPrefs:
 * DESCRIPTION : Rescan the user's preferences.
 *=========================================================================*/
- rescanPrefs:sender
{
    // Cause the browser to reload
    [browser loadColumnZero];
    
    return self;
}

/*=========================================================================
 * NAME        : itemSelected:
 * DESCRIPTION : Target of NXBrowser.
 *=========================================================================*/
- itemSelected:sender
{
    id matrix;
    List *aList;
    id cell;
    
    // Get a list of all the selected cells in the browser
    matrix = [browser matrixInColumn:0];
    aList = [[List alloc] init];
    [matrix getSelectedCells:aList];
    
    // Set the radio button and switch to match the selection
    if ([aList count] == 0) {
        [appRadio clearSelectedCell];
	[appRadio display];
	[appSwitch setState:0];
        [appRadio setEnabled:NO];
	[appSwitch setEnabled:NO];
    } else if ([aList count] == 1) {
        cell = [aList objectAt:0];
        [appRadio selectCellWithTag:[cell depth]];
	[appSwitch setState:[cell testMode]];
	[appRadio setEnabled:YES];
	[appSwitch setEnabled:YES];
    } else {
        if (![appRadio isEnabled]) {
	    [appRadio setEnabled:YES];
	    [appSwitch setEnabled:YES];
	}
        [appRadio clearSelectedCell];
	[appRadio display];
	[appSwitch setState:0];
    }
    [aList free];
    return self;
}

/*=========================================================================
 * NAME        : browser:fillMatrix:inColumn:
 * DESCRIPTION : Delegate message from browser requesting a reload.
 *=========================================================================*/
- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
    appInfo set;
    FILE *fp;
    char *line;
    char *owner, *variable, *value;
    NXAtom newOwner, prevOwner;
    int i;
    int globalSetting = USE_DEFAULT;
    BOOL globalTestSetting = NO;
    int count;
    
    // Call the 'dread' command as a subprocess
    fp = popen("dread -l | sort -", "r");
    if (!fp) {
        NXLogError("WindowDepth.preferences: unable to popen(\"dread -l\")\n");
        NXBeep();
	return 0;
    }
    
    // Get ready to read, erase previous information
    line = malloc(MAX_LINE_LEN+1);
    prevOwner = NULL;
    set.owner = NULL;
    count = 0;
    
    // Process the subprocess output, line by line
    while (fgets(line, MAX_LINE_LEN, fp)) {
        
	// Isolate the first two fields
	if (!(owner = strtok(line, " \"\n\t"))) {
	    continue;
	}
        if (!(variable = strtok(NULL, " \"\n\t"))) {
	    continue;
	}
	
	// New owner found?
	newOwner = NXUniqueString(owner);
	if (newOwner != prevOwner) {
	    
	    // Add the previous owner to browser, unless it's GLOBAL
	    if (set.owner) {
	        if (strcmp(set.owner, "GLOBAL")) {
		    [self setBrowserCell:&set withMatrix:matrix atRow:count];
		    count++;
		} else if (set.value != USE_DEFAULT) {
		    globalSetting = set.value;
		    globalTestSetting = set.test;
		}
	    }
	    
	    // Set up this entry
	    set.owner = newOwner;
	    set.value = USE_DEFAULT;
	    set.test = NO;
	    prevOwner = newOwner;
        }  
  
	// Is this the NXWindowDepthList entry?
	if (strcmp(variable, "NXWindowDepthLimit")) {
	    continue;
	}
	    
	// Yes, find the setting
	if (!(value = strtok(NULL, " \"\n\t"))) {
	    continue;
	}

        // Is this a setting we know?
	for (i = 0; i < 4; i++) {
	    if (!strcmp(value, defaultnames[i])) {
	        set.value = i;
		set.test = NO;
	    }
	}
	
	// Not found so try the Test modes
	if (i == 4) {
	    for (i = 0; i < 4; i++) {
	        if (!strcmp(value, defaulttestnames[i])) {
		    set.value = i;
		    set.test = YES;
		}
	    }
	}
    }

    // Write the last owner
    if (set.owner) {
    	[self setBrowserCell:&set withMatrix:matrix atRow:count];
        count++;
    }
        
    // Deallocate resources
    free(line);
    pclose(fp);

    // Set the radio buttons for the GLOBAL setting
    [defaultRadio selectCellWithTag:globalSetting];
    [defaultSwitch setState:globalTestSetting];
    
    // Nothing is currently selected in the browser
    [appRadio clearSelectedCell];
    [appSwitch setState:0];
    [appRadio setEnabled:NO];
    [appSwitch setEnabled:NO];
    
    return count;    
}

/*=========================================================================
 * NAME        : setDefault:
 * DESCRIPTION : Target of Default radio button matrix.
 *=========================================================================*/
- setDefault:sender
{
    char command[256];
    int offset = [[defaultRadio selectedCell] tag];
    
    if (offset == 4) {
        sprintf(command, "dremove -g NXWindowDepthLimit");
	[defaultSwitch setState:0];
    } else if ([defaultSwitch state]) {
        sprintf(command, "dwrite -g NXWindowDepthLimit %s",
	        defaulttestnames[offset]);
    } else {
        sprintf(command, "dwrite -g NXWindowDepthLimit %s",
	        defaultnames[offset]);
    }
    system(command);
    return self;
}

/*=========================================================================
 * NAME        : setApp:
 * DESCRIPTION : Target of Application radio button matrix.
 *=========================================================================*/
- setApp:sender
{
    char command[256];
    id matrix;
    List *aList;
    int count, total;
    NXAtom owner;
    id cell;
    int offset = [[appRadio selectedCell] tag];
    
    // Get a list of all the selected cells in the browser
    matrix = [browser matrixInColumn:0];
    aList = [[List alloc] init];
    [matrix getSelectedCells:aList];
    
    // Modify the defaults database to match
    total = [aList count];
    for (count = 0; count < total; count++) {
        cell = [aList objectAt:count];
	owner = [cell owner];
        if (offset == 4) {
	    [appSwitch setState:0];
            sprintf(command, "dremove %s NXWindowDepthLimit", owner);
        } else if ([appSwitch state]) {
            sprintf(command, "dwrite %s NXWindowDepthLimit %s",
	            owner, defaulttestnames[offset]);
        } else {
            sprintf(command, "dwrite %s NXWindowDepthLimit %s",
	            owner, defaultnames[offset]);
        }
        system(command);
	
	[cell setStringValue:owner];
	[cell setLoaded:YES];
	[cell setDepth:offset];
	[cell setTestMode:[appSwitch state]];
    }
    
    [aList free];
    [browser displayColumn:0];
    return self;
}

@end
