//
//  EditTabController.m
//  Flash2
//
//  Copyright 2008 Nicholas Matsakis. 
//  The code in thie file is released to the public under the
//  terms of the MIT License as described here:
//  http://www.opensource.org/licenses/mit-license.php
//

#import "EditTabController.h"
#import "Models.h"
#import "OxRegex.h"
#import "OxNSArrayController.h"
#import "OxNSArray.h"
#import "OxNSSet.h"
#import "OxNSMapTable.h"
#import "WordTextFieldDelegate.h"

@implementation ConnectionInfo

@synthesize relationship = a_relationship;
@synthesize toWord = a_toWord;

@end

@implementation EditTabController

- init {
    [super init];
    m_canAddNewConnection = [OxMemoize new];
/*    m_existingConnections = [OxMemoize new];
    m_existingWord = [OxMemoize new];*/
    return self;
}

- (void) awakeFromNib
{
    [m_wordBeingEditedField bind:@"word" toObject:self withKeyPath:@"wordBeingEdited" options:nil];
    [m_wordBeingEditedField bind:@"language" toObject:self withKeyPath:@"language" options:nil];
    [m_wordBeingEditedField setDoNotMigrate:YES];
    
    // K_RELATIONSHIP_CATEGORY, K_CATEGORY_LANGUAGE
    [m_connWordSelector bind:@"word" toObject:self withKeyPath:@"connWord" options:nil];
    [m_connWordSelector bind:@"language" toObject:self withKeyPath:@"connRel.fromCategory.language" options:nil];

    // K_RELATIONSHIP_CATEGORY, K_CATEGORY_LANGUAGE
    [m_newWordSelector bind:@"word" toObject:self withKeyPath:@"newConnWord" options:nil];
    [m_newWordSelector bind:@"language" toObject:self withKeyPath:@"newConnRel.fromCategory.language" options:nil];
    [m_newWordSelector setDoNotMigrate:YES];

    [m_connTable setDoubleAction:@selector(editConnection:)];
}

#pragma mark New Connections

@synthesize newConnRel = a_newConnRel;
@synthesize newConnWord = a_newConnWord;

- (NSNumber *) computeCanAddNewConnection:(OxMemoize*)memo {
    id cntApplRel = [memo valueForKeyPath:@"wordBeingEdited.category.applicableRelationships.@count" // K_WORD_CATEGORY, K_WORD_APPLICABLE_RELATIONSHIPS
                                 ofObject:self];
    return [NSNumber numberWithBool:cntApplRel != nil && [cntApplRel boolValue]];
}

- (NSNumber *) canAddNewConnection {
    return [m_canAddNewConnection computeKey:@"canAddNewConnection"
                                    ofObject:self
                                withSelector:@selector(computeCanAddNewConnection:)];    
}

// This message is sent when the user presses enter in the "new connection"
// text field.  
- (IBAction) addConnection:(id)sender {
    NSAssert(self.newConnRel != nil, @"addConnection: received when newConnRel was nil; control should be disable");

    // First, forward it to the new word selector which will let the user pick an
    // exact word (or make a new one!).  The user might cancel here.
    [m_newWordSelector updateWord:sender];
    if (self.newConnWord == nil)
        return;
    
    // Check whether a connection of this kind already exists, and if not, make
    // one.
    for (Connection *conn in self.wordBeingEdited.connectionsFrom)
        if (conn.type == self.newConnRel && conn.toWord == self.newConnWord)
            return; // conn exists
    
    // Create the new connection object.
    Connection *newConn = [NSEntityDescription insertNewObjectForEntityForName:E_CONNECTION
                                                        inManagedObjectContext:[m_vocabulary managedObjectContext]];
    newConn.type = self.newConnRel;
    newConn.fromWord = self.wordBeingEdited;
    newConn.toWord = self.newConnWord;
}

#pragma mark Editing Existing Connections

@synthesize connRel = a_connRel;
@synthesize connWord = a_connWord;

- (void) startEditSheet {
    [NSApp beginSheet:m_editConn
       modalForWindow:m_mainWindow
        modalDelegate:self
       didEndSelector:@selector(editConnSheetDidEnd:returnCode:contextInfo:)
          contextInfo:nil];
}

- (IBAction) ignore:(id)sender {
    // this is only here because apparently to send a double action, a 
    // normal action must be set?
}

- (IBAction) editConnection:(id)sender {
    // m_connBeingEdited should always be nil except when a conn is actively being edited:
    NSAssert(m_connBeingEdited == nil, @"m_connBeingEdited not nil when starting to add conn");

    // pick the conn. to edit based on currently selected
    m_connBeingEdited = [m_connController selectedObject];
    self.connRel = m_connBeingEdited.type;
    self.connWord = m_connBeingEdited.toWord;
    
    // set the initial string
    [m_editConnTextField setStringValue:self.connWord.text];
    
    [self startEditSheet];
}

- (IBAction) confirmEdit:(id)sender {    
    [NSApp endSheet:m_editConn returnCode:1];
    
    // let the conn word selector pick the word, and handle any migrations
    [m_connWordSelector updateWord:sender];
}

- (IBAction) cancelEdit:(id)sender {
    [NSApp endSheet:m_editConn returnCode:0];
}

- (void) editConnSheetDidEnd:(NSWindow*)window returnCode:(int)ok contextInfo:(void*)contextInfo
{
    [m_editConn orderOut:self];
    m_connBeingEdited = nil;
}

- (Word *) word:(NSString*)text category:(Category*)category
{
    NSManagedObjectContext *mctx = [m_vocabulary managedObjectContext];
    Word *word = [m_vocabulary wordInCategory:category withText:text];
    if (!word) {
        word = [NSEntityDescription insertNewObjectForEntityForName:E_WORD
                                             inManagedObjectContext:mctx];
        word.creationDate = [NSDate date];
        word.text = text;
        word.category = category;
    }
    return word;
}

#pragma mark Sort descriptors

- (NSArray*) sortByOrder {
    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:K_ORDER ascending:YES];
    return [NSArray arrayWithObject:sort];
}

- (NSArray*) sortByName {
    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:K_LANGUAGE_NAME ascending:YES];
    return [NSArray arrayWithObject:sort];
}

#pragma mark Other Properties

//@synthesize wordBeingEdited = a_wordBeingEdited;
@synthesize language = a_language;

- (Word*) wordBeingEdited
{
    return a_wordBeingEdited;
}

- (void) setWordBeingEdited:(Word*)value
{
    a_wordBeingEdited = value;
    
    // when the word changes, we update the "newConnRel" to be some valid 
    // relationship, if there is one.
    if (value != nil)
        self.newConnRel = [value.category.applicableRelationships anyObject];
    else
        self.newConnRel = nil;
}

- (NSManagedObjectContext*) managedObjectContext {
    return [m_vocabulary managedObjectContext];
}

@end
