// // CSVUtils.swift // TournamentStats // // Created by Laurent Morvillier on 03/06/2019. // Copyright © 2019 Stax River. All rights reserved. // import Foundation import UIKit import Charts extension UIColor { static var paGreen: UIColor { return UIColor(red: 9/255, green: 203/255, blue: 157/255, alpha: 1) } static var paBlue: UIColor { return UIColor(red: 0/255, green: 188/255, blue: 198/255, alpha: 1) } static var paColor2: UIColor { return UIColor(red: 185/255, green: 151/255, blue: 199/255, alpha: 1) } static let paColor3: UIColor = UIColor(red: 235/255, green: 153/255, blue: 141/255, alpha: 1) } struct ColumnDescriptor { var header: String var number: Bool = false var widthWeight: CGFloat = 1.0 } protocol ColumnRepresentable { func columnDescriptors() -> [ColumnDescriptor] func cellValues() -> [String] func barChartDataEntry(index: Double) -> BarChartDataEntry var pieChartDataEntry: PieChartDataEntry { get } var name: String { get } } extension ColumnRepresentable { func barChartDataEntry(index: Double) -> BarChartDataEntry { return BarChartDataEntry(x: 0, y: 0) } var pieChartDataEntry: PieChartDataEntry { return PieChartDataEntry(value: 0.0) } var name: String { return "none" } } class IntFormatter : ValueFormatter { var numberFormatter: NumberFormatter = NumberFormatter() init() { self.numberFormatter.maximumFractionDigits = 0 } func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String { return self.numberFormatter.string(from: NSNumber(value: value)) ?? "" } } class PercentageFormatter : ValueFormatter { var numberFormatter: NumberFormatter = NumberFormatter() init() { self.numberFormatter.maximumFractionDigits = 0 } func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String { if let formatted = self.numberFormatter.string(from: NSNumber(value: value)) { return formatted + "%" } else { return "" } } } extension Array where Element : ColumnRepresentable { var pieChartData: PieChartData { var dataEntries: [ChartDataEntry] = [] self.forEach { representable in dataEntries.append(representable.pieChartDataEntry) } let dataSet = PieChartDataSet(entries: dataEntries, label: "") dataSet.entryLabelFont = Fonts.chartEntries dataSet.valueFont = Fonts.chartEntries dataSet.colors = [UIColor.paGreen, UIColor.paColor2, UIColor.paColor3, UIColor.paBlue] dataSet.valueFormatter = PercentageFormatter() return PieChartData(dataSet: dataSet) } var barChartData: BarChartData { var dataEntries: [BarChartDataEntry] = [] for (index, representable) in self.enumerated() { dataEntries.append(representable.barChartDataEntry(index: Double(index))) } let dataSet = BarChartDataSet(entries: dataEntries, label: "") dataSet.valueColors = [UIColor.white] dataSet.valueFont = Fonts.chartEntries dataSet.colors = [UIColor.paGreen, UIColor.paColor2, UIColor.paColor3, UIColor.paBlue] dataSet.valueFormatter = IntFormatter() return BarChartData(dataSet: dataSet) } var labels: [String] { return self.map { $0.name } } } protocol Aggregeable { static func aggregate(table: [Self], param: String) -> [Self] } protocol HTMLRepresentable : ColumnRepresentable { func htmlHeaders() -> String func html() -> String } extension HTMLRepresentable { func htmlHeaders() -> String { let all = self.columnDescriptors().map { $0.header }.joined(separator: "") return "\(all)" } func html() -> String { let all = self.cellValues().joined(separator: "") return "\(all)" } } extension Array where Element : HTMLRepresentable { func writeHTML(fileName: String, limit: Int? = 10) { var html = "
\n" html.append("") html.append(self.first?.htmlHeaders() ?? "") html.append("\n") let max = limit ?? Int.max for (index, rep) in self.enumerated() { html.append("\n") html.append(rep.html()) if index + 1 >= max { break } } html.append("\n
") do { try FileWriter.writeToDocumentDirectory(content: html, fileName: fileName) } catch { print(error) } } } extension Array where Element : CSVRepresentable { func writeCSV(file: String, limit: Int? = 10) { var string = Element.csvHeaders() let max = limit ?? Int.max for (index, rep) in self.enumerated() { string.append("/n") string.append(rep.csv()) if index >= max { break } } do { try FileWriter.writeToDocumentDirectory(content: string, fileName: file) } catch { print(error) } } } public protocol CSVRepresentable { static func csvHeaders() -> String func csv() -> String }