//
//  KMInputMethodBrowserClientEventHandler.m
//  Keyman
//
//  Created by tom on 1/5/18.
//  Copyright © 2018 SIL International. All rights reserved.
//

#import "KMInputMethodBrowserClientEventHandler.h"
#import "KMInputMethodEventHandlerProtected.h"
#import "KMInputMethodBrowserClientEventHandlerProtected.h"

@implementation KMInputMethodBrowserClientEventHandler

// Because Google Docs can't report its context in any of the browsers (Safari, Chrome, Firefox) and Word sometimes
// has trouble doing this in Chrome, we want to try to detect it so each browser can respond appropriately.
NSUInteger _failuresToRetrieveExpectedContext;

- (instancetype)init {
    return [self initWithLegacyMode:YES clientSelectionCanChangeUnexpectedly:YES];
}

- (instancetype)initWithLegacyMode:(BOOL)legacy clientSelectionCanChangeUnexpectedly:(BOOL) flagClientSelectionCanChangeUnexpectedly {
    self = [super initWithLegacyMode:legacy clientSelectionCanChangeUnexpectedly: flagClientSelectionCanChangeUnexpectedly];
    if (self) {
        _failuresToRetrieveExpectedContext = 0;
    }
    return self;
}

- (void)checkContextIn:(id) client {
    if (!self.willDeleteNullChar && !self.contextOutOfDate && _failuresToRetrieveExpectedContext < 3) {
        if (self.AppDelegate.debugMode) {
            NSLog(@"Checking to see if we're in Google Docs (or some other site that can't give context).");
        }
        NSUInteger bufferLength = self.contextBuffer.length;
        if (bufferLength) {
            NSUInteger location = [client selectedRange].location;
            
            if (location != NSNotFound && location > 0) {
                if ([self AppDelegate].debugMode)
                    NSLog(@"Trying to get context up to location %lu", location);
                NSString* clientContext = [self getLimitedContextFrom:client at:location];
                if (clientContext == nil)
                {
                    // Client is failing to provide useful response to attributedSubstringFromRange.
                    // Word (in MS Live) occasionally does this.
                    [self setInSiteThatDoesNotGiveContext];
                }
                else if (!clientContext.length) {
                    if ([self AppDelegate].debugMode) {
                        NSLog(@"Expected context = '%@'", self.contextBuffer);
                        NSLog(@"Actual clientContext was empty");
                    }
                    _failuresToRetrieveExpectedContext++;
                }
                else
                {
                    unichar lastCodepointExpected = [self.contextBuffer characterAtIndex:bufferLength - 1];
                    unichar lastCodepointInClient = [clientContext characterAtIndex:clientContext.length - 1];
                    if (lastCodepointExpected != lastCodepointInClient) {
                        if ([self AppDelegate].debugMode) {
                            NSLog(@"Expected context = '%@'", self.contextBuffer);
                            NSLog(@"Actual clientContext = '%@'", (clientContext == nil ? @"{nil}" : clientContext));
                            NSLog(@"Last character expected (in contextBuffer) = '%lu'", (unsigned long)lastCodepointExpected);
                            NSLog(@"Last character in clientContext = '%lu'", (unsigned long)lastCodepointInClient);
                        }
                        // MS Word converts/reports plain spaces (32) as non-breaking spaces (160). If we
                        // get this kind of mismatch, we don't want to count this as a definite match, but
                        // we also don't want to count it as a failure to match. So just wait for a more
                        // reliable character to test.
                        if (lastCodepointInClient != 160 || lastCodepointExpected != 32) {
                            _failuresToRetrieveExpectedContext++;
                        }
                    }
                    else {
                        if ([self AppDelegate].debugMode) {
                            NSLog(@"We got what we were expecting from the client. We can stop checking.");
                        }
                        _failuresToRetrieveExpectedContext = NSUIntegerMax;
                    }
                }
            }
            else {
                if ([self AppDelegate].debugMode) {
                    NSLog(@"bufferLength is %lu, but location was %lu.", bufferLength, location);
                }
                _failuresToRetrieveExpectedContext++;
            }
            
            if (_failuresToRetrieveExpectedContext == 3)
                [self setInSiteThatDoesNotGiveContext];
        }
    }
}

- (void)setInSiteThatDoesNotGiveContext {
    if ([self AppDelegate].debugMode) {
        NSLog(@"Detected some editor (e.g., Google Docs) that can't provide context.");
    }
    _failuresToRetrieveExpectedContext = NSUIntegerMax;
    
    if (self.clientSelectionCanChangeUnexpectedly) {
        self.clientCanProvideSelectionInfo = Unreliable;
        self.clientSelectionCanChangeUnexpectedly = NO; // This isn't true (it can change unexpectedly), but we can't get the context, so we pretend/hope it won't.
    }
}
@end
