import Foundation import Postbox public struct TelegramMediaPollOption: Equatable, PostboxCoding { public let text: String public let opaqueIdentifier: Data public init(text: String, opaqueIdentifier: Data) { self.text = text self.opaqueIdentifier = opaqueIdentifier } public init(decoder: PostboxDecoder) { self.text = decoder.decodeStringForKey("t", orElse: "") self.opaqueIdentifier = decoder.decodeDataForKey("i") ?? Data() } public func encode(_ encoder: PostboxEncoder) { encoder.encodeString(self.text, forKey: "t") encoder.encodeData(self.opaqueIdentifier, forKey: "i") } } public struct TelegramMediaPollOptionVoters: Equatable, PostboxCoding { public let selected: Bool public let opaqueIdentifier: Data public let count: Int32 public let isCorrect: Bool public init(selected: Bool, opaqueIdentifier: Data, count: Int32, isCorrect: Bool) { self.selected = selected self.opaqueIdentifier = opaqueIdentifier self.count = count self.isCorrect = isCorrect } public init(decoder: PostboxDecoder) { self.selected = decoder.decodeInt32ForKey("s", orElse: 0) != 0 self.opaqueIdentifier = decoder.decodeDataForKey("i") ?? Data() self.count = decoder.decodeInt32ForKey("c", orElse: 0) self.isCorrect = decoder.decodeInt32ForKey("cr", orElse: 0) != 0 } public func encode(_ encoder: PostboxEncoder) { encoder.encodeInt32(self.selected ? 1 : 0, forKey: "s") encoder.encodeData(self.opaqueIdentifier, forKey: "i") encoder.encodeInt32(self.count, forKey: "c") encoder.encodeInt32(self.isCorrect ? 1 : 0, forKey: "cr") } } public struct TelegramMediaPollResults: Equatable, PostboxCoding { public struct Solution: Equatable { public let text: String public let entities: [MessageTextEntity] public init(text: String, entities: [MessageTextEntity]) { self.text = text self.entities = entities } } public let voters: [TelegramMediaPollOptionVoters]? public let totalVoters: Int32? public let recentVoters: [PeerId] public let solution: TelegramMediaPollResults.Solution? public init(voters: [TelegramMediaPollOptionVoters]?, totalVoters: Int32?, recentVoters: [PeerId], solution: TelegramMediaPollResults.Solution?) { self.voters = voters self.totalVoters = totalVoters self.recentVoters = recentVoters self.solution = solution } public init(decoder: PostboxDecoder) { self.voters = decoder.decodeOptionalObjectArrayWithDecoderForKey("v") self.totalVoters = decoder.decodeOptionalInt32ForKey("t") self.recentVoters = decoder.decodeInt64ArrayForKey("rv").map(PeerId.init) if let text = decoder.decodeOptionalStringForKey("sol") { let entities: [MessageTextEntity] = decoder.decodeObjectArrayWithDecoderForKey("solent") self.solution = TelegramMediaPollResults.Solution(text: text, entities: entities) } else { self.solution = nil } } public func encode(_ encoder: PostboxEncoder) { if let voters = self.voters { encoder.encodeObjectArray(voters, forKey: "v") } else { encoder.encodeNil(forKey: "v") } if let totalVoters = self.totalVoters { encoder.encodeInt32(totalVoters, forKey: "t") } else { encoder.encodeNil(forKey: "t") } encoder.encodeInt64Array(self.recentVoters.map { $0.toInt64() }, forKey: "rv") if let solution = self.solution { encoder.encodeString(solution.text, forKey: "sol") encoder.encodeObjectArray(solution.entities, forKey: "solent") } else { encoder.encodeNil(forKey: "sol") } } } public enum TelegramMediaPollPublicity: Int32 { case anonymous case `public` } public enum TelegramMediaPollKind: Equatable, PostboxCoding { case poll(multipleAnswers: Bool) case quiz public init(decoder: PostboxDecoder) { switch decoder.decodeInt32ForKey("_v", orElse: 0) { case 0: self = .poll(multipleAnswers: decoder.decodeInt32ForKey("m", orElse: 0) != 0) case 1: self = .quiz default: assertionFailure() self = .poll(multipleAnswers: false) } } public func encode(_ encoder: PostboxEncoder) { switch self { case let .poll(multipleAnswers): encoder.encodeInt32(0, forKey: "_v") encoder.encodeInt32(multipleAnswers ? 1 : 0, forKey: "m") case .quiz: encoder.encodeInt32(1, forKey: "_v") } } } public final class TelegramMediaPoll: Media, Equatable { public var id: MediaId? { return self.pollId } public let pollId: MediaId public var peerIds: [PeerId] { return results.recentVoters } public let publicity: TelegramMediaPollPublicity public let kind: TelegramMediaPollKind public let text: String public let options: [TelegramMediaPollOption] public let correctAnswers: [Data]? public let results: TelegramMediaPollResults public let isClosed: Bool public let deadlineTimeout: Int32? public init(pollId: MediaId, publicity: TelegramMediaPollPublicity, kind: TelegramMediaPollKind, text: String, options: [TelegramMediaPollOption], correctAnswers: [Data]?, results: TelegramMediaPollResults, isClosed: Bool, deadlineTimeout: Int32?) { self.pollId = pollId self.publicity = publicity self.kind = kind self.text = text self.options = options self.correctAnswers = correctAnswers self.results = results self.isClosed = isClosed self.deadlineTimeout = deadlineTimeout } public init(decoder: PostboxDecoder) { if let idBytes = decoder.decodeBytesForKeyNoCopy("i") { self.pollId = MediaId(idBytes) } else { self.pollId = MediaId(namespace: Namespaces.Media.LocalPoll, id: 0) } self.publicity = TelegramMediaPollPublicity(rawValue: decoder.decodeInt32ForKey("pb", orElse: 0)) ?? TelegramMediaPollPublicity.anonymous self.kind = decoder.decodeObjectForKey("kn", decoder: { TelegramMediaPollKind(decoder: $0) }) as? TelegramMediaPollKind ?? TelegramMediaPollKind.poll(multipleAnswers: false) self.text = decoder.decodeStringForKey("t", orElse: "") self.options = decoder.decodeObjectArrayWithDecoderForKey("os") self.correctAnswers = decoder.decodeOptionalDataArrayForKey("ca") self.results = decoder.decodeObjectForKey("rs", decoder: { TelegramMediaPollResults(decoder: $0) }) as? TelegramMediaPollResults ?? TelegramMediaPollResults(voters: nil, totalVoters: nil, recentVoters: [], solution: nil) self.isClosed = decoder.decodeInt32ForKey("ic", orElse: 0) != 0 self.deadlineTimeout = decoder.decodeOptionalInt32ForKey("dt") } public func encode(_ encoder: PostboxEncoder) { let buffer = WriteBuffer() self.pollId.encodeToBuffer(buffer) encoder.encodeInt32(self.publicity.rawValue, forKey: "pb") encoder.encodeObject(self.kind, forKey: "kn") encoder.encodeBytes(buffer, forKey: "i") encoder.encodeString(self.text, forKey: "t") encoder.encodeObjectArray(self.options, forKey: "os") if let correctAnswers = self.correctAnswers { encoder.encodeDataArray(correctAnswers, forKey: "ca") } else { encoder.encodeNil(forKey: "ca") } encoder.encodeObject(results, forKey: "rs") encoder.encodeInt32(self.isClosed ? 1 : 0, forKey: "ic") if let deadlineTimeout = self.deadlineTimeout { encoder.encodeInt32(deadlineTimeout, forKey: "dt") } else { encoder.encodeNil(forKey: "dt") } } public func isEqual(to other: Media) -> Bool { guard let other = other as? TelegramMediaPoll else { return false } return self == other } public func isSemanticallyEqual(to other: Media) -> Bool { return self.isEqual(to: other) } public static func ==(lhs: TelegramMediaPoll, rhs: TelegramMediaPoll) -> Bool { if lhs.pollId != rhs.pollId { return false } if lhs.publicity != rhs.publicity { return false } if lhs.kind != rhs.kind { return false } if lhs.text != rhs.text { return false } if lhs.options != rhs.options { return false } if lhs.correctAnswers != rhs.correctAnswers { return false } if lhs.results != rhs.results { return false } if lhs.isClosed != rhs.isClosed { return false } if lhs.deadlineTimeout != rhs.deadlineTimeout { return false } return true } public func withUpdatedResults(_ results: TelegramMediaPollResults, min: Bool) -> TelegramMediaPoll { let updatedResults: TelegramMediaPollResults if min { if let currentVoters = self.results.voters, let updatedVoters = results.voters { var selectedOpaqueIdentifiers = Set() var correctOpaqueIdentifiers = Set() for voters in currentVoters { if voters.selected { selectedOpaqueIdentifiers.insert(voters.opaqueIdentifier) } if voters.isCorrect { correctOpaqueIdentifiers.insert(voters.opaqueIdentifier) } } updatedResults = TelegramMediaPollResults(voters: updatedVoters.map({ voters in return TelegramMediaPollOptionVoters(selected: selectedOpaqueIdentifiers.contains(voters.opaqueIdentifier), opaqueIdentifier: voters.opaqueIdentifier, count: voters.count, isCorrect: correctOpaqueIdentifiers.contains(voters.opaqueIdentifier)) }), totalVoters: results.totalVoters, recentVoters: results.recentVoters, solution: results.solution ?? self.results.solution) } else if let updatedVoters = results.voters { updatedResults = TelegramMediaPollResults(voters: updatedVoters, totalVoters: results.totalVoters, recentVoters: results.recentVoters, solution: results.solution ?? self.results.solution) } else { updatedResults = TelegramMediaPollResults(voters: self.results.voters, totalVoters: results.totalVoters, recentVoters: results.recentVoters, solution: results.solution ?? self.results.solution) } } else { updatedResults = results } return TelegramMediaPoll(pollId: self.pollId, publicity: self.publicity, kind: self.kind, text: self.text, options: self.options, correctAnswers: self.correctAnswers, results: updatedResults, isClosed: self.isClosed, deadlineTimeout: self.deadlineTimeout) } }