
//======================================================================
//
//	Portions written by FreemanSoft Inc.
//
//	FreemanSoft disclaims any warranty of any kind, expressed or implied,
//	as to this source code's fitness for any particular use.
//
//	For more information, use the following electronic mail addresses:
//	 
//		info@FreemanSoft.com	general questions
//		support@FreemanSoft.com	technical questions
//
//======================================================================


/* Written by
 *	Joe Freeman	jfreeman@next.com	
 *	TwoPassUIControl
 *
 *	This code has no warranty.  
 *	It is provided so that the consumer may maintain and modify it
 *	at their own risk.  Use this code at your own risk.
 */

#import "TwoPassUIControl.h"

#import "DragView.h"
#import "Subprocess.h"
///#import "PreferencesPanel.h"
#import "pathutil.h"

#import "common.h"

#import "twoPassUI.h"		// strings entries


/*================================================================
 *	Private methods 
 *================================================================*/
 
@implementation TwoPassUIControl(Private)

/* updates currentState and title */
- setState:(int)newState
{
    switch (newState){
    	case NOTHING_RUNNING:
		[theWindow setTitle:title_string];
		currentState = newState;
		break;
	case PASS_1_RUNNING:
		[theWindow setTitle:title_pass_1];
		currentState = newState;
		break;
	case PASS_2_RUNNING:
		[theWindow setTitle:title_pass_2];
		currentState = newState;
		break;
	default: /* invalid state so pick other */
		[theWindow setTitle:title_string];
		[self setState: NOTHING_RUNNING];
		break;
    }

    return self;
}

@end

@implementation TwoPassUIControl

/*================================================================
 *	all strings related to rdist are right before runPassTwo: 
 *================================================================*/

	
/*================================================================
 *	initializers 
 *================================================================*/
- init
{
    static windowPosX = 0;
    static windowPosY = 0;
    NXRect windowRect;
    
    [super init];
    
    [self setState: NOTHING_RUNNING];
    canContinue = YES;			/* redundant */
    
    [NXApp loadNibSection: "TwoPassUIControl.nib" owner:self];
    [theWindow getFrame:&windowRect];
    windowRect.origin.x+=windowPosX;
    windowRect.origin.y-=windowPosY;
    if (windowPosX < 120){
	windowPosX+= 20.0;
	windowPosY+= 20.0;
    } else {
	windowPosX =  0.0;
	windowPosY =  0.0;
    }
    [theWindow moveTo:windowRect.origin.x :windowRect.origin.y];
    [theWindow setTitle:title_string];
    [theWindow makeKeyAndOrderFront:self];
    return self;
}
 
- initSourcePath:(char *)srcPath destinationPath:(char *)destPath
{
    [self init];
    if (srcPath && *srcPath){
    	if (srcPath[0] == '~'  ){
		strcpy(sPathList, NXHomeDirectory());
		strcat(sPathList, &srcPath[1]);
	}else {
    		strcpy(sPathList, srcPath);
	}
    }
    
    if (destPath && *destPath){
    	if (destPath[0] == '~' ){
		strcpy(dPathList, NXHomeDirectory());
		strcat(dPathList, &destPath[1]);
	} else {
    		strcpy(dPathList, destPath);
	}
    }
    
    [self updateTextFields:self];
    [self updateIconViews:self];
    return self;
}


/*================================================================
 *	outlet connection
 *================================================================*/
 
- window
{
    return theWindow;
}

- (int)state
{
    return currentState;
}

- (const char *)buttonImageName
{
    return "JumpBack_notext.tiff";
}

- (const char *)buttonAltImageName
{
    return "JumpBack_abort.tiff";
}

- (const char *)stringsTable
{
    return "twoPassUI";
}


- setStartButton:anObject
{
    startButton = anObject;
    [NXImage findImageNamed: 	[self buttonImageName]];
    [startButton setIcon: 	[self buttonImageName]];
    [NXImage findImageNamed: 	[self buttonAltImageName]];
    [startButton setAltIcon: 	[self buttonAltImageName]];
    return self;
}

/* ===========================
 * Utility methods
 * ===========================*/

	/*
	 * default behavior says to just use the whole path typed in 
	 */
- updateFromTextFields:sender
{
    strcpy(dPathList, [destinationText stringValue]);
    strcpy(sPathList, [sourceText stringValue]);
    return self;
}
    

/* simple standard case where all paths are absolute
 */
- updateTextFields:sender
{
    [sourceText 	setStringValue:sPathList];
    [destinationText 	setStringValue:dPathList];
    return self;
}

- updateIconViews:sender
{
    [sourceDragView		useIconForFile:sPathList];
    [destinationDragView	useIconForFile:dPathList];
    return self;
}

/* show a string in the log window */
- logIt:(const char *)s
{
    int	numChars = [logText textLength];
    [[[logText setSel:numChars :numChars] replaceSel:s] scrollSelToVisible];
    NXPing();
    return self;
}

 
/* ===========================
 * Target/Action stuff
 * ===========================*/

#define	rhost_string	\
 	"/bin/echo localhost `whoami` | /bin/cat >> ~/.rhosts; /usr/bin/sort ~/.rhosts | /usr/bin/uniq > /tmp/$$ ; /bin/mv /tmp/$$ ~/.rhosts"

- startProcess:sender
{
    canContinue=YES;
    if ([sender state] == 1){
	[logText selectText:self];
	[logText replaceSel:startup_string];
	
	if ( !sPathList || !*sPathList){
		[self logIt:missing_source];
		[sender setState:0];
		return nil;
	}
	if ( !dPathList || !*dPathList) {
		[self logIt:missing_dest];
		[sender setState:0];
		return nil;
	}
		
	/* really should scan the rhosts files to make sure this will work */
	system(rhost_string);
	
	/* run find (which will spawn rdist), or just run rdist */
	if (![self runPassOne:self])
		[self runPassTwo:self];
	
    } else [self abortProcess:self];
    return self;
}

/* default is no pass one */
- runPassOne:sender
{
    return nil;
}

- runPassTwo:sender
{
    return self;
}


- abortProcess:sender
{
    [self setState: NOTHING_RUNNING];
    canContinue = NO;
    [subprocessObj terminate:sender ];
    [self logIt: abort_string];
    [startButton setState:0];
    return self;
}


/*=======================================
 *
 * drag support 
 *
 *=======================================*/

- iconEntered:where
{
    [theWindow setTitle:almost_got_it];
    return self;
}

- iconLeft:where
{
    [theWindow setTitle:title_string];
    return self;
}

- iconDropped:where
{
    if (sPathList)
    	[theWindow setTitle:basename(sPathList)];
    else
	[theWindow setTitle:title_string];
    return self;
}

- iconBogus:where
{
    [theWindow setTitle:bogus_file_type];
    NXBeep();
    return self;
}

- (BOOL) isFilePBValid:(Pasteboard *)pboard forView:sender
{
    int length;
    const char * tPathList;

    [pboard readType:NXFilenamePboardType data:&tPathList length:&length];
    if (!isDirectory((char *)tPathList))
    	return NO;
    else
    	return YES;
}
    

- (BOOL) acceptedFilePB:(Pasteboard *)pboard forView:sender
{
    int length;
    const char * tPathList;
    
    
    [pboard readType:NXFilenamePboardType data:&tPathList length:&length];
    if (!isDirectory((char *) tPathList))
    {
	NXRunAlertPanel([NXApp appName],
		bogus_file_type,
		"OK",NULL,NULL);
    	return NO;
    }
    else
    {
	if (sender == destinationDragView)
	{
  	  	strcpy(dPathList, tPathList);
	}
	else
	{
  	  	strcpy(sPathList, tPathList);
	}
	[self updateTextFields:self];
    }
    return YES;
}    

- userClicked:(int)numTimes at:(NXPoint *)clickPoint inDragView:sender;
{
    const char *ourPath;
	if (sender == destinationDragView)
	{
	 	ourPath = dPathList;
	}
	else if (sender == sourceDragView)
	{
	 	ourPath = sPathList;
	} else
	{
		return nil;
	}
	
	if (numTimes == 1)
		[[Application workspace] selectFile:ourPath
				inFileViewerRootedAt:""];
	else if (numTimes == 2)
		[[Application workspace] openFile:ourPath
				fromImage: [sender currentImage]
				at:clickPoint
				inView:sender];
	return self;
}
/* ===========================
 * subprocess delegation
 * ===========================*/
 
 
- subprocessOutput:(char *)buffer
{
	char	*copyBuf;	

	copyBuf = buffer;
	if (currentState == PASS_1_RUNNING){
		/*
		 *	The find only returns offensive directories 
		 * 	if we get anything back from the find,
		 * 	it means we have found something bad
		 */
		if (debug_level >= debug_except_pat)
		    		fprintf(stderr,"find returned: %s\n", copyBuf);
		if (canContinue) {
			/* 
			 * this is the first one to be found bad
			 */
			[self logIt: pass_1_found_something];
		}
		/* log the offensive directory names */
		[self logIt: copyBuf];
		/* do this so rdist doesn't run later */
		canContinue = NO;
		/* we don't abort the find cause we want to see them all */
	} else if (currentState == PASS_2_RUNNING) {
		[self logIt: buffer];
	} else {
		/* I'm confused unknown state */
	}
 	return self;
}

- subprocessDone
{
	if (currentState == PASS_1_RUNNING){
		/* if find was running and found no problems */
		if (canContinue) {
			[self runPassTwo:self];
		} else {
			[self abortProcess:self];
		}
	} else if (currentState == PASS_2_RUNNING){
		[self setState: NOTHING_RUNNING];
		[self logIt:finished_string];
		[startButton setState:0];
	} else {
		/* I'm confused, unknown state */
	}
    return self;
}


/* ===========================
 * window delegation
 * ===========================*/

- windowWillClose:sender
{
    id retID;
    
    if ([startButton state] == 1)
    {
        if (	NXRunAlertPanel([NXApp appName],
		process_running,
		dont_close, close_anyway,NULL) == NX_ALERTDEFAULT )
	{
		retID= nil;
	}
	else
	{
		[self abortProcess:self];
		retID= self;
	}

    }
    else
    {
    	retID= self;
    }
    if (retID == self) {
    	[self free];
	[sender setDelegate:nil];
    }
    return retID;
}

/* ===========================
 * text delegation
 * ===========================*/

- textDidEnd:textObject endChar:(unsigned short)whyEnd
{
    [ self updateFromTextFields:self];
    [ self updateIconViews:self];
    return self;
}

@end
