OSDN Git Service

NSManagedObjetの監視を別クラスに分けてbindingを削除した
[kcd/KCD.git] / KCD / KenzoDockStatus.swift
index d452047..ec6db52 100644 (file)
 
 import Cocoa
 
-private enum DockState: Int {
+protocol KenzoDockStatusObserver: class {
     
-    case empty = 0
-    case hasShip = 2
-    case completed = 3
-    case notOpen = -1
+    func didUpdate(state: KenzoDockStatus)
+}
+
+protocol KenzoDockStatusObserverDelegate: class {
+    
+    func didChangeState(dock: KenzoDock)
+}
+
+final class KenzoDockObserver {
+    
+    private let dock: KenzoDock
+    private var observation: NSKeyValueObservation?
+    
+    weak var delegate: KenzoDockStatusObserverDelegate? {
+        
+        didSet {
+            delegate?.didChangeState(dock: dock)
+        }
+    }
+    
+    init(dock: KenzoDock) {
+        
+        self.dock = dock
+        
+        observation = dock.observe(\KenzoDock.state) { _, _ in
+            self.delegate?.didChangeState(dock: self.dock)
+        }
+    }
 }
 
 final class KenzoDockStatus: NSObject {
     
-    private let number: Int
-    private let controller = NSArrayController()
-    private var isTasking = false
-    private var didNotify = false
-    private var realTime: TimeInterval = 0.0 {
+    private enum DockState: Int {
+        
+        case empty = 0
+        case hasShip = 2
+        case completed = 3
+        case notOpen = -1
         
-        didSet { time = realTime as NSNumber }
+        case unknown = 999999
     }
     
-    @objc dynamic var time: NSNumber?
-    @objc dynamic var state: NSNumber? {
+    static func valid(number: Int) -> Bool {
         
-        didSet { updateState() }
+        return 1...4 ~= number
     }
-    @objc dynamic var completeTime: NSNumber?
     
+    let number: Int
+    private let observer: KenzoDockObserver
+    
+    private(set) var time: TimeInterval?
+    
+    private var isTasking = false
+    
+    private var state: DockState = .unknown
+    private var rawState: Int = 0 {
+        
+        didSet {
+            state = DockState(rawValue: rawState) ?? .unknown
+        }
+    }
+    private var completeTime: Int = 0
+    
+    private var didNotify = false
+    
+    weak var delegate: KenzoDockStatusObserver?
+    
+    /// CAUTION: 初回起動時/マスタ更新時にはデータがないので失敗する
     init?(number: Int) {
         
-        guard case 1...4 = number else { return nil }
+        guard KenzoDockStatus.valid(number: number) else { return nil }
         
         self.number = number
         
-        super.init()
-        
-        controller.managedObjectContext = ServerDataStore.default.context
-        controller.entityName = KenzoDock.entityName
-        controller.fetchPredicate = NSPredicate(#keyPath(KenzoDock.id), equal: number)
-        controller.automaticallyRearrangesObjects = true
-        controller.fetch(nil)
+        guard let dock = ServerDataStore.default.kenzoDock(by: number) else { return nil }
+        self.observer = KenzoDockObserver(dock: dock)
         
-        bind(NSBindingName(#keyPath(state)), to: controller, withKeyPath: "selection.state")
-        bind(NSBindingName(#keyPath(completeTime)), to: controller, withKeyPath: "selection.complete_time")
+        super.init()
+                
+        observer.delegate = self
     }
     
     private func updateState() {
         
-        guard let state = state as? Int,
-            let stat = DockState(rawValue: state) else {
-                
-                return Logger.shared.log("unknown State")
-        }
-        
-        switch stat {
+        switch state {
+            
         case .empty, .notOpen:
             isTasking = false
             didNotify = false
+            time = nil
             
         case .hasShip, .completed:
             isTasking = true
+            
+        case .unknown:
+            Logger.shared.log("unknown State")
         }
+        
+        delegate?.didUpdate(state: self)
     }
+}
+
+extension KenzoDockStatus: DockInformationUpdater {
     
     func update() {
         
-        if !isTasking {
-            
-            time = nil
-            return
-        }
-        guard let completeTime = completeTime as? Int else {
-            
-            time = nil
-            return
+        defer {
+            delegate?.didUpdate(state: self)
         }
         
+        guard isTasking else { return }
+        
         let compTime = TimeInterval(Int(completeTime / 1_000))
         let diff = compTime - Date().timeIntervalSince1970
         
-        realTime = max(0, diff)
+        // set to 0. if diff is less than 0.
+        time = max(0, diff)
         
+        // notify UserNotification.
         if didNotify { return }
         if diff > 0 { return }
         
@@ -107,3 +148,14 @@ final class KenzoDockStatus: NSObject {
     }
     
 }
+
+extension KenzoDockStatus: KenzoDockStatusObserverDelegate {
+    
+    func didChangeState(dock: KenzoDock) {
+        
+        rawState = dock.state
+        completeTime = dock.complete_time
+        
+        updateState()
+    }
+}