//
//  QuizAnswer.m
//  Flash
//
//  Created by Niko Matsakis on 11/11/06.
//  Copyright 2006 __MyCompanyName__. All rights reserved.
//

#import "QuizAnswer.h"
#import "Accessors.h"
#import "OAMacros.h"
#import "DictionaryDocument.h"
#import "OADebug.h"
#import "OACategories.h"
#import "OACoreData.h"
#import "Preferences.h"

@implementation QuizAnswer

#pragma mark -
#pragma mark Initialization

- initWithConnection:(NSManagedObject*)connection 
          answerWord:(NSManagedObject*)word
            indirect:(BOOL)indirect
          dictionary:(DictionaryDocument*)dictionary
{
    if ((self = [super init])) {
        m_connection = [connection retain];
        m_answerWord = [word retain];
        m_dictionary = dictionary;
        m_indirect = indirect;
        
        if ([m_connection fromValue] == m_answerWord) {
            m_inverse = YES;
            m_questionWord = [m_connection toValue];
        }
        else {
            m_inverse = NO;
            m_questionWord = [m_connection fromValue];
        }

        [m_questionWord retain];
    }
    return self;
}

- (void) dealloc 
{
    [m_connection release];
    [m_questionWord release];
    [m_answerWord release];
    [super dealloc];
}

#pragma mark -
#pragma mark Queries

- (BOOL) groupWith:(QuizAnswer*)qa
{
    return [m_connection typeValue] == [qa->m_connection typeValue];
}

- (NSManagedObject*) questionWord
{
    return m_questionWord;
}

// Returns the word whose text the user is expected to type
- (NSManagedObject*) answerWord
{
    return m_answerWord;
}

// Returns a description of the relationship, such as
// @"inverse past tense" or @"equivalent"
- (NSString*) relationshipDescription
{
    NSString *invPrompt = (m_inverse ? @"Inverse " : @"");

    // If this answer is not directly connected to our
    // question word, then we include the word that the
    // answer IS directly related to as a hint for the
    // prompt.  i.e., if the question word is "I ate"
    // and the answer is "comer", which is indirectly
    // connected through the word "to eat", then we ask
    // for 'equivalent of "to eat"', not just 'equivalent'
    NSString *hintPrompt = @"";
    if (m_indirect) 
        hintPrompt = [NSString stringWithFormat:@" of \"%@\"", [m_questionWord textValue]];
    
    NSString *relName = [[m_connection typeValue] nameValue];
    
    return [NSString stringWithFormat:@"%@%@%@", invPrompt, relName, hintPrompt];
}

// Returns the language the user's answer should be in
- (NSManagedObject*) answerLanguage
{
    return [m_answerWord languageValue];
}

#pragma mark -
#pragma mark Dealing with concurrent modification

// Invoked when the user changes the set of words
// during a quiz.  Indicates whether the connection
// we are asking about was removed by returning 
// a false NSNumber if so.
- (NSNumber*) shouldRetainAnswer
{
    if ([m_connection isDeleted] || 
        [m_connection toValue] == nil ||
        [m_connection fromValue] == nil ||
        [m_connection typeValue] == nil) 
    {
        return [NSNumber numberWithBool:NO];
    }
    
    return [NSNumber numberWithBool:YES];    
}

#pragma mark -
#pragma mark Marking a word as learned (or unlearned)

- (void) markWordForUser:(NSManagedObject*)user correct:(BOOL)correct
{
    OAINDENTED(@"Marking answer %@ correct=%d", [m_answerWord textValue], correct) {
        
        // Find existing Learning object, or create one if none exists.
        NSManagedObjectContext *mctx = [m_dictionary managedObjectContext];
        NSManagedObject *learning = [mctx objectOfEntityType:E_LEARNING
                                     matchingPredicateFormat:@"user == %@ and connection == %@", 
            user, m_connection];
        if (!learning) {
            OALog (@"Creating new learning for connection %@", m_connection);
            learning =  [NSEntityDescription insertNewObjectForEntityForName:@"Learning"
                                                      inManagedObjectContext:[m_dictionary managedObjectContext]];
            [learning setValue:m_connection forKey:@"connection"];
            [learning setValue:user forKey:@"user"];
        }
		
        // Determine the interval until we ask again.
        int stage;
        if (correct) {
            // After a correct answer, we increment the "stage" (number of times that the word has been
            // answered correctly in a row).  We then determine how many days to wait until
            // we ask again.  Right now, we increase the time exponentially, but cap it at once every 1.5 months.
            stage = [learning stageValue]+1;
			if (stage < 0)
				stage = 1;
        }
        else {
            // After a negative answer, we set the stage to -1 and re-ask the word after 22 hours.
            // Why 22?  The idea is that if they take their quiz "in the morning", they will get 
            // asked again in the morning.  This gives people some lee-way in when they take their 
            // quiz.  Could do it better if I was less lazy, I guess.
            stage = -1; 
        }        
		
        /* Adjust when to next ask for this word and it's current "stage" */
		[learning setStageValue:stage];
		[learning adjustAskNextOnFromStage];
    } OAUNDENTED;
}

- (void) markCorrectForUser:(NSManagedObject*)user
{
    [self markWordForUser:user correct:YES];
}
    
- (void) markWrongForUser:(NSManagedObject*)user
{
    [self markWordForUser:user correct:NO];
}

@end
