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

#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.h"

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#include "flutter/fml/logging.h"

FLUTTER_ASSERT_NOT_ARC

@interface FlutterRestorationPlugin ()
@property(nonatomic, copy) FlutterResult pendingRequest;
@end

@implementation FlutterRestorationPlugin {
  BOOL _waitForData;
  BOOL _restorationEnabled;
}

- (instancetype)initWithChannel:(FlutterMethodChannel*)channel
             restorationEnabled:(BOOL)restorationEnabled {
  FML_DCHECK(channel) << "channel must be set";
  self = [super init];
  if (self) {
    [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
      [self handleMethodCall:call result:result];
    }];
    _restorationEnabled = restorationEnabled;
    _waitForData = restorationEnabled;
  }
  return self;
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
  if ([[call method] isEqualToString:@"put"]) {
    NSAssert(self.pendingRequest == nil, @"Cannot put data while a get request is pending.");
    FlutterStandardTypedData* data = [call arguments];
    self.restorationData = [data data];
    result(nil);
  } else if ([[call method] isEqualToString:@"get"]) {
    if (!_restorationEnabled || !_waitForData) {
      result([self dataForFramework]);
      return;
    }
    NSAssert(self.pendingRequest == nil, @"There can only be one pending request.");
    self.pendingRequest = result;
  } else {
    result(FlutterMethodNotImplemented);
  }
}

- (void)setRestorationData:(NSData*)data {
  if (data != _restorationData) {
    [_restorationData release];
    _restorationData = [data retain];
  }
  _waitForData = NO;
  if (self.pendingRequest != nil) {
    self.pendingRequest([self dataForFramework]);
    self.pendingRequest = nil;
  }
}

- (void)markRestorationComplete {
  _waitForData = NO;
  if (self.pendingRequest != nil) {
    NSAssert(_restorationEnabled, @"No request can be pending when restoration is disabled.");
    self.pendingRequest([self dataForFramework]);
    self.pendingRequest = nil;
  }
}

- (void)reset {
  self.pendingRequest = nil;
  self.restorationData = nil;
}

- (NSDictionary*)dataForFramework {
  if (!_restorationEnabled) {
    return @{@"enabled" : @NO};
  }
  if (self.restorationData == nil) {
    return @{@"enabled" : @YES};
  }
  return @{
    @"enabled" : @YES,
    @"data" : [FlutterStandardTypedData typedDataWithBytes:self.restorationData]
  };
}

- (void)dealloc {
  [_restorationData release];
  [_pendingRequest release];
  [super dealloc];
}

@end
