//
//  WordTextFieldDelegate.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 "WordSelector.h"
#import "OxCoreData.h"
#import "OxNSArray.h"
#import "OxNSSet.h"
#import "OxNSString.h"
#import "PickWordController.h"
#import "MigrateConnController.h"

@implementation WordSelector

@synthesize doNotMigrate = m_doNotMigrate;
@synthesize vocabulary = m_vocabulary;
@synthesize window = m_window;
@synthesize word = a_word;
@synthesize language = a_language;

+ (void) initialize
{
    [self exposeBinding:@"word"];
    [self exposeBinding:@"language"];
}

- init
{
    [super init];
    m_binder = [OxBinder new];
    return self;
}

- (void) bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
    NSAssert([[self exposedBindings] containsObject:binding], @"Invalid binding");
    [m_binder bindKeyPath:binding
            ofSlaveObject:self
                toKeyPath:keyPath
           ofMasterObject:observable];
}

- (void) setDoNotMigrate:(BOOL)value
{
    m_doNotMigrate = value;
}

- (IBAction) updateWord:(id)textControl
{
    NSString *wordText = [textControl stringValue];
    
    // Check if wordText is entirely whitespace and bind word to nil if so
    if ([[wordText strip] isEqual:@""]) {
        self.word = nil;
        return;
    }
    
    // Check to see if the text changed from what was there before;
    // if not, don't change the word.
    Word *word = self.word;
    if (word) {
        NSString *oldText = word.text;
        if ([oldText isEqualToString:wordText])
            return;
    }
        
    WordSelectorHelper *helper = [[WordSelectorHelper alloc] initWithMain:self
                                                              textControl:textControl];
    
    [helper performSelectorOnMainThread:@selector(react:)
                             withObject:self
                          waitUntilDone:NO];
}

@end

// Whenever the text changes, we create one of these helpers and
// stick him on the run loop to react to changes.

@implementation WordSelectorHelper 

- initWithMain:(WordSelector*)main textControl:(id)textControl
{
    self = [super init];
    m_main = main;
    m_textControl = textControl;
    return self;
}

- (void) react:(id)sender
{
    NSString *wordText = [m_textControl stringValue];
    
    NSManagedObjectContext *mctx = [m_main.vocabulary managedObjectContext];
    NSArray *existingWords = [mctx objectsOfEntityType:E_WORD 
                               matchingPredicateFormat:
                              K_WORD_TEXT @" BEGINSWITH[cd] %@ OR "
                              K_WORD_TEXT @" ENDSWITH[cd] %@", wordText, wordText];    
    
    [[[PickWordController alloc] initWithDelegate:self
                                         language:m_main.language
                                     existingText:wordText
                                    existingWords:existingWords
                                     parentWindow:m_main.window
                             managedObjectContext:[m_main.vocabulary managedObjectContext]] activate];
    
    // control returns here only once a new word has been picked and old connections
    // migrated.  In case the text of the word ended up changing, or the edits were
    // canceled, reset the text field:
    /*
    NSString *curText = (self.word ? self.word.text : @"");
    NSAssert(curText != nil, @"word with nil text");
    if (![curText isEqualToString:wordText])
        [textField setStringValue:curText];
     */
}

- (void) newWordSelected:(NSString*)text category:(Category*)category
{
    NSManagedObjectContext *mctx = [m_main.vocabulary managedObjectContext];
    Word *word = [NSEntityDescription insertNewObjectForEntityForName:E_WORD
                                               inManagedObjectContext:mctx];
    [word setText:text];
    [word setCategory:category];
    [self existingWordSelected:word];
}

- (void) existingWordSelected:(Word*)newWord
{
    Word *oldWord = m_main.word;
    
    // We have to ask the user what connections from the old word
    // should be migrated to the new word;
    if (!m_main.doNotMigrate 
        && oldWord != nil 
        && (![oldWord.connectionsFrom isEmpty] || ![oldWord.connectionsTo isEmpty]))
    {
        [[[MigrateConnController alloc] initWithFromWord:oldWord
                                                  toWord:newWord
                                            parentWindow:m_main.window
                                                delegate:self] activate];
    } else {
        [self migrateConnections:[NSArray array] toWord:newWord];
    }
}

- (void) migrateConnections:(NSArray*)selectedConns toWord:(Word*)newWord
{
    NSManagedObjectContext *mctx = [m_main.vocabulary managedObjectContext];
    Word *oldWord = m_main.word;

    for (Connection *conn in selectedConns) {
        Word *fromWord, *toWord;        
        NSSet *existingConn;
        if (conn.fromWord == oldWord) {
            fromWord = newWord;
            toWord = conn.toWord;
            existingConn = newWord.connectionsFrom;
        } else {
            fromWord = conn.fromWord;
            toWord = newWord;
            existingConn = newWord.connectionsTo;
        }
        
        // Check if there is an existing connection already
        if ([[existingConn exists] connectsWord:fromWord toWord:toWord withType:conn.type]) {
            // if so, just delete this connection
            [mctx deleteObject:conn];
        } else {
            // otherwise, migrate it
            if (fromWord == newWord) conn.fromWord = fromWord;
            else conn.toWord = toWord;
        }
    }
    
    m_main.word = newWord;
    [m_textControl setStringValue:newWord.text];
}

- (void) cancelChanges
{
    if (m_main.word)
        [m_textControl setStringValue:m_main.word.text];    
    else
        [m_textControl setStringValue:@""];
}

@end
