Files
Zockerhoehle/Zockerhoehle/Utils/LibraryImport.swift

248 lines
8.2 KiB
Swift

//
// LibraryImport.swift
// Zockerhoehle
//
// Created by Julian-Steffen Müller on 20.11.19.
// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
//
import Foundation
import UIKit
import CoreData
// MARK: - Library Import
class LibraryImport {
let CDContext : NSManagedObjectContext
init(context CDContext: NSManagedObjectContext = CDManager.shared.viewContext) {
self.CDContext = CDContext
}
static func backupName(from filename : String) -> String? {
if filename.hasPrefix("libExp_") && filename.hasSuffix(".json") {
var backupName = filename
backupName.removeFirst("libExp_".count)
backupName.removeLast(".json".count)
return backupName
}else{
return .none
}
}
func backupFiles() -> [String] {
do {
guard let documentDirectory = try ICloudManager.backup_folder else { return [] }
let filesInDocumentsDir = try FileManager.default.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: .none, options: [])
let backupFiles = filesInDocumentsDir.filter{
$0.isFileURL
}.map {
$0.lastPathComponent
}.filter {
$0.hasPrefix("libExp_") && $0.hasSuffix(".json")
}.sorted(by: { $0 > $1 })
return backupFiles
}catch let error {
print(error)
print("LibraryImport::backupFiles - Error reading files from Document directory!")
}
return []
}
private func resetDatabase() {
self.CDContext.reset()
self.CDContext.performAndWait {
let deleteRequests =
[NSBatchDeleteRequest(fetchRequest: Game.fetchRequest()),
NSBatchDeleteRequest(fetchRequest: Accessory.fetchRequest()),
NSBatchDeleteRequest(fetchRequest: Console.fetchRequest()),
NSBatchDeleteRequest(fetchRequest: GameSeries.fetchRequest())]
let storeCoordinator = CDManager.shared.persistentContainer.persistentStoreCoordinator
do {
for deleteRequest in deleteRequests {
try storeCoordinator.execute(deleteRequest, with: CDContext)
}
}catch let error {
print(error)
print("LibraryImport::resetDatabase - Reset of Database failes!")
}
}
}
private func makeCDGame(from game: BHLGame, _ gameDict: inout [UUID : Game], _ cdConsole: Console) {
let cdGame = Game(context: self.CDContext)
gameDict[game.uuid] = cdGame
cdGame.name = game.name ?? "n/a"
cdGame.uuid = game.uuid
cdGame.inWishlist = game.inWishlist
cdGame.isFinished = game.isFinished
cdGame.finishedDate = game.finishedDate
cdGame.lentTo = game.lentTo
cdGame.cover_icloud_path = game.cover_icloud_path
cdGame.pickupDescription = game.pickupDescription
cdGame.isDigital = game.isDigital
if let date = Date.from(string: game.createdAt) {
cdGame.createdAt = date
}else{
print("Could not decode date '\(game.createdAt)' for game '\(cdGame.name)'")
}
cdConsole.addToGames(cdGame)
cdGame.console = cdConsole
print("Imported: \(cdGame.name) for \(cdConsole.name)")
}
private func makeCDAccessory(from accessory: BHLAccessory, _ accessoryDict: inout [UUID : Accessory], _ cdConsole: Console) {
let cdAccessory = Accessory(context: self.CDContext)
accessoryDict[accessory.uuid] = cdAccessory
cdAccessory.name = accessory.name
cdAccessory.uuid = accessory.uuid
cdAccessory.lentTo = accessory.lentTo
cdAccessory.color = accessory.color
cdAccessory.manufacturer = accessory.manufacturer
cdAccessory.inWishlist = accessory.inWishlist
cdConsole.addToAccessories(cdAccessory)
cdAccessory.console = cdConsole
}
private func makeCDConsole(from console : BHLConsole) -> Console {
let cdConsole = Console(context: self.CDContext)
cdConsole.name = console.name ?? "n/a"
cdConsole.uuid = console.uuid
cdConsole.manufacturer = console.manufacturer
cdConsole.shortName = console.shortName
cdConsole.logo_icloud_path = console.logo_icloud_path
cdConsole.releaseDate = console.releaseDate
return cdConsole
}
private func makeCDGameSeries(from gameSeries: BHLGameSeries, _ gameDict: inout [UUID : Game]) {
let cdGameSeries = GameSeries(context: self.CDContext)
cdGameSeries.name = gameSeries.name
cdGameSeries.cover_icloud_path = gameSeries.cover_icloud_path
for uuid in gameSeries.games {
if let game = gameDict[uuid] {
cdGameSeries.addToGames(game)
game.series = cdGameSeries
}
}
}
func importLIB(from filename: String) {
guard let file = ICloudManager.backup_folder?.appendingPathComponent(filename) else {
print("LibraryImport:importLIB Could not get icloud backup folder")
return
}
if file.isFileURL {
do {
let data = try Data(contentsOf: file)
importLIB(data: data)
}catch let error {
print("LibraryImport::importLIB::String - Cannot create data from file '\(error)'")
}
}
}
func importLIB(data : Data) {
do {
let library = try JSONDecoder().decode(BHLibrary.self, from: data)
resetDatabase()
var gameDict = [UUID:Game]()
var accessoryDict = [UUID:Accessory]()
for console in library.consoles {
let cdConsole = makeCDConsole(from: console)
print("CONSOLE: \(cdConsole.name ?? "n/a") with \(console.games.count) games")
for uuid in console.games {
if let game = library.games.first(where: {$0.uuid == uuid}) {
makeCDGame(from: game, &gameDict, cdConsole)
}else{
print("LibraryImport::importLIB - Game with UUID '\(uuid)' not found")
}
}
for uuid in console.accessories {
if let accessory = library.accessories.first(where: {$0.uuid == uuid}) {
makeCDAccessory(from: accessory, &accessoryDict, cdConsole)
}else{
print("LibraryImport::importLIB - Accessory with UUID '\(uuid)' not found")
}
}
}
for gameSeries in library.gameSeries {
makeCDGameSeries(from: gameSeries, &gameDict)
}
}catch let error {
print("LibraryImport::importLIB::DATA - Error while importing! '\(error)'")
}
}
}
// MARK: - BHLLibrary Classes
struct BHLibrary : Decodable {
let games : [BHLGame]
let consoles : [BHLConsole]
let gameSeries : [BHLGameSeries]
let accessories : [BHLAccessory]
}
struct BHLGame : Decodable {
let uuid : UUID
let name : String?
let lentTo : String?
let isDigital : Bool
let inWishlist : Bool
let isFinished : Bool
let finishedDate : Date?
let notes : String?
let createdAt : String
let pickupDescription : String?
let publisher : String?
let console : UUID
let cover_icloud_path : String?
}
struct BHLAccessory : Decodable {
let uuid : UUID
let name : String
let color : String?
let manufacturer : String?
let inWishlist : Bool
let lentTo : String?
let console : UUID?
}
struct BHLGameSeries : Decodable {
let uuid : UUID
let name : String
let games : [UUID]
let cover_icloud_path : String?
}
struct BHLConsole : Decodable {
let uuid : UUID
let name : String?
let logo_icloud_path : String?
let manufacturer : String?
let releaseDate : Date
let shortName : String?
let accessories : [UUID]
let games : [UUID]
}