370 lines
13 KiB
Swift
370 lines
13 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>()
|
|
public var notes = List<VehicleNote>()
|
|
@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 notes
|
|
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)
|
|
}
|
|
|
|
if let notes = try container.decodeIfPresent([VehicleNote].self, forKey: .notes) {
|
|
self.notes.append(objectsIn: notes)
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
let notes = List<VehicleNote>()
|
|
notes.append(objectsIn: copy.notes.map { $0.clone() })
|
|
self.notes = notes
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|