/*
 * Copyright 2008 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

#include <map>
#import <JavaScriptCore/JavaScriptCore.h>
#import <WebKit/WebKit.h>
#import "BrowserChannel.h"
#import "Debug.h"
#import "GTMSystemVersion.h"
#import "NSMutableString+HtmlReplacement.h"
#import "LoadModuleMessage.h"
#import "OophmWebScriptObject.h"
#import "SessionHandler.h"
#import "AllowedConnections.h"

/*
 * This is a helper shim to bridge crash events from the core cpp code to the
 * objc plugin and UI layer.
 */
class PluginCrashHandler : public CrashHandler {
public:
  PluginCrashHandler(OophmWebScriptObject* obj) : obj(obj) {
  }
  
  virtual void crash(const char* functionName, const char* message) {
    Debug::log(Debug::Error) << "Crashing with message: "<< message << Debug::flush;
    NSString* str = [NSString stringWithFormat:@"%s\n\n%s", message, functionName];
    [obj crashWithMessage:str];
  }
  virtual bool hasCrashed();
private:
  OophmWebScriptObject* const obj;
};

@interface OophmWebScriptObject (Private)
+ (void)logAndThrowString: (NSString*)message;
- (void)addAllowedHost: (NSString*)host;
- (BOOL)hasCrashed;
- (void)connectAlertDidEnd: (NSAlert*)alert
                returnCode: (int)returnCode
               contextInfo: (void*)contextInfo;
- (BOOL)doConnectWithUrl: (NSString*) url
          withSessionKey: (NSString*) sessionKey
                withHost: (NSString*) host
              withModule: (NSString*) moduleName
   withHostedHtmlVersion: (NSString*) hostedHtmlVersion;
	
@end

// This is declared here so that we can access the category method
bool PluginCrashHandler::hasCrashed() {
  return [obj hasCrashed] ? true : false;
}

@implementation OophmWebScriptObject
+ (void)initialize {
  // Add the plugin's bundle name to the user defaults search path
  NSBundle* pluginBundle = [NSBundle bundleForClass:[OophmWebScriptObject class]];
  NSString* bundleIdentifier = [pluginBundle bundleIdentifier];
  NSUserDefaults* shared = [NSUserDefaults standardUserDefaults];
  [shared addSuiteNamed:bundleIdentifier];
}

+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector {
  if (selector == @selector(initForWebScriptWithJsniContext:)) {
    return NO;
  } else if (selector == @selector(connectWithUrl:withSessionKey:withHost:withModuleName:withHostedHtmlVersion:)) {
    return NO;
  } else if (selector == @selector(crashWithMessage:)) {
    return NO;
  }

  return YES;
}

+ (OophmWebScriptObject*)scriptObjectWithContext: (JSGlobalContextRef) context
                                     withWebView: (WebView*) webView {
  JSGlobalContextRetain(context);
  OophmWebScriptObject* obj = [[[OophmWebScriptObject alloc] init] autorelease];
  obj->_contextRef = context;
  obj->_webView = [webView retain];
  return obj;
}

+ (NSString*)webScriptNameForSelector: (SEL)selector {
  if (selector == @selector(initForWebScriptWithJsniContext:)) {
    return @"init";
  } else if (selector == @selector(connectWithUrl:withSessionKey:withHost:withModuleName:withHostedHtmlVersion:)) {
    return @"connect";
  } else if (selector == @selector(crashWithMessage:)) {
    return @"crash";
  }
  return nil;
}

// Simply return true to indicate the plugin was successfully loaded and
// reachable.
- (BOOL)initForWebScriptWithJsniContext: (WebScriptObject*) jsniContext {
  return YES;
}

- (BOOL)connectWithUrl: (NSString*) url
        withSessionKey: (NSString*) sessionKey
              withHost: (NSString*) host
        withModuleName: (NSString*) moduleName
 withHostedHtmlVersion: (NSString*) hostedHtmlVersion {

  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

  // See if authentication has been bypassed
  if ([defaults boolForKey:@"allowAll"]) {
    return [self doConnectWithUrl:url withSessionKey:sessionKey withHost:host
        withModule:moduleName withHostedHtmlVersion:hostedHtmlVersion];
  }
  
  // TODO(jat): do this only once, refactor to a separate method
  NSArray* allowedHosts = [defaults arrayForKey:@"allowedHosts"];
  if (allowedHosts != nil) {
    AllowedConnections::clearRules();
    int n = [allowedHosts count];
    for (int i = 0; i < n; ++i) {
      NSString* entry = [allowedHosts objectAtIndex:i];
      std::string hostName = [entry UTF8String];
      int len = hostName.length();
      bool exclude = false;
      if (len > 0) {
        if (len > 1 && hostName[0] == '!') {
          exclude = true;
          hostName = hostName.substr(1);
        }
        AllowedConnections::addRule(hostName, exclude);
      }
    }
  }

  const std::string urlStr = [url UTF8String];
  bool allowed = false;
  if (AllowedConnections::matchesRule(urlStr, &allowed)) {
    if (allowed) {
      return [self doConnectWithUrl:url withSessionKey:sessionKey withHost:host
          withModule:moduleName withHostedHtmlVersion:hostedHtmlVersion];
    } else {
      return YES;
    }
  }

  // Otherwise, bring up an alert dialog
  // TODO(jat): add an include/exclude option, currently treat as only include
  NSAlert* alert = [NSAlert alertWithMessageText:@"Initiate development mode session"
                                   defaultButton:@"Deny"
                                 alternateButton:nil
                                     otherButton:@"Allow"
                       informativeTextWithFormat:@"The current web-page would like to initiate a development-mode connection to %@", host];
  
  if ([alert respondsToSelector:@selector(setShowsSuppressionButton:)]) {
    [alert setShowsSuppressionButton:YES];
    [[alert suppressionButton] setTitle:@"Remember this decision for this server"];
  } else {
    [[alert addButtonWithTitle:@"Always allow"] setTag:NSAlertAlternateReturn];
  }
  
  NSBundle* bundle = [NSBundle bundleForClass:[OophmWebScriptObject class]];
	NSArray* contextArray = [[NSArray arrayWithObjects:[url retain],
      [sessionKey retain], [host retain], [moduleName retain],
      [hostedHtmlVersion retain], nil] retain];
  NSString* imagePath = [bundle pathForImageResource:@"gwtlogo"];
  if (imagePath != nil) {
    NSImage* img = [[[NSImage alloc] initByReferencingFile:imagePath] autorelease];
    [alert setIcon:img];
  }
  
  [alert beginSheetModalForWindow:[_webView hostWindow]
                    modalDelegate:self
                   didEndSelector:@selector(connectAlertDidEnd:returnCode:contextInfo:)
                      contextInfo:contextArray];
  return YES;
}

- (void)crashWithMessage: (NSString*)message {
  if (self->_hasCrashed) {
    return;
  }
  self->_hasCrashed = YES;
  
#ifdef GWT_DEBUGDISABLE
  // We'll call out to the JS support function
  JSGlobalContextRef contextRef = self->_contextRef;
  JSStringRef disconnectedName = JSStringCreateWithUTF8CString("__gwt_disconnected");
  JSValueRef disconnected = JSObjectGetProperty(contextRef, JSContextGetGlobalObject(contextRef), disconnectedName, NULL);
  JSStringRelease(disconnectedName);
  
  if (JSValueIsObject(contextRef, disconnected)) {
    // Found hosted.html's crash support
    JSObjectRef disconnectedFunction = JSValueToObject(contextRef, disconnected, NULL);
    JSValueRef exception = NULL;
    JSObjectCallAsFunction(contextRef, disconnectedFunction, JSContextGetGlobalObject(contextRef), 0, NULL, &exception);
    if (!exception) {
      // Couldn't invoke the crash handler.
      return;
    }
  }
#endif //GWT_DEBUGDISABLE

  // Use a simple crash page built into the bundle
  NSBundle* oophmBundle = [NSBundle bundleForClass:[self class]];
  NSString* path = [oophmBundle pathForResource:@"crash" ofType:@"html"];
  NSMutableString* crashPage = [NSMutableString stringWithContentsOfFile:path];
  [crashPage replacePattern:@"__MESSAGE__" withStringLiteral:message];
  
  long major, minor, bugFix;
  [GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugFix];
  NSString* systemVersion = [NSString stringWithFormat:@"%i.%i.%i", major, minor, bugFix];
  [crashPage replacePattern:@"__SYSTEM_VERSION__" withStringLiteral:systemVersion];
  
  NSString* ua = [_webView userAgentForURL:[NSURL URLWithString:@"about:blank"]];
  [crashPage replacePattern:@"__USER_AGENT__" withStringLiteral:ua];
  
  [crashPage replacePattern:@"__DATE__"
          withStringLiteral:[NSString stringWithUTF8String:__DATE__]];
  [crashPage replacePattern:@"__TIME__"
          withStringLiteral:[NSString stringWithUTF8String:__TIME__]];  

  NSURL* currentUrl = [[[[_webView mainFrame] dataSource] response] URL];

  [[_webView mainFrame] loadAlternateHTMLString:crashPage
                                        baseURL:[NSURL fileURLWithPath:path]
                              forUnreachableURL:currentUrl];
}

- (void)dealloc {
  [_webView release];  
  delete _crashHandler;
  [super dealloc];
}

- (void)finalizeForWebScript {
  Debug::log(Debug::Info) << "Finalizing OophmWebScriptObject" << Debug::flush;

  // Disable any lingering JS proxy objects
  _hasCrashed = true;

  // Free memory
  delete _sessionHandler;
  
  if (_hostChannel) {
    _hostChannel->disconnectFromHost();
    delete _hostChannel;
    _hostChannel = NULL;
  }

  if (_contextRef) {
    JSGlobalContextRelease(_contextRef);
    _contextRef = NULL;
  }
}
@end

@implementation OophmWebScriptObject (Private)
+ (void)logAndThrowString:(NSString*)message {
  Debug::log(Debug::Info) << "Throwing exception from WSO: " << message << Debug::flush;
  [WebScriptObject throwException:message];
}

- (void)addAllowedHost:(NSString*)host {
  /*
   * This is more complicated than usual because we're not using the
   * application's default persestent domain.  Instead, we use a plugin-specific
   * domain.
   */
  NSBundle* pluginBundle = [NSBundle bundleForClass:[OophmWebScriptObject class]];
  NSString* bundleIdentifier = [pluginBundle bundleIdentifier];
  
  NSUserDefaults* shared = [NSUserDefaults standardUserDefaults];
  NSDictionary* pluginDict = [shared persistentDomainForName:bundleIdentifier];
  NSArray* allowedHosts = [pluginDict objectForKey:@"allowedHosts"];
  
  NSMutableArray* mutableHosts = [NSMutableArray arrayWithArray:allowedHosts];
  NSMutableDictionary* mutableDict = [NSMutableDictionary dictionaryWithDictionary:pluginDict];
  [mutableHosts addObject:host];
  [mutableDict setObject:mutableHosts forKey:@"allowedHosts"];
  [shared setPersistentDomain:mutableDict forName:bundleIdentifier];
  [shared synchronize];
}

- (BOOL)hasCrashed{
  return self->_hasCrashed;
}

- (void)connectAlertDidEnd:(NSAlert *)alert
                returnCode:(int)returnCode
               contextInfo:(void *)contextInfo {
  NSArray* contextArray = (NSArray*) contextInfo;
  NSString* url = [[contextArray objectAtIndex:0] autorelease];
  NSString* sessionKey = [[contextArray objectAtIndex:1] autorelease];
  NSString* host = [[contextArray objectAtIndex:2] autorelease];
  NSString* moduleName = [[contextArray objectAtIndex:3] autorelease];
  NSString* hostedHtmlVersion = [[contextArray objectAtIndex:4] autorelease];
  [contextArray release];
  
  if (returnCode == NSAlertDefaultReturn) {
    return;
  } else if (returnCode == NSAlertAlternateReturn ||
      [alert respondsToSelector:@selector(suppressionButton)] &&
      [[alert suppressionButton] state] == NSOnState) {
    // TODO(jat): simplify, handle errors
    // Get the host part of the URL and store that
    NSString* server = [[[[[[url componentsSeparatedByString:@"://"]
        objectAtIndex:1] componentsSeparatedByString:@"/"] objectAtIndex:0]
        componentsSeparatedByString:@":"] objectAtIndex:0];
    [self addAllowedHost:server];
  }

  [self doConnectWithUrl:url withSessionKey:sessionKey withHost:host
      withModule:moduleName withHostedHtmlVersion:hostedHtmlVersion];
}

- (BOOL)doConnectWithUrl: (NSString*) url
          withSessionKey: (NSString*) sessionKey
                withHost: (NSString*) host
              withModule: (NSString*) moduleName
   withHostedHtmlVersion: (NSString*) hostedHtmlVersion {
  Debug::log(Debug::Debugging) << "connect : " << [host UTF8String] << " " <<
      [moduleName UTF8String] << Debug::flush;
  
  if (_hostChannel != NULL) {
    [OophmWebScriptObject logAndThrowString:@"Already connected"];
    return NO;
  }
  
  NSArray *parts = [host componentsSeparatedByString:@":"];
  if ([parts count] != 2) {
    [OophmWebScriptObject logAndThrowString:
     [NSString stringWithFormat:@"Incorrect format for host string %i",
      [parts count]]];
    return NO;
  }
  
  NSString *hostPart = [parts objectAtIndex:0];
  NSString *portPart = [parts objectAtIndex:1];
  
  Debug::log(Debug::Debugging) << "Extracted host: " << [hostPart UTF8String] <<
      " and port: " << [portPart UTF8String] << Debug::flush;
  
  char *hostAsChars = const_cast<char*>([hostPart UTF8String]);
  unsigned portAsInt = [portPart intValue];
  
  _hostChannel = new HostChannel();
  if (!_hostChannel->connectToHost(hostAsChars, portAsInt)) {
    [OophmWebScriptObject logAndThrowString:@"HostChannel failed to connect"];
    delete _hostChannel;
    _hostChannel = NULL;
    return NO;
  }
  
  _crashHandler = new PluginCrashHandler(self);
  _sessionHandler = new WebScriptSessionHandler(_hostChannel, _contextRef, _crashHandler);

  std::string hostedHtmlVersionStr([hostedHtmlVersion UTF8String]);
  // TODO: add support for a range of protocol versions when more are added.
  if (!_hostChannel->init(_sessionHandler, BROWSERCHANNEL_PROTOCOL_VERSION,
      BROWSERCHANNEL_PROTOCOL_VERSION, hostedHtmlVersionStr)) {
    [OophmWebScriptObject logAndThrowString:@"HostChannel failed to initialize"];
    _hostChannel->disconnectFromHost();
    delete _hostChannel;
    _hostChannel = NULL;
    return NO;
  }

  const std::string urlStr = [url UTF8String];
  // TODO(jat): add support for tab identity
  const std::string tabKeyStr = "";
  const std::string sessionKeyStr = [sessionKey UTF8String];
  const std::string moduleNameStr = [moduleName UTF8String];
    
  if (!LoadModuleMessage::send(*_hostChannel, urlStr, tabKeyStr, 
                               sessionKeyStr, moduleNameStr,
                               "Safari DMP", _sessionHandler)) {
    _hostChannel->disconnectFromHost();
    delete _hostChannel;
    _hostChannel = NULL;
    [OophmWebScriptObject logAndThrowString:@"Unable to load module"];
    return NO;
  }  
  
  return YES;
}
@end
