//
//  Watcher.swift
//  Pods
//
//  Created by Tadeas Kriz on 4/25/17.
//
//

import Foundation
import RxSwift

public class Watcher {
    public struct Error: Swift.Error {
        public let message: String
    }

    private let subject = PublishSubject<String>()
    private let path: String
    private let queue: DispatchQueue
    private let events: DispatchSource.FileSystemEvent

    private var source: DispatchSourceFileSystemObject?

    init(path: String, events: DispatchSource.FileSystemEvent = .all, queue: DispatchQueue = DispatchQueue.main) throws {
        self.path = path
        self.events = events
        self.queue = queue

        try setup()
    }

    private func setup() throws {
        let path = self.path
        let handle = open(path , O_EVTONLY)
        guard handle != -1 else {
            throw Error(message: "Failed to open file")
        }

        let source = DispatchSource.makeFileSystemObjectSource(fileDescriptor: handle, eventMask: events, queue: queue)
        source.setEventHandler { [subject, weak source, weak self] in
            if let source = source, source.data.contains(.delete) || source.data.contains(.rename) {
                source.cancel()
                self?.source = nil
                _ = try? self?.setup()
            }
            subject.onNext(path)
        }

        source.setCancelHandler { [subject] in
            close(handle)
        }

        self.source = source

        source.resume()
    }

    func watch() -> Observable<String> {
        return subject
    }

    deinit {
        source?.cancel()
        subject.onCompleted()
    }
}

//
//  Watcher.swift
//  Pods
//
//  Created by Tadeas Kriz on 4/25/17.
//
//

import Foundation
import RxSwift

public class Watcher {
    public struct Error: Swift.Error {
        public let message: String
    }

    private let subject = PublishSubject<String>()
    private let path: String
    private let queue: DispatchQueue
    private let events: DispatchSource.FileSystemEvent

    private var source: DispatchSourceFileSystemObject?

    init(path: String, events: DispatchSource.FileSystemEvent = .all, queue: DispatchQueue = DispatchQueue.main) throws {
        self.path = path
        self.events = events
        self.queue = queue

        try setup()
    }

    private func setup() throws {
        let path = self.path
        let handle = open(path , O_EVTONLY)
        guard handle != -1 else {
            throw Error(message: "Watcher: Failed to open file \(path)")
        }

        let source = DispatchSource.makeFileSystemObjectSource(fileDescriptor: handle, eventMask: events, queue: queue)
        source.setEventHandler { [subject, weak source, weak self] in
            if let source = source, source.data.contains(.delete) || source.data.contains(.rename) {
                source.cancel()
                self?.source = nil
                _ = try? self?.setup()
            }
            subject.onNext(path)
        }

        source.setCancelHandler { [subject] in
            close(handle)
        }

        self.source = source

        source.resume()
    }

    func watch() -> Observable<String> {
        return subject
    }

    deinit {
        source?.cancel()
        subject.onCompleted()
    }
}

Make watcher error more descriptive.
Make watcher error more descriptive.
