<commit_before>//
//  WBMaterialProcessor.swift
//  GoWWorldBosses
//
//  Created by <NAME> on 2016-12-11.
//  Copyright © 2016 <NAME>. All rights reserved.
//

import Foundation
import RealmSwift


class WBMaterialProcessor: NSObject {
    let context: WBSyncContext
    
    init (context: WBSyncContext) {
        self.context = context
    }
    
    lazy var materialRemote: WBMaterialRemoteType = {
        return WBMaterialRemote(remoteSession: self.context.remoteSession)
    }()
    
    lazy var itemRemote: WBItemRemote = {
        return WBItemRemote(remoteSession: self.context.remoteSession)
    }()
    
    func sync(completion: @escaping (_ success: Bool, _ syncedObjects: [AnyObject]?, _ error: Error?) -> ()) {
        self.syncMaterialElements { (success, elements, error) in
            guard success,
                let elements = elements else
            {
                completion(false, nil, error)
                return
            }
            
            let ids = elements.map{ $0.id }
            self.syncMaterialItems(byIds: ids, completion: { (success, syncedObjects, error) in
                completion(success, syncedObjects, error)
            })
        }
    }
    
    func syncMaterialElements(completion: @escaping (_ success: Bool, _ elements: [WBJsonMaterialElement]?, _ error: Error?) -> ()) {
        self.materialRemote.fetchMaterialElements { result in
            switch result {
            case .success(let elements):
                guard let elements = elements else {
                    DispatchQueue.main.async {
                        completion(false, nil, nil)
                    }
                    return
                }
                
                let realm = try! Realm()
                let changes: [WBRemoteRecordChange<WBJsonMaterialElement, WBMaterialElement>] = realm.findOrInsert(elements)
                
                try! realm.write {
                    for change in changes {
                        switch change {
                        case .found(let remoteRecord, let localObject):
                            localObject.saveSyncableProperties(fromSyncable: remoteRecord)
                            realm.add(localObject, update: true)
                            break
                        case .inserted(let remoteRecord, let localObject):
                            localObject.saveSyncableProperties(fromSyncable: remoteRecord)
                            realm.add(localObject)
                            break
                        default:
                            break
                        }
                    }
                }
                DispatchQueue.main.async {
                    completion(true, elements, nil)
                }
                break
                
            case .failure(let error):
                DispatchQueue.main.async {
                    completion(false, nil, error)
                }
            }
            
        }
    }
    
    func syncMaterialItems(byIds ids:[String], completion: @escaping (_ success: Bool, _ elements: [WBJsonItem]?, _ error: Error?) -> ())
    {
        let chunkSize = 150
        let chunks = stride(from: 0, to: ids.count, by: chunkSize).map {
            Array(ids[$0..<min($0 + chunkSize, ids.count)])
        }
        
        let dispatchGroup = DispatchGroup()
        var err: Error?
        
        for chunk in chunks {
            // FIXME: v2 does not work?
            dispatchGroup.enter()
            self.itemRemote.fetchItems(byIds: chunk, completion: { result in
                switch result {
                case .success(let items):
                    guard let items = items else
                    {
                        dispatchGroup.leave()
                        return
                    }
                    
                    let realm = try! Realm()
                    let changes: [WBRemoteRecordChange<WBJsonItem, WBItem>] = realm.findOrInsert(items)
                    
                    try! realm.write {
                        for change in changes {
                            switch change {<commit_msg>Fix: potential crash on fetching Material elements<commit_after>//
//  WBMaterialProcessor.swift
//  GoWWorldBosses
//
//  Created by <NAME> on 2016-12-11.
//  Copyright © 2016 <NAME>. All rights reserved.
//

import Foundation
import RealmSwift


class WBMaterialProcessor: NSObject {
    let context: WBSyncContext
    
    init (context: WBSyncContext) {
        self.context = context
    }
    
    lazy var materialRemote: WBMaterialRemoteType = {
        return WBMaterialRemote(remoteSession: self.context.remoteSession)
    }()
    
    lazy var itemRemote: WBItemRemote = {
        return WBItemRemote(remoteSession: self.context.remoteSession)
    }()
    
    func sync(completion: @escaping (_ success: Bool, _ syncedObjects: [AnyObject]?, _ error: Error?) -> ()) {
        self.syncMaterialElements { (success, elements, error) in
            guard success,
                let elements = elements else
            {
                completion(false, nil, error)
                return
            }
            
            let ids = elements.map{ $0.id }
            self.syncMaterialItems(byIds: ids, completion: { (success, syncedObjects, error) in
                completion(success, syncedObjects, error)
            })
        }
    }
    
    func syncMaterialElements(completion: @escaping (_ success: Bool, _ elements: [WBJsonMaterialElement]?, _ error: Error?) -> ()) {
        self.materialRemote.fetchMaterialElements { result in
            switch result {
            case .success(let elements):
                guard let elements = elements else {
                    DispatchQueue.main.async {
                        completion(false, nil, nil)
                    }
                    return
                }
                
                let realm = try! Realm()
                let changes: [WBRemoteRecordChange<WBJsonMaterialElement, WBMaterialElement>] = realm.findOrInsert(elements)
                
                try! realm.write {
                    for change in changes {
                        switch change {
                        case .found(let remoteRecord, let localObject):
                            localObject.saveSyncableProperties(fromSyncable: remoteRecord)
                            realm.add(localObject, update: true)
                            break
                        case .inserted(let remoteRecord, let localObject):
                            localObject.saveSyncableProperties(fromSyncable: remoteRecord)
                            realm.add(localObject)
                            break
                        default:
                            break
                        }
                    }
                }
                DispatchQueue.main.async {
                    completion(true, elements, nil)
                }
                break
                
            case .failure(let error):
                DispatchQueue.main.async {
                    completion(false, nil, error)
                }
            }
            
        }
    }
    
    func syncMaterialItems(byIds ids:[String], completion: @escaping (_ success: Bool, _ elements: [WBJsonItem]?, _ error: Error?) -> ())
    {
        var ids = ids
        ids.uniqueInPlace() // remove duplicates
        
        let chunkSize = 150
        let chunks = stride(from: 0, to: ids.count, by: chunkSize).map {
            Array(ids[$0..<min($0 + chunkSize, ids.count)])
        }
        
        let dispatchGroup = DispatchGroup()
        var err: Error?
        
        for chunk in chunks {
            // FIXME: v2 does not work?
            dispatchGroup.enter()
            self.itemRemote.fetchItems(byIds: chunk, completion: { result in
                switch result {
                case .success(let items):
                    guard let items = items else
                    {
                        dispatchGroup.leave()
                        return
                    }
                    
                    let realm = try! Realm()
                    let changes: [WBRemoteRecordChange<WBJsonItem, WBItem>] = realm.findOrInsert(items)
                    
                    try! realm.write {
                        for change in changes {
                            switch change {
{'fraction_non_alphanumeric': 0.07888823181549379, 'fraction_numerical': 0.004730928444707274, 'mean_word_length': 1.2567387243127837, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3952635', 'n_tokens_mistral': 2084, 'n_tokens_neox': 1937, 'n_words': 482}