AutoCat/AutoCatCore/Models/Vehicle.swift

360 lines
12 KiB
Swift

import Foundation
import RealmSwift
import DifferenceKit
public class VehicleName: Object, Decodable, Cloneable {
@objc public dynamic var original: String?
@objc public dynamic var normalized: String?
public required init(copy: VehicleName) {
self.original = copy.original
self.normalized = copy.normalized
}
required init() {
}
}
public class VehicleBrand: Object, Decodable, Cloneable {
@objc public dynamic var name: VehicleName?
@objc public dynamic var logo: String?
public required init(copy: VehicleBrand) {
self.name = copy.name?.clone()
self.logo = copy.logo
}
required init() {
super.init()
}
}
public class VehicleModel: Object, Decodable, Cloneable {
@objc dynamic var name: VehicleName?
public required init(copy: VehicleModel) {
self.name = copy.name?.clone()
}
required init() {
super.init()
}
}
public class VehicleEngine: Object, Decodable, Cloneable {
@objc public dynamic var number: String?
public var volume: RealmOptional<Int> = RealmOptional(0)
@objc public dynamic var powerHp: Float = 0
public var powerKw: RealmOptional<Float> = RealmOptional(0)
@objc public dynamic var fuelType: String?
enum CodingKeys: String, CodingKey {
case number, volume, powerHp, powerKw, fuelType
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.number = try container.decodeIfPresent(String.self, forKey: .number)
self.volume = RealmOptional(try container.decodeIfPresent(Int.self, forKey: .volume))
self.powerHp = try container.decode(Float.self, forKey: .powerHp)
self.powerKw = RealmOptional(try container.decodeIfPresent(Float.self, forKey: .powerKw))
self.fuelType = try container.decodeIfPresent(String.self, forKey: .fuelType)
}
required init() {
super.init()
}
public required init(copy: VehicleEngine) {
self.number = copy.number
self.volume = copy.volume
self.powerHp = copy.powerHp
self.powerKw = copy.powerKw
self.fuelType = copy.fuelType
}
}
public class VehiclePhoto: Object, Decodable, Cloneable {
@objc public dynamic var brand: String?
@objc public dynamic var model: String?
@objc public dynamic var date: TimeInterval = 0
@objc public dynamic var url: String = ""
public override var description: String {
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier:"GMT")
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))"
}
public required init(copy: VehiclePhoto) {
self.brand = copy.brand
self.model = copy.model
self.date = copy.date
self.url = copy.url
}
required init() {
super.init()
}
}
public enum OwnerType: String, CustomStringConvertible {
case legal
case individual
public var description: String {
switch self {
case .legal: return NSLocalizedString("legal", comment: "Owner type")
case .individual: return NSLocalizedString("individual", comment: "Owner type")
}
}
}
public enum SteeringWheelPosition: CustomStringConvertible {
case left
case right
case unknown
public var description: String {
switch self {
case .left: return "Left"
case .right: return "Right"
case .unknown: return "Unknown"
}
}
}
public class VehicleOwnershipPeriod: Object, Decodable, Cloneable {
@objc public dynamic var lastOperation: String = ""
@objc public dynamic var ownerType: String = ""
@objc public dynamic var from: Int64 = 0
@objc public dynamic var to: Int64 = 0
@objc public dynamic var region: String?
@objc public dynamic var registrationRegion: String?
@objc public dynamic var locality: String?
@objc public dynamic var code: String?
@objc public dynamic var street: String?
@objc public dynamic var building: String?
@objc public dynamic var inn: String?
required public init(copy: VehicleOwnershipPeriod) {
self.lastOperation = copy.lastOperation
self.ownerType = copy.ownerType
self.from = copy.from
self.to = copy.to
self.region = copy.region
self.registrationRegion = copy.registrationRegion
self.locality = copy.locality
self.code = copy.code
self.street = copy.street
self.building = copy.building
self.inn = copy.inn
}
required init() {
super.init()
}
}
public class Vehicle: Object, Decodable, Identifiable, Differentiable, Cloneable, Exportable {
@objc public dynamic var brand: VehicleBrand?
@objc public dynamic var model: VehicleModel?
@objc public dynamic var color: String?
@objc public dynamic var year: Int = 0
@objc public dynamic var category: String?
@objc public dynamic var engine: VehicleEngine?
@objc private dynamic var number: String = ""
@objc public dynamic var currentNumber: String?
@objc public dynamic var vin1: String?
@objc public dynamic var vin2: String?
@objc public dynamic var sts: String?
@objc public dynamic var pts: String?
public var isRightWheel = RealmOptional<Bool>()
public var isJapanese: RealmOptional<Bool> = RealmOptional<Bool>()
@objc public dynamic var addedDate: TimeInterval = 0
@objc public dynamic var updatedDate: TimeInterval = 0
@objc public dynamic var addedBy: String = ""
public var photos = List<VehiclePhoto>()
public var ownershipPeriods = List<VehicleOwnershipPeriod>()
public var events = List<VehicleEvent>()
public var osagoContracts = List<Osago>()
public var ads = List<VehicleAd>()
@objc public dynamic var debugInfo: DebugInfo?
lazy var formatter: DateFormatter = {
let f = DateFormatter()
f.dateStyle = .medium
f.timeStyle = .medium
return f
}()
public var differenceIdentifier: String { self.number }
public func isContentEqual(to source: Vehicle) -> Bool {
return self.number == source.number &&
self.addedDate == source.addedDate &&
self.updatedDate == source.updatedDate
}
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 updatedDate
case addedBy
case photos
case ownershipPeriods
case events
case osagoContracts
case ads
case debugInfo
}
required public 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.number = try container.decode(String.self, forKey: .number)
self.engine = try container.decodeIfPresent(VehicleEngine.self, forKey: .engine)
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 = RealmOptional(try container.decodeIfPresent(Bool.self, forKey: .isRightWheel))
self.isJapanese = RealmOptional(try container.decodeIfPresent(Bool.self, forKey: .isJapanese))
self.addedDate = (try container.decode(TimeInterval.self, forKey: .addedDate))/1000
self.addedBy = try container.decode(String.self, forKey: .addedBy)
self.debugInfo = try container.decodeIfPresent(DebugInfo.self, forKey: .debugInfo)
self.updatedDate = (try container.decode(TimeInterval.self, forKey: .updatedDate))/1000
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 osago = try container.decodeIfPresent([Osago].self, forKey: .osagoContracts) {
self.osagoContracts.append(objectsIn: osago)
}
if let ads = try container.decodeIfPresent([VehicleAd].self, forKey: .ads) {
self.ads.append(objectsIn: ads)
}
}
required init() {
super.init()
}
public init(_ number: String) {
self.number = number
self.addedDate = Date().timeIntervalSince1970
self.updatedDate = self.addedDate
}
public func getNumber() -> String {
return self.number
}
public override static func primaryKey() -> String? {
return "number"
}
public override class func ignoredProperties() -> [String] {
return ["id", "identifier", "differenceIdentifier", "formatter"]
}
public var unrecognized: Bool {
return self.brand == nil
}
public var outdated: Bool {
if let current = self.currentNumber {
return current != self.number
} else {
return false
}
}
// MARK: - Cloneable
required public init(copy: Vehicle) {
self.brand = copy.brand
self.model = copy.model
self.color = copy.color
self.year = copy.year
self.category = copy.category
self.engine = copy.engine
self.number = copy.number
self.currentNumber = copy.currentNumber
self.vin1 = copy.vin1
self.vin2 = copy.vin2
self.sts = copy.sts
self.pts = copy.pts
self.isRightWheel = copy.isRightWheel
self.isJapanese = copy.isJapanese
self.addedDate = copy.addedDate
self.addedBy = copy.addedBy
self.updatedDate = copy.updatedDate
let photos = List<VehiclePhoto>()
photos.append(objectsIn: copy.photos.map { $0.clone() })
self.photos = photos
let ownerships = List<VehicleOwnershipPeriod>()
ownerships.append(objectsIn: copy.ownershipPeriods.map { $0.clone() })
self.ownershipPeriods = ownerships
let events = List<VehicleEvent>()
events.append(objectsIn: copy.events.map { $0.clone() })
self.events = events
let osago = List<Osago>()
osago.append(objectsIn: copy.osagoContracts.map { $0.clone() })
self.osagoContracts = osago
let ads = List<VehicleAd>()
ads.append(objectsIn: copy.ads.map { $0.clone() })
self.ads = ads
}
// MARK: - Exportable
public static var csvHeader: String {
return "Model, Color, Year, Plate Number, VIN, STS, PTS, Added Date, Updated date"
}
public var csvLine: String {
let model = self.brand?.name?.original ?? "<unknown>"
let added = self.formatter.string(from: Date(timeIntervalSince1970: self.addedDate))
let updated = self.formatter.string(from: Date(timeIntervalSince1970: self.updatedDate))
return String(format: "\"%@\", %@, %d, %@, %@, %@, %@, \"%@\", \"%@\"", model, self.color ?? "", self.year, self.number, self.vin1 ?? "", self.sts ?? "", self.pts ?? "", added, updated)
}
}