You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
5.6 KiB
209 lines
5.6 KiB
//
|
|
// 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: "</td><td>")
|
|
return "<tr class=\"table-header\"><td>\(all)</td></tr>"
|
|
}
|
|
|
|
func html() -> String {
|
|
let all = self.cellValues().joined(separator: "</td><td>")
|
|
return "<tr><td>\(all)</td></tr>"
|
|
}
|
|
|
|
}
|
|
|
|
extension Array where Element : HTMLRepresentable {
|
|
|
|
func writeHTML(fileName: String, limit: Int? = 10) {
|
|
|
|
var html = "<figure class=\"wp-block-table alignwide\"><table>\n"
|
|
html.append("<thead>")
|
|
html.append(self.first?.htmlHeaders() ?? "")
|
|
html.append("</thead>\n<tbody>")
|
|
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</tbody></table></figure>")
|
|
|
|
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
|
|
}
|
|
|