AutoCat/AutoCat/Models/Vehicle.swift

207 lines
6.5 KiB
Swift

import Foundation
import RealmSwift
import DifferenceKit
class VehicleName: Object, Decodable {
@objc dynamic var original: String?
@objc dynamic var normalized: String?
}
class VehicleBrand: Object, Decodable {
@objc dynamic var name: VehicleName?
@objc dynamic var logo: String?
}
class VehicleModel: Object, Decodable {
@objc dynamic var name: VehicleName?
}
class VehicleEngine: Object, Decodable {
@objc dynamic var number: String?
@objc dynamic var volume: Int = 0
@objc dynamic var powerHp: Float = 0
@objc dynamic var powerKw: Float = 0
@objc dynamic var fuelType: String?
}
class VehiclePhoto: Object, Decodable {
@objc dynamic var brand: String?
@objc dynamic var model: String?
@objc dynamic var date: TimeInterval = 0
@objc dynamic var url: String = ""
override var description: String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
let date = Date(timeIntervalSince1970: self.date/1000)
let dateStr = formatter.string(from: date)
return "\(self.brand ?? "") \(self.model ?? "") (\(dateStr))"
}
}
enum OwnerType: String {
case legal
case individual
}
enum SteeringWheelPosition: CustomStringConvertible {
case left
case right
case unknown
var description: String {
switch self {
case .left: return "Left"
case .right: return "Right"
case .unknown: return "Unknown"
}
}
}
class VehicleOwnershipPeriod: Object, Decodable {
@objc dynamic var lastOperation: String
@objc dynamic var ownerType: String
@objc dynamic var from: Int64
@objc dynamic var to: Int64
}
class Vehicle: Object, Decodable, Identifiable, Differentiable {
@objc dynamic var brand: VehicleBrand?
@objc dynamic var model: VehicleModel?
@objc dynamic var color: String?
@objc dynamic var year: Int = 0
@objc dynamic var category: String?
@objc dynamic var engine: VehicleEngine?
@objc private dynamic var number: String = ""
@objc dynamic var currentNumber: String?
@objc dynamic var vin1: String?
@objc dynamic var vin2: String?
@objc dynamic var sts: String?
@objc dynamic var pts: String?
var isRightWheel = RealmOptional<Bool>()
@objc dynamic var isJapanese: Bool = false
@objc dynamic var addedDate: TimeInterval = 0
@objc dynamic var updatedDate: TimeInterval = 0
@objc dynamic var addedBy: String = ""
let photos = List<VehiclePhoto>()
let ownershipPeriods = List<VehicleOwnershipPeriod>()
let events = List<VehicleEvent>()
var identifier: String = ""
var id: String {
if self.identifier.isEmpty {
self.identifier = self.number
}
return self.identifier
}
var differenceIdentifier: String { id }
func isContentEqual(to source: Vehicle) -> Bool {
return self == source
}
enum CodingKeys: String, CodingKey {
case brand
case model
case color
case year
case category
case engine
case number
case currentNumber
case vin1
case vin2
case sts
case pts
case isRightWheel
case isJapanese
case addedDate
case addedBy
case photos
case ownershipPeriods
case events
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.brand = try container.decodeIfPresent(VehicleBrand.self, forKey: .brand)
self.model = try container.decodeIfPresent(VehicleModel.self, forKey: .model)
self.color = try container.decodeIfPresent(String.self, forKey: .color)
self.year = try container.decodeIfPresent(Int.self, forKey: .year) ?? 0
self.category = try container.decodeIfPresent(String.self, forKey: .category)
self.engine = try container.decodeIfPresent(VehicleEngine.self, forKey: .engine)
self.number = try container.decode(String.self, forKey: .number)
self.currentNumber = try container.decodeIfPresent(String.self, forKey: .currentNumber)
self.vin1 = try container.decodeIfPresent(String.self, forKey: .vin1)
self.vin2 = try container.decodeIfPresent(String.self, forKey: .vin2)
self.sts = try container.decodeIfPresent(String.self, forKey: .sts)
self.pts = try container.decodeIfPresent(String.self, forKey: .pts)
self.isRightWheel = try container.decode(RealmOptional<Bool>.self, forKey: .isRightWheel)
self.isJapanese = try container.decode(Bool.self, forKey: .isJapanese)
self.addedDate = (try container.decode(TimeInterval.self, forKey: .addedDate))/1000
self.addedBy = try container.decode(String.self, forKey: .addedBy)
if let photosArray = try container.decodeIfPresent([VehiclePhoto].self, forKey: .photos) {
self.photos.append(objectsIn: photosArray)
}
if let ownersipsArray = try container.decodeIfPresent([VehicleOwnershipPeriod].self, forKey: .ownershipPeriods) {
self.ownershipPeriods.append(objectsIn: ownersipsArray)
}
if let eventsArray = try container.decodeIfPresent([VehicleEvent].self, forKey: .events) {
self.events.append(objectsIn: eventsArray)
}
if let lastEventDate = self.events.max(by: { $0.date < $1.date })?.date {
self.updatedDate = max(self.addedDate, lastEventDate)
} else {
self.updatedDate = self.addedDate
}
self.identifier = self.number
}
required init() {
super.init()
self.identifier = self.number
}
init(_ number: String) {
self.identifier = number
self.number = number
self.addedDate = Date().timeIntervalSince1970
self.updatedDate = self.addedDate
}
func getNumber() -> String {
if self.identifier.isEmpty {
self.identifier = self.number
}
return self.number
}
override static func primaryKey() -> String? {
return "number"
}
override class func ignoredProperties() -> [String] {
return ["id", "identifier", "differenceIdentifier"]
}
var unrecognized: Bool {
return self.brand == nil
}
var outdated: Bool {
if let current = self.currentNumber {
return current != self.number
} else {
return false
}
}
}