// Editor.m
//
// created by Martin Wennerberg on Sun 12-Nov-1995
//
// when		who	modification

#import "Editor.h"
#import "MorphLine.h"
#import "MorphDocument.h"
#import "algebra.h"
#import "NSBitmapImageRep_editing.h"
#import "InspectorController.h"

static void drawLine (NSPoint startPt, NSPoint endPt)
{
    PSmoveto(startPt.x, startPt.y);
    PSarc(startPt.x, startPt.y, 2.0, 0, 360.0);
    PSmoveto(startPt.x, startPt.y);
    PSlineto(endPt.x, endPt.y);
}

static void drawKnob (NSPoint p)
{
    PSmoveto(p.x - 2, p.y - 2);
    PSlineto(p.x - 2, p.y + 2);
    PSlineto(p.x + 2, p.y + 2);
    PSlineto(p.x + 2, p.y - 2);
    PSlineto(p.x - 2, p.y - 2);
}

@implementation Editor
- (id)initWithFrame:(NSRect)rect;
{
    self = [super initWithFrame:rect];
    [self registerForDraggedTypes:[NSImage imagePasteboardTypes]];
    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
    [self setToolTip:NSLocalizedString (@"Editor. Drop an image here", @"Editor before image")];
    [self setNeedsDisplay:YES];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(selectionChanged:) name:NOTIFICATION_SELECTION_CHANGED object:delegate];
    return self;
}

- (BOOL) isFlipped
{
    return NO;
}

- (BOOL) acceptsFirstResponder
{
    return YES;
}

- (void) dealloc
{
    [image release];
    [super dealloc];
}

- (NSImage *) image
{
    if (image == nil)
        [self setImage:[delegate imageAtDelta:delta]];
    return image;
}

- (void) setImage:(NSImage *)im
{
    [image release];
    image = [im retain];
    [image setDataRetained:YES];
    [image setScalesWhenResized:YES];
    [image setSize:[self bounds].size];
    [self setNeedsDisplay:YES];
    if (image != nil)
        [self setToolTip:NSLocalizedString (@"Editor. Drag mouse to draw lines to indicate similar sections.", @"Editor after image")];
    [delegate setImage:image atDelta:delta];
}

- (void) setDelta:(float)d
{
    delta = d;
    [self setNeedsDisplay:YES];
}

- (float) delta
{
    return delta;
}

- (void) setEditingIsEnabled:(BOOL)yn
{
    editingIsEnabled = yn;
}

- (BOOL) editingIsEnabled
{
    return editingIsEnabled;
}

- (void)resizeWithOldSuperviewSize:(NSSize)oldSize
{
    [super resizeWithOldSuperviewSize:oldSize];
    [[self image] setSize:[self bounds].size];
    [self setNeedsDisplay:YES];
}

- (void)keyDown:(NSEvent *)event
{
    NSEnumerator *lineEnum = [[delegate morphLines] objectEnumerator];
    MorphLine	 *line;
    NSArray      *selectedLines = [delegate currentSelection];
    int		      c;

    c = [event keyCode];
    while ((line = [lineEnum nextObject]))
        if ([selectedLines containsObject:line])
            switch (c)
            {
                case 14:	// Backspace
                case 83:	// Delete
                case NSDeleteFunctionKey:
                case NSClearLineFunctionKey:
                case NSDeleteLineFunctionKey:
                case NSDeleteCharFunctionKey:
                    [delegate deleteMorphLine:line];
                    break;
                case NSUpArrowFunctionKey:
                case NSDownArrowFunctionKey:
                case NSLeftArrowFunctionKey:
                case NSRightArrowFunctionKey:
                    // Implement moving here
                default:
                    NSLog (@"Unknown keydown: %d", c);
                    break;
            }
}

#define MOVE		0
#define RESIZE_STARTPT	1
#define RESIZE_ENDPT	2
#define	CREATE		3
#define DRAGGING_MASK (NSLeftMouseUpMask|NSLeftMouseDraggedMask)

- (void)mouseDown:(NSEvent *)event
{
    short		 action;
    NSEnumerator	*lineEnum;
    MorphLine		*morphLine = nil;
    MorphLine		*tmpLine;
    NSPoint		 startPt, endPt;
    NSPoint		 mousePt;
    float		 maxDist;
    NSRect		 oldRect;
    float		 xscale, yscale;
    NSPoint    		 offset;
    NSPoint		 oldMousePt;
    BOOL		 shouldDeselect = (([event modifierFlags] & NSShiftKeyMask) == 0);

    xscale = NSWidth([self bounds]);
    yscale = NSHeight([self bounds]);
    maxDist = 9.0;
    mousePt = [self convertPoint:[event locationInWindow] fromView:nil];
    oldMousePt = mousePt;
    
    lineEnum = [[delegate morphLines] objectEnumerator];

    while ((tmpLine = [lineEnum nextObject]))
    {
        startPt = pt_scale([tmpLine startPointAtDelta:delta], xscale, yscale);
        endPt = pt_scale([tmpLine endPointAtDelta:delta], xscale, yscale);
        
        if (line_dist2_to_point(startPt, endPt, mousePt) <= maxDist)
        {
            morphLine = tmpLine;
            [delegate addToCurrentSelection:morphLine];
        }
        else if (shouldDeselect)
            [delegate removeFromCurrentSelection:tmpLine];
    }

    if (morphLine)
    {
        startPt = pt_scale([morphLine startPointAtDelta:delta], xscale, yscale);
        endPt = pt_scale([morphLine endPointAtDelta:delta], xscale, yscale);

        if (pt_dist2(mousePt, startPt) <= maxDist)
            action = RESIZE_STARTPT;
        else if (pt_dist2(mousePt, endPt) <= maxDist)
            action = RESIZE_ENDPT;
        else
            action = MOVE;
    }
    else
    {
        startPt = mousePt;
        action = CREATE;
    }
    
    [self lockFocus];

    oldRect = NSInsetRect(rectContainingPoints(startPt,endPt), -4.0, -4.0);

    while ([event type] != NSLeftMouseUp)
    {
        event = [[self window] nextEventMatchingMask:DRAGGING_MASK];
        mousePt = [self convertPoint:[event locationInWindow] fromView:nil];

        switch (action)
        {
        case MOVE:
            offset = pt_sub(mousePt, oldMousePt);
            startPt = pt_sum(offset, pt_scale([morphLine startPointAtDelta:delta], xscale, yscale));
            [morphLine setStartPoint:pt_scale(startPt,1.0/xscale,1.0/yscale) atDelta:delta];
            endPt = pt_sum(offset, pt_scale([morphLine endPointAtDelta:delta], xscale, yscale));
            [morphLine setEndPoint:pt_scale(endPt,1.0/xscale,1.0/yscale) atDelta:delta];
            oldMousePt = mousePt;
            break;
        case RESIZE_ENDPT:
            endPt = mousePt;
            [morphLine setEndPoint:pt_scale(endPt,1.0/xscale,1.0/yscale) atDelta:delta];
            break;
        case RESIZE_STARTPT:
            startPt = mousePt;
            [morphLine setStartPoint:pt_scale(startPt,1.0/xscale,1.0/yscale) atDelta:delta];
            break;
        case CREATE:
            endPt = mousePt;
            break;
        }
        [self drawRect:oldRect];
        drawLine (startPt, endPt);
        [[NSColor greenColor] set];
        PSsetlinewidth(2.0);
        PSstroke();
        [[self window] flushWindow];
        oldRect = NSInsetRect(rectContainingPoints(startPt,endPt), -4.0, -4.0);
    }
    if (action == CREATE)
    {
        if (pt_dist(startPt, endPt) > 5.0)
        {
            morphLine = [[[MorphLine allocWithZone:[self zone]] init] autorelease];
            [morphLine setStartPoint:pt_scale(startPt, 1.0/xscale, 1.0/yscale) atDelta:delta];
            [morphLine setStartPoint:pt_scale(startPt, 1.0/xscale, 1.0/yscale) atDelta:1.0 - delta];
            [morphLine setEndPoint:pt_scale(endPt, 1.0/xscale, 1.0/yscale) atDelta:delta];
            [morphLine setEndPoint:pt_scale(endPt, 1.0/xscale, 1.0/yscale) atDelta:1.0 - delta];
            [delegate addMorphLine:morphLine];
            [delegate addToCurrentSelection:morphLine];
        }
    }
    [self unlockFocus];
    [[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self]
                                postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];

    [self setNeedsDisplay:YES];
}

- (void) selectionChanged:(NSNotification *)notification
{
    [self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)rect
{
    NSArray      *selectedLines = [delegate currentSelection];
    NSEnumerator *lineEnum;
    MorphLine	 *morphLine;
    NSPoint		  startPt;
    NSPoint		  endPt;
    NSRect		  lineBounds;
    BOOL		  containsLine = NO;
    NSPoint		  p;

    p.x = NSMinX(rect);
    p.y = NSMaxY(rect);

    [[self image] compositeToPoint:rect.origin fromRect:rect operation:NSCompositeCopy];

    lineEnum = [[delegate morphLines] objectEnumerator];

    while ((morphLine = [lineEnum nextObject]))
    {
        startPt = [morphLine startPointAtDelta:delta];
        endPt = [morphLine endPointAtDelta:delta];

        startPt = pt_scale (startPt, NSWidth([self bounds]), NSHeight([self bounds]));
        endPt = pt_scale (endPt, NSWidth([self bounds]), NSHeight([self bounds]));
        
        // Find out if the line intersects the drawing rect
        // and if it does not then skip it.
        lineBounds = NSInsetRect(rectContainingPoints(startPt,endPt), -3.0, -3.0);
        if (NSIntersectsRect(rect, lineBounds))
        {
            drawLine (startPt, endPt);
            if ([selectedLines containsObject:morphLine])
            {
                drawKnob (startPt);
                drawKnob (endPt);
            }
            containsLine = YES;
        }
    }
    if (containsLine)
    {
        [[NSColor greenColor] set];
        PSsetlinewidth(3.0);
        PSstroke();
    }
}
@end

@implementation Editor(Drag)
- (unsigned int)draggingEntered:(id <NSDraggingInfo>)sender
{
//    NSPasteboard *pboard = [sender draggingPasteboard];
//  if ([NSImage canInitWithPasteboard:pboard])
    return NSDragOperationCopy;
//    else
    return NSDragOperationNone;
}

- (unsigned int)draggingUpdated:(id <NSDraggingInfo>)sender
{
    return [self draggingEntered:sender];
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
    NSImage	*im;
    NSString	*filename;
    
//    im = [[[NSImage allocWithZone:[self zone]] initWithPasteboard:[sender draggingPasteboard]] autorelease];

    filename = [[[sender draggingPasteboard] propertyListForType:NSFilenamesPboardType] lastObject];
    im = [[NSImage allocWithZone:[self zone]] initWithContentsOfFile:filename];
    [im setScalesWhenResized:YES];
    if (im)
    {
        [self setImage:[im autorelease]];
        return YES;
    }
    else
        return NO;
}
@end
