// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif

#import "remoting/ios/host_refresh.h"

#import "remoting/ios/authorize.h"
#import "remoting/ios/host.h"
#import "remoting/ios/utility.h"

namespace {
NSString* kDefaultErrorMessage = @"The Host list refresh is not available at "
    @"this time.  Please try again later.";
}  // namespace

@interface HostRefresh (Private)
- (void)authentication:(GTMOAuth2Authentication*)auth
               request:(NSMutableURLRequest*)request
                 error:(NSError*)error;
- (void)formatErrorMessage:(NSString*)error;
- (void)notifyDelegate;
@end

// Logic flow begins with refreshHostList, and continues until an error occurs,
// or the host list is returned to the delegate
@implementation HostRefresh

@synthesize jsonData = _jsonData;
@synthesize errorMessage = _errorMessage;
@synthesize delegate = _delegate;

// Override default constructor and initialize internals
- (id)init {
  self = [super init];
  if (self) {
    _jsonData = [[NSMutableData alloc] init];
  }
  return self;
}

// Begin the authentication and authorization process.  Begin the process by
// creating an oAuth2 request to google api's including the needed scopes to
// fetch the users host list.
- (void)refreshHostList:(GTMOAuth2Authentication*)authReq
               delegate:(id<HostRefreshDelegate>)delegate {

  CHECK(_delegate == nil);  // Do not reuse an instance of this class

  _delegate = delegate;

  [Authorize beginRequest:authReq
                 delegate:self
        didFinishSelector:@selector(authentication:request:error:)];
}

// Handle completion of the authorization process. Append service credentials
// for jabber.  If an error occurred, notify user.
- (void)authentication:(NSObject*)auth
               request:(NSMutableURLRequest*)request
                 error:(NSError*)error {
  if (error != nil) {
    [self formatErrorMessage:error.localizedDescription];
  } else {
    // Add credentials for service
    [Authorize appendCredentials:request];

    // Begin connection, the returned reference is not useful right now and
    // marked as __unused
    __unused NSURLConnection* connection =
        [[NSURLConnection alloc] initWithRequest:request delegate:self];
  }
}

// @protocol NSURLConnectionDelegate, handle any error during connection
- (void)connection:(NSURLConnection*)connection
    didFailWithError:(NSError*)error {
  [self formatErrorMessage:[error localizedDescription]];

  [self notifyDelegate];
}

// @protocol NSURLConnectionDataDelegate, may be called async multiple times.
// Each call appends the new data to the known data until completed.
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data {
  [_jsonData appendData:data];
}

// @protocol NSURLConnectionDataDelegate
// Ensure connection succeeded: HTTP 200 OK
- (void)connection:(NSURLConnection*)connection
    didReceiveResponse:(NSURLResponse*)response {
  NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
  if ([response respondsToSelector:@selector(allHeaderFields)]) {
    NSNumber* responseCode =
        [[NSNumber alloc] initWithInteger:[httpResponse statusCode]];
    if (responseCode.intValue != 200) {
      [self formatErrorMessage:[NSString
                                   stringWithFormat:@"HTTP STATUS CODE: %d",
                                                    [httpResponse statusCode]]];
    }
  }
}

// @protocol NSURLConnectionDataDelegate handle a completed connection, parse
// received data, and return host list to delegate
- (void)connectionDidFinishLoading:(NSURLConnection*)connection {
  [self notifyDelegate];
}

// Store a formatted error message to return later
- (void)formatErrorMessage:(NSString*)error {
  _errorMessage = kDefaultErrorMessage;
  if (error != nil && error.length > 0) {
    _errorMessage = [_errorMessage
        stringByAppendingString:[@" " stringByAppendingString:error]];
  }
}

// The connection has finished, call to delegate
- (void)notifyDelegate {
  if (_jsonData.length == 0 && _errorMessage == nil) {
    [self formatErrorMessage:nil];
  }

  [_delegate hostListRefresh:[Host parseListFromJSON:_jsonData]
                errorMessage:_errorMessage];
}
@end