/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import "NSDictionary+FBUtf8SafeDictionary.h"

const unichar REPLACER = 0xfffd;

@implementation NSString (FBUtf8SafeString)

- (instancetype)fb_utf8SafeStringWithReplacement:(unichar)replacement
{
  if ([self canBeConvertedToEncoding:NSUTF8StringEncoding]) {
    return self;
  }

  NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
  NSString *convertedString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  NSMutableString *result = [NSMutableString string];
  NSString *replacementStr = [NSString stringWithCharacters:&replacement length:1];
  NSUInteger originalIdx = 0;
  NSUInteger convertedIdx = 0;
  while (originalIdx < [self length] && convertedIdx < [convertedString length]) {
    unichar originalChar = [self characterAtIndex:originalIdx];
    unichar convertedChar = [convertedString characterAtIndex:convertedIdx];

    if (originalChar == convertedChar) {
      [result appendString:[NSString stringWithCharacters:&originalChar length:1]];
      originalIdx++;
      convertedIdx++;
      continue;
    }

    while (originalChar != convertedChar && originalIdx < [self length]) {
      [result appendString:replacementStr];
      originalChar = [self characterAtIndex:++originalIdx];
    }
  }
  return result.copy;
}

@end

@implementation NSArray (FBUtf8SafeArray)

- (instancetype)fb_utf8SafeArray
{
  NSMutableArray *result = [NSMutableArray array];
  for (id item in self) {
    if ([item isKindOfClass:NSString.class]) {
      [result addObject:[(NSString *)item fb_utf8SafeStringWithReplacement:REPLACER]];
    } else if ([item isKindOfClass:NSDictionary.class]) {
      [result addObject:[(NSDictionary *)item fb_utf8SafeDictionary]];
    } else if ([item isKindOfClass:NSArray.class]) {
      [result addObject:[(NSArray *)item fb_utf8SafeArray]];
    } else {
      [result addObject:item];
    }
  }
  return result.copy;
}

@end

@implementation NSDictionary (FBUtf8SafeDictionary)

- (instancetype)fb_utf8SafeDictionary
{
  NSMutableDictionary *result = [self mutableCopy];
  for (id key in self) {
    id value = result[key];
    if ([value isKindOfClass:NSString.class]) {
      result[key] = [(NSString *)value fb_utf8SafeStringWithReplacement:REPLACER];
    } else if ([value isKindOfClass:NSArray.class]) {
      result[key] = [(NSArray *)value fb_utf8SafeArray];
    } else if ([value isKindOfClass:NSDictionary.class]) {
      result[key] = [(NSDictionary *)value fb_utf8SafeDictionary];
    }
  }
  return result.copy;
}

@end
