// IconView.m

/*
 * Copyright 1991 RightBrain Software.  All rights reserved.
 *
 * No part of this code may be reproduced in any form, compiled
 * or source code, nor used for any purpose without the express
 * written permission of RightBrain Software.
 * 
 * Entered into the public domain 12/15/93 by RightBrain Software.
 *
 */

#import <strings.h>
#import <dpsclient/psops.h>
#import <dpsclient/wraps.h>
#import <appkit/NXImage.h>
#import <objc/NXStringTable.h>
#import <appkit/appkit.h>

#import "CopyIcon.h"
#import "Controller.h"
#import "IconView.h"
// #import "Defaults.h"

@implementation IconView

static NXRect	fileRect = {{2.0, 2.0}, {54.0, 54.0}};
    

/* instance methods */

/****************************** initFrame */
- initFrame:(NXRect *)frameRect
{
    NXSize	imageSize = {54.0, 54.0};
//    NXSize	imageSize = {96.0, 96.0};
    
    [super initFrame:frameRect];

    iconImage = [[NXImage alloc] initSize:&imageSize];
    stringTable = [[NXApp delegate] stringTable];
    hasIcon = NO;
    autoLaunch = NO;
    [self clear];
    
    return self;
}

/****************************** bounds */
- (NXRect *)bounds;
{
    return &bounds;
}


/****************************** setAppOrFile */
- setAppOrFile:(int)ilk;
{
    isApplication = (ilk == NX_ISAPPLICATION);
    isBogus = (ilk == MISSING_FILE);
    return self;
}


/****************************** acceptsFirstMouse */
- (BOOL)acceptsFirstMouse
{
    return YES;
}


/****************************** acceptsFirstMouse */
- (BOOL)hasIcon
{
    return hasIcon;
}


/****************************** filename */
- (char *)filename;
{
    return filename;
}


/****************************** appname */
- (char *)appname;
{
    return appname;
}


/****************************** dirname */
- (char *)dirname;
{
    return dirname;
}


/****************************** tellName */
- tellName:sender;
{
    fprintf ( stderr, "List: %s\n", filename );
    [self display];
    return self;
}


/****************************** setFilename */
- setFilename:(const char *)name multipleSelected:(BOOL)multipleSelected
{
    char *lastSlash, *stringPosition, *tmpPosition;
    
  /*
   * we need to remember this so that the we don't let the user drag the
   * multple-files-selected-icon from the icon well
   */
    multipleFiles = multipleSelected;
    
  /* save the file name if necessary */
    if (!multipleSelected) {
	strcpy ( filename, name );
	strcpy ( appname, (rindex(name, '/') + 1) );
	strcpy ( dirname, name );
	lastSlash = rindex(dirname, '/');
	if (lastSlash) *lastSlash = '\0';
    } else {
	strcpy ( filename, name );
	appname[0] = '\0';
	strcpy ( buff, name );
	tmpPosition = buff; // gcr
	for ( stringPosition=buff; stringPosition!=NULL; stringPosition++ ) {
	    if ( *stringPosition == '\t' ) {
		*stringPosition = '\0';
		if ( appname[0] != '\0' ) strcat ( appname, ", " );
		strcat ( appname, (rindex(tmpPosition, '/')+1) );
		tmpPosition = stringPosition + 1;
	    } else if ( *stringPosition == '\0' ) {
		if ( appname[0] != '\0' ) strcat ( appname, ", " );
		strcat ( appname, (rindex(tmpPosition, '/')+1) );
		break;
	    }
	}
	strcpy ( dirname, name );
	stringPosition = index ( dirname, '\t' );
	if ( stringPosition ) *stringPosition = '\0';
	lastSlash = rindex(dirname, '/');
	if (lastSlash) *lastSlash = '\0';
    }
    if ( dirname == NULL || strlen(dirname) < 2 ) {
	strcpy ( dirname, "root directory" );
    }
    
    return self;
}


/****************************** setMyCheckBox */
- setMyCheckBox:theBox;
{
    myCheckBox = theBox;
    return self;
}


/****************************** myCheckBox */
- myCheckBox;
{
    return myCheckBox;
}


/****************************** setMyWideBox */
- setMyWideBox:theBox;
{
    myWideBox = theBox;
    return self;
}


/****************************** myWideBox */
- myWideBox;
{
    return myWideBox;
}


/****************************** setMyLabelText */
- setMyLabelText:theText;
{
    myLabelText = theText;
    return self;
}


/****************************** myLabelText */
- myLabelText;
{
    return myLabelText;
}


/****************************** setMyDirText */
- setMyDirText:theText;
{
    myDirText = theText;
    return self;
}


/****************************** myDirText */
- myDirText;
{
    return myDirText;
}


/****************************** toggleCheckBox */
- toggleCheckBox:sender;
{
    if ( autoLaunch ) {
	autoLaunch = FALSE;
    } else {
	autoLaunch = TRUE;
    }
    if ( sender != [window delegate] ) {
	[[window delegate] writeFileList:
	    [[window delegate] listFileName]
	];
    }
    return self;
}


/****************************** autoLaunch */
- (int)autoLaunch;
{
    return autoLaunch;
}


/****************************** takeIconFromWindow */
- takeIconFromWindow:(int)windowNumber :(float)x :(float)y :(float)width
  :(float)height
{
  /* copy the icon into our nximage */
    if ( windowNumber == 0 ) return NULL;
    [iconImage lockFocus];
    copyIconPicture(windowNumber, x, y, width, height);		// was + 2.0
    [iconImage unlockFocus];
    
  /* now display the new image */
    showFile = YES;
    hasIcon = YES;
    [self display];
    
    return self;
}



/****************************** takeIconFromData */
- takeIconFromData : (char *)data : (int)length;
{
    float width, height, bits;
    
  /* copy the icon into our nximage */
    if ( length == 0 || !data ) return NULL;
    width = height = 48.0;
    bits = length / (width * height / 8);
    [iconImage lockFocus];
    imageIconPicture ( (int)width, (int)height, (int)bits, data );
    [iconImage unlockFocus];
    
  /* now display the new image */
    showFile = YES;
    hasIcon = YES;
    [self display];
    
    return self;
}



/****************************** takeIconFromTIFF */
- takeIconFromTIFF : (char *)fname;
{
    id tmp;
    tmp = iconImage;
    iconImage = [[NXImage alloc] initFromFile:fname];
    if ( iconImage ) {
	if ( tmp ) [tmp free];
    }
    showFile = YES;
    hasIcon = YES;
    [self display];
    
    return self;
}



/****************************** clear */
- clear
{
  /* remove any image from the nximage */
    [self display];
    return self;
    
    [iconImage lockFocus];
    PSsetgray(NX_LTGRAY);
    NXRectFill(&bounds);
    [iconImage unlockFocus];
    
  /* now display the blank nximage */
    [self lockFocus];
	NXDrawGrayBezel(&bounds, NULL);
	PSsetgray(NX_LTGRAY);
	NXRectFill(&bounds);
    [self unlockFocus];

    hasIcon = NO;

    return self;
}


/****************************** openSelf */
- openSelf:sender;
{
    id speaker;
    int flag, response, files;
    char *extension, *program, *newPath, *stringPosition;
    char *tmpFile;
    char launch[24];

    speaker = [NXApp appSpeaker];
    [speaker setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];

    // the number of tabs + 1 equals the number of files dragged in
    stringPosition = filename;
    files = 1; // gcr
    while (stringPosition = index(stringPosition, '\t')) {
      files++;
      stringPosition++;
    }
    strcpy ( buff, filename );
    while ( files ) {
        if ( files >= 1 ) {
	    stringPosition = rindex ( buff, '\t' );
	    if ( stringPosition ) {
		tmpFile = stringPosition + 1;
		*stringPosition = '\0';
	    } else {
		tmpFile = buff;
	    }
	} else {
	    tmpFile = buff;
	}
	files--;
	// check our instance variable (set from Controller's getFileInfo)
	if ( isApplication ) {
	    extension = rindex ( tmpFile, '.' );
	    if ( extension && !strcmp(extension,".app") ) {
		program = rindex ( tmpFile, '/' );
		newPath = (char *)malloc(strlen(tmpFile) + strlen(program));
		sprintf ( newPath, "%s%s", tmpFile, program );
		newPath [ strlen(newPath) - 4 ] = '\0';
		[NXApp deactivateSelf];
		[speaker launchProgram:newPath ok: &flag];
		free ( newPath );
	    } else {
		[NXApp deactivateSelf];
		[speaker launchProgram:tmpFile ok: &flag];
	    }
	    strcpy ( launch, "launch" );
	} else {
	    [NXApp deactivateSelf];
	    [speaker openFile:tmpFile ok: &flag];
	    strcpy ( launch, "open" );
	}
	if ( !flag ) {
	    response = NXRunAlertPanel ( "Launch",
		"Could not %s %s", "Remove It", "OK", NULL, launch, tmpFile
	    );
	    response = NXRunAlertPanel (
		[stringTable valueForStringKey:"launch"],
		[stringTable valueForStringKey:"launchCANT"],
		[stringTable valueForStringKey:"launchRemove"],
		[stringTable valueForStringKey:"OK"],
		NULL,
		[stringTable valueForStringKey:launch],
		filename
	    );
	    if ( response == NX_ALERTDEFAULT ) {
		[[NXApp delegate] removeFileFromScroller:filename];
		return self;
	    }
	} else {
	    [NXApp deactivateSelf];
	}
    }
    return self;
}


/****************************** openSelfIfAutoLaunch */
- openSelfIfAutoLaunch:sender;
{
//    id speaker;
//    char *appName, *extension, *newPath;

    if ( !autoLaunch ) return self;

    [self openSelf:sender];

    // if we're autolaunching, then "hide" the app if possible
    return self;
}


/****************************** highlightSelf */
- highlightSelf:sender;
{
    [self lockFocus];
    NXHighlightRect ( &bounds );
    [self unlockFocus];
    return self;
}


/****************************** mouseDown */
- mouseDown:(NXEvent *)theEvent
{
    NXPoint mouseLoc;
    NXPoint origLoc, newLoc;
    id prevSelected;
    int Yoff;
    int oldMask;
    int tryDrag;
    NXEvent peekEvent, *nextEvent;

    if ( !filename || !(strlen(filename)) ) { NXBeep(); return self; }

    mouseLoc = theEvent->location;
    origLoc = mouseLoc;
    [self convertPoint: &mouseLoc fromView:[scrollR docView]];
    Yoff = (int)mouseLoc.y % 54;
    mouseLoc.y -= Yoff;
    mouseLoc.x = 24.0;
    mouseLoc.y += 24.0;
    [self convertPoint: &mouseLoc toView:[scrollR docView]];
    theEvent->location = mouseLoc;
    
    oldMask = [
	window addToEventMask: NX_MOUSEDRAGGEDMASK
    ];
    if ( theEvent->data.mouse.click == 1  ) {
	prevSelected = [[NXApp delegate] selected];
	if ( prevSelected && (prevSelected != self) ) {
	    [prevSelected lockFocus];
	    [prevSelected highlightSelf:self];
	    [prevSelected unlockFocus];
	    [[NXApp delegate] setSelected:self];
	    [self lockFocus];
	    NXHighlightRect ( &bounds );
	    [self unlockFocus];
	    PSflushgraphics();  NXPing();
	} else if ( !prevSelected ) {
	    [[NXApp delegate] setSelected:self];
	    [self lockFocus];
	    NXHighlightRect ( &bounds );
	    [self unlockFocus];
	    PSflushgraphics();  NXPing();
	}
    } else
    if ( theEvent->data.mouse.click >= 2 ) {
	[self openSelf:self];
	if ( theEvent->flags & NX_ALTERNATEMASK ) {
	    [NXApp deactivateSelf];
	    [NXApp hide:self];
	}
	if ( theEvent->data.mouse.click >= 3 ) {
	    [NXApp deactivateSelf];
	    [NXApp hide:self];
	}
	return self;
    } else {
	// do nothing for now
    }

    nextEvent = [ NXApp
	peekNextEvent: NX_ALLEVENTS
	into: &peekEvent
	waitFor: 0.5
	threshold: NX_MODALRESPTHRESHOLD
    ];
    if ( nextEvent != NULL ) {
	tryDrag = NO;
	if ( nextEvent->type == NX_LMOUSEDRAGGED ) {
	    [[NXApp delegate] setFrom:self];
	    [[window contentView] lockFocus];
	    PSsetinstance ( TRUE );
	    while ( nextEvent->type != NX_LMOUSEUP ) {
		switch ( nextEvent->type ) {
		    case NX_MOUSEDRAGGED: {
			PSnewinstance();
			newLoc = nextEvent->location;
			[self convertPoint: &newLoc fromView: self];
			newLoc.x =  24.0;
			newLoc.y = newLoc.y - 24.0;
			[iconImage composite:NX_COPY toPoint:&newLoc];
			PSflushgraphics();
			NXPing();
		    } break;
		    default: {
		    } break;
		}
		nextEvent = [ NXApp getNextEvent: NX_ALLEVENTS ];
	    }
	    PSnewinstance();
	    PSsetinstance ( FALSE );
	    [[window contentView] unlockFocus];

	    // compensate for the bottom of the window:
	    newLoc.y += 10.0;

	    // [self convertPoint: &newLoc toView: self];

	    // slide the icon to the new location
	    [[NXApp delegate] slideIconInScroller: self toLocation:newLoc.y];
	/***
	    [self dragFile:filename
		fromRect:&fileRect
		slideBack:NO
		event:theEvent
	    ];
	 ***/
	} else if ( nextEvent->type == NX_LMOUSEUP ) {
	    // throw away mouseUp event
	    // nextEvent = [ NXApp getNextEvent: NX_LMOUSEUPMASK ];
	    nextEvent = [ NXApp getNextEvent: NX_ALLEVENTS ];
	    if ( nextEvent->type != NX_LMOUSEUP ) {
		NXRunAlertPanel ( "Yikes",
		    "NextEvent was %d instead of MOUSEUPMASK",
		    NULL, NULL, NULL, nextEvent->type
		);
	    }
	    nextEvent = [ NXApp
		peekNextEvent: NX_ALLEVENTS
		into: &peekEvent
		waitFor: 0.25
		threshold: NX_MODALRESPTHRESHOLD
	    ];
	    if ( nextEvent != NULL && nextEvent->type == NX_LMOUSEDOWN ) {
		nextEvent = [ NXApp getNextEvent: NX_LMOUSEDOWNMASK ];
		[self mouseDown:nextEvent];
		return self;
	    } else {
		if ( [[NXApp delegate] selected] ) {
		    [[[NXApp delegate] selected] highlightSelf:self];
		}
		[[NXApp delegate] setSelected:self];
		[self lockFocus];
		NXHighlightRect ( &bounds );
		[self unlockFocus];
		PSflushgraphics();  NXPing();
	    }
	} else {
	    fprintf ( stderr, "unknown type: %d\n", nextEvent->type );
	}
    } else {
	[[NXApp delegate] setFrom:self];
	[self dragFile:filename
		fromRect:&fileRect
		slideBack:NO
		event:theEvent
	];
    }
    return self;
}


/****************************** drawSelf */
- drawSelf:(NXRect *)rects :(int)rectCount
{
    
    if ( !filename || !(strlen(filename)) ) return self;
    NXDrawGrayBezel(&bounds, NULL);
    PSgsave();
	PStranslate ( deltaX, deltaY );
	[iconImage composite:NX_SOVER toPoint:&fileRect.origin];
    PSgrestore();
    
    if ( [[NXApp delegate] selected] == self ) {
	NXHighlightRect ( &bounds );
    }
    return self;
}


@end