import Foundation public struct RDEPUBTextPositionConverter { public let book: RDEPUBTextBook public init(book: RDEPUBTextBook) { self.book = book } public var totalCharacterCount: Int { book.indexTable.totalCharacterCount } public func globalIndex(for anchor: RDEPUBTextAnchor) -> Int { book.indexTable.globalIndex(for: anchor) } public func globalRange(for rangeAnchor: RDEPUBTextRangeAnchor) -> NSRange { book.indexTable.globalRange(for: rangeAnchor) } public func fileIndex(forCharacterPosition index: Int) -> Int? { book.indexTable.fileIndex(forCharacterPosition: index) } public func localOffsetInFile(at fileIndex: Int, forGlobalPosition index: Int) -> Int? { book.indexTable.localOffsetInFile(at: fileIndex, forGlobalPosition: index) } public func anchor(forCharacterPosition index: Int) -> RDEPUBTextAnchor? { book.indexTable.anchor(forGlobalIndex: index) } public func anchor(for location: RDEPUBLocation) -> RDEPUBTextAnchor? { book.indexTable.anchor(for: location) } public func pageNumber(for anchor: RDEPUBTextAnchor) -> Int? { book.indexTable.pageNumber(for: anchor, in: book).map { $0 + 1 } } public func pageNumber(forCharacterPosition index: Int) -> Int? { guard let anchor = anchor(forCharacterPosition: index) else { return nil } return pageNumber(for: anchor) } public func location( for anchor: RDEPUBTextAnchor, bookIdentifier: String? ) -> RDEPUBLocation? { guard let chapter = book.chapters.first(where: { $0.spineIndex == anchor.fileIndex }) else { return nil } return book.indexTable.location(for: anchor, in: chapter, bookIdentifier: bookIdentifier) } public func location( for rangeAnchor: RDEPUBTextRangeAnchor, bookIdentifier: String? ) -> RDEPUBLocation? { guard let chapter = book.chapters.first(where: { $0.spineIndex == rangeAnchor.start.fileIndex }) else { return nil } return book.indexTable.location(for: rangeAnchor, in: chapter, bookIdentifier: bookIdentifier) } }