<commit_before>//
//  WidgetInstaller.swift
//  Pock
//
//  Created by <NAME> on 03/05/21.
//

import Foundation
import PockKit
import Zip

// MARK: Error
internal enum WidgetsInstallerError: PockError {
	case invalidBundle(reason: String?)
	case cantCopy(reason: String?)
	case cantRemove(reason: String?)
	var description: String {
		switch self {
		case let .invalidBundle(reason):
			return "error.invalid-bundle".localized(reason ?? "error.unknown".localized)
		case let .cantCopy(reason):
			return "error.cant-copy".localized(reason ?? "error.unknown".localized)
		case let .cantRemove(reason):
			return "error.cant-remove".localized(reason ?? "error.unknown".localized)
		}
	}
}

internal final class WidgetsInstaller: NSDocument {

	typealias Error = WidgetsInstallerError
	
	// MARK: State

	internal enum State {
		case dragdrop
		case remove(widget: PKWidgetInfo)
		case install(widget: PKWidgetInfo)
		case installArchive(url: URL)
		case update(widget: PKWidgetInfo, version: Version)
		case removing(widget: PKWidgetInfo)
		case installing(widget: PKWidgetInfo)
		case downloading(widget: PKWidgetInfo, progress: Double)
		case removed(widget: PKWidgetInfo)
		case installed(widget: PKWidgetInfo)
		case updated(widget: PKWidgetInfo)
		case error(_ error: PockError)
		
		case installDefault
		case installingDefault(_ progress: DefaultWidgetsInstallProgress)
		case installedDefault(_ errors: String?)
	}
	
	private lazy var manager: FileManager = FileManager.default
	
	// MARK: NSDocument
	
	override init() {
		// default initialiser
	}
	
	init(contentsOf url: URL, ofType typeName: String) throws {
		super.init()
		let controller = WidgetsManagerViewController()
		AppController.shared.openController(controller)
		do {
			switch url.pathExtension {
			case "pock":
				let widget = try PKWidgetInfo(path: url)
				installWidget(widget) { _, error in
					let state: WidgetsInstaller.State
					if let error = error {
						state = .error(error)
					} else {
						state = .installed(widget: widget)
					}
					controller.presentWidgetInstallPanel(withInitialState: state)
				}
			case "pkarchive":
				let name = url.lastPathComponent.replacingOccurrences(of: ".pkarchive", with: "")
				extractAndInstall(name, atLocation: url, removeSource: false) { widget, error in
					let state: WidgetsInstaller.State
					if let error = error {
						state = .error(error)
					} else if let widget = widget {
						state = .installed(widget: widget)
					} else {
						state = .error(WidgetsInstallerError.invalidBundle(reason: nil))
					}
					controller.presentWidgetInstallPanel(withInitialState: state)
				}
			default:
				controller.presentWidgetInstallPanel(withInitialState: .error(WidgetsInstallerError.invalidBundle(reason: nil)))
			}
			
		} catch {
			controller.presentWidgetInstallPanel(withInitialState: .error(WidgetsInstallerError.invalidBundle(reason: error.localizedDescription)))
		}
	}
	
	// MARK: Methods
	
	// MARK: Install local widget
	
	internal func installWidget(_ widget: PKWidgetInfo, removeSource: Bool = false, _ completion: (PKWidgetInfo?, PockError?) -> Void) {
		do {
			let fromLocation = URL(fileURLWithPath: widget.path.path)
			let toLocation = kWidgetsPathURL.appendingPathComponent(widget.path.lastPathComponent)
			if removeSource {
				try manager.moveItem(at: fromLocation, to: toLocation)
			} else {
				try manager.copyItem(at: fromLocation, to: toLocation)
			}
			completion(widget, nil)
		} catch {<commit_msg>fix: remove previous version before installing<commit_after>//
//  WidgetInstaller.swift
//  Pock
//
//  Created by <NAME> on 03/05/21.
//

import Foundation
import PockKit
import Zip

// MARK: Error
internal enum WidgetsInstallerError: PockError {
	case invalidBundle(reason: String?)
	case cantCopy(reason: String?)
	case cantRemove(reason: String?)
	var description: String {
		switch self {
		case let .invalidBundle(reason):
			return "error.invalid-bundle".localized(reason ?? "error.unknown".localized)
		case let .cantCopy(reason):
			return "error.cant-copy".localized(reason ?? "error.unknown".localized)
		case let .cantRemove(reason):
			return "error.cant-remove".localized(reason ?? "error.unknown".localized)
		}
	}
}

internal final class WidgetsInstaller: NSDocument {

	typealias Error = WidgetsInstallerError
	
	// MARK: State

	internal enum State {
		case dragdrop
		case remove(widget: PKWidgetInfo)
		case install(widget: PKWidgetInfo)
		case installArchive(url: URL)
		case update(widget: PKWidgetInfo, version: Version)
		case removing(widget: PKWidgetInfo)
		case installing(widget: PKWidgetInfo)
		case downloading(widget: PKWidgetInfo, progress: Double)
		case removed(widget: PKWidgetInfo)
		case installed(widget: PKWidgetInfo)
		case updated(widget: PKWidgetInfo)
		case error(_ error: PockError)
		
		case installDefault
		case installingDefault(_ progress: DefaultWidgetsInstallProgress)
		case installedDefault(_ errors: String?)
	}
	
	private lazy var manager: FileManager = FileManager.default
	
	// MARK: NSDocument
	
	override init() {
		// default initialiser
	}
	
	init(contentsOf url: URL, ofType typeName: String) throws {
		super.init()
		let controller = WidgetsManagerViewController()
		AppController.shared.openController(controller)
		do {
			switch url.pathExtension {
			case "pock":
				let widget = try PKWidgetInfo(path: url)
				installWidget(widget) { _, error in
					let state: WidgetsInstaller.State
					if let error = error {
						state = .error(error)
					} else {
						state = .installed(widget: widget)
					}
					controller.presentWidgetInstallPanel(withInitialState: state)
				}
			case "pkarchive":
				let name = url.lastPathComponent.replacingOccurrences(of: ".pkarchive", with: "")
				extractAndInstall(name, atLocation: url, removeSource: false) { widget, error in
					let state: WidgetsInstaller.State
					if let error = error {
						state = .error(error)
					} else if let widget = widget {
						state = .installed(widget: widget)
					} else {
						state = .error(WidgetsInstallerError.invalidBundle(reason: nil))
					}
					controller.presentWidgetInstallPanel(withInitialState: state)
				}
			default:
				controller.presentWidgetInstallPanel(withInitialState: .error(WidgetsInstallerError.invalidBundle(reason: nil)))
			}
			
		} catch {
			controller.presentWidgetInstallPanel(withInitialState: .error(WidgetsInstallerError.invalidBundle(reason: error.localizedDescription)))
		}
	}
	
	// MARK: Methods
	
	// MARK: Install local widget
	
	internal func installWidget(_ widget: PKWidgetInfo, removeSource: Bool = false, _ completion: (PKWidgetInfo?, PockError?) -> Void) {
		do {
			let fromLocation = URL(fileURLWithPath: widget.path.path)
			let toLocation = kWidgetsPathURL.appendingPathComponent(widget.path.lastPathComponent)
            if manager.fileExists(at: toLocation.path, directory: true) {
                try? manager.removeItem(at: toLocation)
            }
            if removeSource {
				try manager.moveItem(at: fromLocation, to: toLocation)
			} else {
				try manager.copyItem(at: fromLocation, to: toLocation)
			}
			completion(widget, nil)
		} catch {
{'fraction_non_alphanumeric': 0.10027972027972028, 'fraction_numerical': 0.0016783216783216783, 'mean_word_length': 4.000699300699301, 'pattern_counts': {'":': 4, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3499813', 'n_tokens_mistral': 2476, 'n_tokens_neox': 2081, 'n_words': 523}