<commit_before>#import "Common.h"
#import "MWMMapDownloaderDefaultDataSource.h"
#import "MWMStorage.h"
#import "Statistics.h"

#include "Framework.h"

extern NSString * const kCountryCellIdentifier;
extern NSString * const kSubplaceCellIdentifier;
extern NSString * const kPlaceCellIdentifier;
extern NSString * const kLargeCountryCellIdentifier;

namespace
{
auto compareStrings = ^NSComparisonResult(NSString * s1, NSString * s2)
{
  return [s1 compare:s2 options:NSCaseInsensitiveSearch range:{0, s1.length} locale:[NSLocale currentLocale]];
};

auto compareLocalNames = ^NSComparisonResult(NSString * s1, NSString * s2)
{
  auto const & s = GetFramework().Storage();
  string l1 = s.GetNodeLocalName(s1.UTF8String);
  string l2 = s.GetNodeLocalName(s2.UTF8String);
  return compareStrings(@(l1.c_str()), @(l2.c_str()));
};
} // namespace

using namespace storage;

@interface MWMMapDownloaderDataSource ()

@property (nonatomic, readwrite) BOOL needFullReload;

@end

@interface MWMMapDownloaderDefaultDataSource ()

@property (copy, nonatomic) NSArray<NSString *> * indexes;
@property (copy, nonatomic) NSDictionary<NSString *, NSArray<NSString *> *> * availableCountries;
@property (copy, nonatomic) NSArray<NSString *> * downloadedCountries;

@end

@implementation MWMMapDownloaderDefaultDataSource
{
  TCountryId m_parentId;
}

@synthesize isParentRoot = _isParentRoot;

- (instancetype)initForRootCountryId:(storage::TCountryId)countryId delegate:(id<MWMMapDownloaderProtocol>)delegate
{
  self = [super initWithDelegate:delegate];
  if (self)
  {
    m_parentId = countryId;
    _isParentRoot = (m_parentId == GetFramework().Storage().GetRootId());
    [self load];
  }
  return self;
}

- (void)load
{
  auto const & s = GetFramework().Storage();
  TCountriesVec downloadedChildren;
  TCountriesVec availableChildren;
  s.GetChildrenInGroups(m_parentId, downloadedChildren, availableChildren);
  [self configAvailableSections:availableChildren];
  [self configDownloadedSection:downloadedChildren];
}

- (void)reload
{
  [self.reloadSections removeAllIndexes];
  // Get old data for comparison.
  NSDictionary<NSString *, NSArray<NSString *> *> * availableCountriesBeforeUpdate = self.availableCountries;
  NSInteger const downloadedCountriesCountBeforeUpdate = self.downloadedCountries.count;

  // Load updated data.
  [self load];

  // Compare new data vs old data to understand what kind of reload is required and what sections need reload.
  NSInteger const downloadedCountriesCountAfterUpdate = self.downloadedCountries.count;
  self.needFullReload =
      (downloadedCountriesCountBeforeUpdate == 0 || downloadedCountriesCountAfterUpdate == 0 ||
       availableCountriesBeforeUpdate.count == 0);
  if (self.needFullReload)
    return;
  [availableCountriesBeforeUpdate enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSArray<NSString *> * obj, BOOL * stop)
  {
    NSArray<NSString *> * sectionCountries = self.availableCountries[key];
    if (!sectionCountries)
    {
      self.needFullReload = YES;
      *stop = YES;
    }
    if (obj.count != sectionCountries.count)
      [self.reloadSections addIndex:[self.indexes indexOfObject:key]];
  }];
  [self.reloadSections shiftIndexesStartingAtIndex:0 by:self.downloadedSectionShift];
  if (downloadedCountriesCountBeforeUpdate != downloadedCountriesCountAfterUpdate)
    [self.reloadSections addIndex:self.downloadedSection];
}

- (void)configAvailableSections:(TCountriesVec const &)availableChildren
{
  NSMutableSet<NSString *> * indexSet = [NSMutableSet setWithCapacity:availableChildren.size()];
  NSMutableDictionary<NSString *, NSMutableArray<NSString *> *> * availableCountries = [@{} mutableCopy];
  BOOL const isParentRoot = self.isParentRoot;
  auto const & s = GetFramework().Storage();
  for (auto const & countryId : availableChildren)
  {
    NSString * nsCountryId = @(countryId.c_str());
    string localName = s.GetNodeLocalName(countryId);
    NSString * index = isParentRoot ? [@(localName.c_str()) substringToIndex:1].capitalizedString : L(@"downloader_available_maps");
    [indexSet addObject:index];
<commit_msg>[ios] Fixed download all crash.<commit_after>#import "Common.h"
#import "MWMMapDownloaderDefaultDataSource.h"
#import "MWMStorage.h"
#import "Statistics.h"

#include "Framework.h"

extern NSString * const kCountryCellIdentifier;
extern NSString * const kSubplaceCellIdentifier;
extern NSString * const kPlaceCellIdentifier;
extern NSString * const kLargeCountryCellIdentifier;

namespace
{
auto compareStrings = ^NSComparisonResult(NSString * s1, NSString * s2)
{
  return [s1 compare:s2 options:NSCaseInsensitiveSearch range:{0, s1.length} locale:[NSLocale currentLocale]];
};

auto compareLocalNames = ^NSComparisonResult(NSString * s1, NSString * s2)
{
  auto const & s = GetFramework().Storage();
  string l1 = s.GetNodeLocalName(s1.UTF8String);
  string l2 = s.GetNodeLocalName(s2.UTF8String);
  return compareStrings(@(l1.c_str()), @(l2.c_str()));
};
} // namespace

using namespace storage;

@interface MWMMapDownloaderDataSource ()

@property (nonatomic, readwrite) BOOL needFullReload;

@end

@interface MWMMapDownloaderDefaultDataSource ()

@property (copy, nonatomic) NSArray<NSString *> * indexes;
@property (copy, nonatomic) NSDictionary<NSString *, NSArray<NSString *> *> * availableCountries;
@property (copy, nonatomic) NSArray<NSString *> * downloadedCountries;

@end

@implementation MWMMapDownloaderDefaultDataSource
{
  TCountryId m_parentId;
}

@synthesize isParentRoot = _isParentRoot;

- (instancetype)initForRootCountryId:(storage::TCountryId)countryId delegate:(id<MWMMapDownloaderProtocol>)delegate
{
  self = [super initWithDelegate:delegate];
  if (self)
  {
    m_parentId = countryId;
    _isParentRoot = (m_parentId == GetFramework().Storage().GetRootId());
    [self load];
  }
  return self;
}

- (void)load
{
  auto const & s = GetFramework().Storage();
  TCountriesVec downloadedChildren;
  TCountriesVec availableChildren;
  s.GetChildrenInGroups(m_parentId, downloadedChildren, availableChildren);
  [self configAvailableSections:availableChildren];
  [self configDownloadedSection:downloadedChildren];
}

- (void)reload
{
  [self.reloadSections removeAllIndexes];
  // Get old data for comparison.
  NSDictionary<NSString *, NSArray<NSString *> *> * availableCountriesBeforeUpdate = self.availableCountries;
  NSInteger const downloadedCountriesCountBeforeUpdate = self.downloadedCountries.count;

  // Load updated data.
  [self load];

  // Compare new data vs old data to understand what kind of reload is required and what sections need reload.
  NSInteger const downloadedCountriesCountAfterUpdate = self.downloadedCountries.count;
  self.needFullReload =
      (downloadedCountriesCountBeforeUpdate == 0 || downloadedCountriesCountAfterUpdate == 0 ||
       availableCountriesBeforeUpdate.count == 0);
  if (self.needFullReload)
    return;
  [availableCountriesBeforeUpdate enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSArray<NSString *> * obj, BOOL * stop)
  {
    NSUInteger const sectionIndex = [self.indexes indexOfObject:key];
    if (sectionIndex == NSNotFound)
    {
      self.needFullReload = YES;
      *stop = YES;
    }
    else if (obj.count != self.availableCountries[key].count)
    {
      [self.reloadSections addIndex:sectionIndex];
    }
  }];
  [self.reloadSections shiftIndexesStartingAtIndex:0 by:self.downloadedSectionShift];
  if (downloadedCountriesCountBeforeUpdate != downloadedCountriesCountAfterUpdate)
    [self.reloadSections addIndex:self.downloadedSection];
}

- (void)configAvailableSections:(TCountriesVec const &)availableChildren
{
  NSMutableSet<NSString *> * indexSet = [NSMutableSet setWithCapacity:availableChildren.size()];
  NSMutableDictionary<NSString *, NSMutableArray<NSString *> *> * availableCountries = [@{} mutableCopy];
  BOOL const isParentRoot = self.isParentRoot;
  auto const & s = GetFramework().Storage();
  for (auto const & countryId : availableChildren)
  {
    NSString * nsCountryId = @(countryId.c_str());
    string localName = s.GetNodeLocalName(countryId);
    NSString * index = isParentRoot ? [@(localName.c_str()) substringToIndex:1].capitalizedString : L(@"downloader_available_maps");
    [indexSet addObject:index];

{'fraction_non_alphanumeric': 0.10929359020962075, 'fraction_numerical': 0.005089058524173028, 'mean_word_length': 5.799011532125206, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 43, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4157595', 'n_tokens_mistral': 2568, 'n_tokens_neox': 2422, 'n_words': 511}