//************************************************************************
//
//	HLDelegate.m.  
//
//		NXBrowser delegate of the Hot list and HotList controller
//
//			by	Felipe A. Rodriguez		
//
//	This code is supplied "as is" the author makes no warranty as to its 
//	suitability for any purpose.  This code is free and may be distributed 
//	in accordance with the terms of the:
//		
//			GNU GENERAL PUBLIC LICENSE
//			Version 2, June 1991
//			copyright (C) 1989, 1991 Free Software Foundation, Inc.
// 			675 Mass Ave, Cambridge, MA 02139, USA
//
//************************************************************************


#import "GKdefs.h"
#import "HLDelegate.h"
#import "HLRecord.h"
#import "Coordinator.h"
#import <appkit/appkit.h>
#import <dbkit/DBImageView.h>

#import <sys/types.h>
#import <sys/dir.h>  /* POSIX applications #include <dirent.h> */


@implementation HLDelegate

//************************************************************************
//
//		sent to us after nib objects are unarchived and init'd 
//
//************************************************************************

- awakeFromNib
{
char *sC;
NXRect spVRect;							// sizeof splitview
NXSize maxSize = {300.0, 600.0};		// max hotlist win size

	[[HLImageView setEditable:NO] setStyle:DB_ImageNoFrame];

				// theSplitView -- IB connected to be top view
	[theSplitView getFrame: &spVRect];
	spVRect.size.width -= 20;	
	sC = NXCopyStringBuffer(NXGetDefaultValue([NXApp appName],BROWSERHT));
				// if not def and val is less than splitview's height
	if(atof(sC) > 600.0 || atof(sC) < 0.0)	
		spVRect.size.height *= 2.0/3.0;	// def, make top view 2/3 of splitview
	else		 						
		spVRect.size.height = atof(sC);					// per saved 
	free(sC);

	HLBrowser = [[NXBrowser alloc] initFrame:&spVRect];
	[[[[[[[[HLBrowser setTitled:NO] 		// create and configure nxbrowser
					setHorizontalScrollButtonsEnabled:NO]
					setDelegate:self]
					setTarget:self]
					setAction:@selector(browserHit:)]
					setDoubleAction:@selector(browserDoubleClick:)]
					setMinColumnWidth:200]
					setMaxVisibleColumns:1];

	[theSplitView addSubview:HLBrowser];
	sC = NXCopyStringBuffer(NXGetDefaultValue([NXApp appName], ADDRESSHT));
	if(atof(sC) > 600.0 || atof(sC) < 0.0)	
		spVRect.size.height /= 2.0;		// make bottom view 1/3 of splitview
	else		 						
		spVRect.size.height = atof(sC);					// per saved 
	free(sC);
	[addressView setFrame:&spVRect];
	[theSplitView addSubview:addressView];
	[theSplitView display];

	if(![[NXBundle mainBundle]getPath:oPath forResource:"options" ofType:NULL])
		oPath[0] = '\0';
	[self initHotListPath];		
				// set each view in the heirarchy to resize its subviews
	[hotList setMaxSize:&maxSize];			 
	[hotList setFrameUsingName:[hotList title]];			// remem 
	[hotList setFrameAutosaveName:[hotList title]];

    return self;
}
//*****************************************************************************
//
// 		initialize the hotlist and reinit if path to it is changed 
//
//*****************************************************************************

- initHotListPath 
{
char *sC;
				//	cell selection in hotList should persist between sessions
				//	so recall previous selection
	sC = NXCopyStringBuffer(NXGetDefaultValue([NXApp appName],SELCELL));		
	selCell = atoi(sC);
	free(sC);

	[HLBrowser loadColumnZero];		// NXBrowser s/load cols from its delegate
	if(hotListDirValid)				// if hotList path is valid
		{
		mat = [HLBrowser matrixInColumn:0];		
		[HLBrowser useScrollButtons:NO];		
		if(!(selCell < [dirList count]))
			selCell = 0;
		if(selCell < [dirList count])
			{
			[mat selectCellAt:selCell :0];
			if(!(image = [[dirList objectAt:selCell] gateIcon]))	
				image = [NXImage findImageNamed: "Blank"];	// else use blank
			[mat scrollCellToVisible:selCell :0];
			}
		else
			image = [NXImage findImageNamed: "Blank"];	// else use blank
		[HLImageView setImage:image];
		[HLProviderField setStringValue:
					[[[HLBrowser matrixInColumn:0] selectedCell] stringValue]];
		}													

	return self;
}
//*****************************************************************************
//
// 		provide to listBrowser(NXBrowser) it's data to be displayed
//			do this because we are its delegate  
//
//*****************************************************************************

- (int)browser:b fillMatrix:m inColumn:(int)c
{
int	i = 0, strSize;
id t, obj = nil;
char *ptr;
NXHashState state;
const void  *key; 
void  *value; 
struct direct *dirp;
static DIR *dp = NULL, *dpOLD = NULL;

	if(dp)
		dpOLD = dp;
    if ((dp = opendir(NXGetDefaultValue([NXApp appName], "HotList"))) != NULL)
		{
		if(!namHashTable)				// alloc hashtable w/str keys, obj vals
			namHashTable = [[HashTable alloc] initKeyDesc:"*" valueDesc:"@"];
		else
			{
			tmpHashTable = [namHashTable copyFromZone:[self zone]];
			[namHashTable empty];
			}
		if(dirList)
			[dirList empty];					// empty list
		else
			dirList = [[List alloc] init];		// produce an array of objects
		if ([tmpHashTable isKey:"AppDefault"] == NO) 	
			{						// create a HotList record for app default
			if (oPath[0] != '\0') 	// if options file exists in app wrapper
				{					
				obj = [[HLRecord alloc] init];	
				[obj setRecordPath:oPath];
				[namHashTable insertKey:"AppDefault" value:obj];
				}							
			}							// if record exists in hash
		else							// use existing record
			[namHashTable insertKey:"AppDefault" 	
								value:[tmpHashTable valueForKey:"AppDefault"]];
		while (dirp = readdir(dp)) 				// read dir and find all
			{									// entries with ext .Gate
			if((strSize = strlen(dirp->d_name)) > 5)
				{
				ptr = dirp->d_name + strSize;		// point to end of name str
				ptr -= 5;						
				if(strcmp(ptr, ".Gate") == 0)		// if extension is .Gate
					{								// if str not in hash table
					if ([tmpHashTable isKey:dirp->d_name] == NO) 	
						{							// create a HotList record
						obj = [[HLRecord alloc] init];	
						[obj setGateDocName:dirp->d_name];
						[namHashTable insertKey:dirp->d_name value:obj];
						}							// if record exists in hash
					else							// use existing record
						[namHashTable insertKey:dirp->d_name 	
								value:[tmpHashTable valueForKey:dirp->d_name]];
					}
				}
			};
		[tmpHashTable free];
		if(dpOLD)
			closedir(dpOLD);
									// sort and display dir in NXBrowser
		for(i = 0; i < [namHashTable count]; i++) 
			{						// Return NXHashState structure required 
									// when iterating through the HashTable
			state = [namHashTable initState]; 
			while ([namHashTable nextState:&state key:&key value:&value]) 
				{					// iterate thru the hashtable and perform
				if ([dirList indexOf:value] == NX_NOT_IN_LIST)
					{
					if(!obj)
						obj = value;					// an ascending sort
					if(strcasecmp(key, [obj gateDocName]) < 0)		
						obj = [namHashTable valueForKey:key];
					}			
				};
			[m addRow];								// add row to HotList matrx
			t = [m cellAt:i :0];					// ret cell in NXBrowser
			[dirList addObject:obj];
			[t setStringValueNoCopy:[obj gateDocName]];
			[t setLoaded:YES];
			[t setLeaf:YES];
			obj = nil;
			}
		hotListDirValid = YES;						// hotList dir was opened
		}
	else
		{
		[[NXApp delegate] showAlert:"Error opening HotList directory."];
		hotListDirValid = NO;						// hotList dir is invalid
		}

    return i; 
}
//*****************************************************************************
//
//  target/action for a single click in the browser. 
//
//*****************************************************************************

- browserHit:sender
{   
  	selCell = [[sender matrixInColumn:0] selectedRow];
	[self setDispPerCellAt:selCell];			// display traits of sel'd cell

    return self;
}
//*****************************************************************************
//
//  target/action method for a double click in the browser.  
//
//*****************************************************************************

- browserDoubleClick:sender
{   
  	selCell = [[sender matrixInColumn:0] selectedRow];
	[self setDispPerCellAt:selCell];			// display traits of sel'd cell
	if([dirList count] >= 1)					// open sel'td HotList file
		[[NXApp delegate] app:self openFile:
						[[dirList objectAt:selCell] gateDocPath] type:NULL];
	else						
		[[NXApp delegate] showAlert:"noSelectedDoc"];

    return self;
}
//*****************************************************************************
//
// 	target/action for a single click in the preferences browser. 
//
//*****************************************************************************

- pBrowserHit:sender
{   
  	selCell = [[sender matrixInColumn:0] selectedRow];
	[mat selectCellAt:selCell :0];
	[self setDispPerCellAt:selCell];			// display traits of sel'd cell
	[mat scrollCellToVisible:selCell :0];

    return self;
}
//*****************************************************************************
//
// 	target/action method for a double click in the preferences browser.  
//
//*****************************************************************************

- pBrowserDoubleClick:sender
{   
  	selCell = [[sender matrixInColumn:0] selectedRow];
	[mat selectCellAt:selCell :0];
	[self setDispPerCellAt:selCell];			// display traits of sel'd cell
	[mat scrollCellToVisible:selCell :0];
	if([dirList count] >= 1)					// open sel'td HotList file
		[[NXApp delegate] app:self openFile:
						[[dirList objectAt:selCell] gateDocPath] type:NULL];
	else						
		[[NXApp delegate] showAlert:"noSelectedDoc"];

    return self;
}
//*****************************************************************************
//
// 		go to next gate doc in hotList 
//
//*****************************************************************************

- nextItem:sender 
{
	[sender setState:0];
	if(selCell < ([dirList count] - 1))
		selCell++;
	else
		selCell = 0;
	[mat selectCellAt:selCell :0];
	[self setDispPerCellAt:selCell];			// display traits of sel'd cell
	[mat scrollCellToVisible:selCell :0];

	return self;
}
//*****************************************************************************
//
// 		go to previous gate doc in hotList 
//
//*****************************************************************************

- prevItem:sender 
{
	[sender setState:0];
	if(selCell > 0)
		selCell--;
	else
		selCell = [dirList count] - 1;
	[mat selectCellAt:selCell :0];
	[self setDispPerCellAt:selCell];			// display traits of sel'd cell
	[mat scrollCellToVisible:selCell :0];

	return self;
}
//*****************************************************************************
//
// 		set views per selected cell in hotlist 
//
//*****************************************************************************

- setDispPerCellAt:(int)selectedCell 
{
	if((strcmp([[[NXApp mainMenu] findCellWithTag:2] title], 
					[[NXApp delegate] localString:"Connect"]) == 0) && 
							[[[NXApp mainMenu] findCellWithTag:2] isEnabled])
		{													// item enabled
		[HLProviderField setStringValue:
					[[[HLBrowser matrixInColumn:0] selectedCell] stringValue]];
		if(!(image = [[dirList objectAt:selectedCell] gateIcon]))	// if imge
			image = [NXImage findImageNamed: "Blank"];		// else use blank
		[HLImageView setImage:image];
		if(toolBarView)
			[toolBarView setImage:image];
		}
	if(prefBMat)
		{
		[prefBMat selectCellAt:selCell :0];
		[prefBMat scrollCellToVisible:selCell :0];
		}

	return self;
}
//*****************************************************************************
//
// 		link based on selected file  
//
//*****************************************************************************

- playLink 
{
	if([dirList count] >= 1)					// open sel'td HotList file
		[[NXApp delegate]linkWithFile:[[dirList objectAt:selCell]gateDocPath]];
	else						
		[[NXApp delegate] showAlert:"noSelectedDoc"];

	return self;
}
//*****************************************************************************
//
// 		forward anything in Greek to someone who might understand 
//
//*****************************************************************************

- forward:(SEL)aSelector :(marg_list)argFrame
{
//    if ( [toolWin respondsTo:aSelector] )
//        return [toolWin performv:aSelector :argFrame];

    [self doesNotRecognize:aSelector];					// error abort process

	return self;
}
//************************************************************************
//
// 	app will terminate so save selected cell, browser size
//
//************************************************************************

- appWillTerminate
{
char tmpStr[16];
NXRect hlVRect;							

	sprintf(tmpStr, "%d", selCell);
								// write an entry to defaults database
	if(!NXWriteDefault([NXApp appName], SELCELL, tmpStr))
		[[NXApp delegate] showAlert:"ddbWriteError"];

	[HLBrowser getFrame: &hlVRect];
	sprintf(tmpStr,"%f", hlVRect.size.height);
								// write an entry to defaults database
	if(!NXWriteDefault([NXApp appName], BROWSERHT, tmpStr))
		[[NXApp delegate] showAlert:"ddbWriteError"];
	[addressView getFrame: &hlVRect];
	sprintf(tmpStr,"%f", hlVRect.size.height);
								// write an entry to defaults database
	if(!NXWriteDefault([NXApp appName], ADDRESSHT, tmpStr))
		[[NXApp delegate] showAlert:"ddbWriteError"];

	return self;
}
//************************************************************************
//
// 	free simply gets rid of everything we created
// 	This is how nice objects clean up.
//
//************************************************************************

- free
{
	if(dirList)
		{
		[dirList freeObjects];							// free list's objects
		[dirList free];									// free list object
		}		
	if(namHashTable)
		[namHashTable free];									

    return [super free];
}
//*****************************************************************************
//
// 		splitview delegate method, invoked after divider is moved by user 
//
//*****************************************************************************

- splitViewDidResizeSubviews:sender
{
NXRect graphRect;							// sizeof scroll's content view

	[HLBrowser getFrame: &graphRect];

	return self;
}
//*****************************************************************************
//
// 		tell the Browser to load col 0 
//
//*****************************************************************************

- loadBrowser 
{
	[HLBrowser loadColumnZero];		// NXBrowser s/load cols from its delegate
	if(hotListDirValid)				// if hotList path is valid
		{
		mat = [HLBrowser matrixInColumn:0];		
		[mat selectCellAt:selCell :0];
		[mat scrollCellToVisible:selCell :0];
		[HLBrowser display];
		[hotList makeKeyAndOrderFront:self];
		}													

	return self;
}
//*****************************************************************************
//
// 		send images back to this object 
//
//*****************************************************************************

- setToolBar:aView 
{
	toolBarView = aView;
	[toolBarView setImage:image];

	return self;
}
//*****************************************************************************
//
// 		send selected cell back to this object 
//
//*****************************************************************************

- setPreferencesBMat:aMatrix 
{
	prefBMat = aMatrix;

	return self;
}
//*****************************************************************************
//
// 		return the selectedCell 
//
//*****************************************************************************

- (int)hLSelectedCell 
{
	return selCell;
}
//*****************************************************************************
//
// 		return the statusWindow 
//
//*****************************************************************************

- statusWindow 
{
	return hotList;
}
//*****************************************************************************
//
// 		return the path to the selected gate docs options file 
//
//*****************************************************************************

- (const char *)selGateDocOptionsPath 
{
	if([dirList count] >= 1)							// path of selected doc
		{
		strncpy(oPath,[[dirList objectAt:selCell] gateDocPath], MAXPATHLEN);			
		strncat(oPath, OPTION, MAXPATHLEN - strlen(oPath));

		return oPath;
		}
	else						
		[[NXApp delegate] showAlert:"noSelectedDoc"];

	return NULL;
}
//******************* status Window delegate methods **************************
//*****************************************************************************
//
// 		called whenever the user minituriazes our status window.
//
//*****************************************************************************

- windowWillMiniaturize:sender toMiniwindow:miniwindow 
{
    return [sender setMiniwindowIcon:"miniWinIcon"];
}
//*****************************************************************************
//
// 		called whenever the user closes our status window.
//
//*****************************************************************************

- windowWillClose:sender  
{
	if(!NXWriteDefault([NXApp appName], DISPLAYS, "NO"))
		[[NXApp delegate] showAlert:"ddbWriteError"];

    return self;
}

@end
