
com.innovenso.townplanner.io.concepts.PropertiesExcelIO.scala Maven / Gradle / Ivy
package com.innovenso.townplanner.io.concepts
import com.innovenso.townplanner.io.concepts.ExcelFields._
import com.innovenso.townplanner.model._
import com.innovenso.townplanner.model.concepts.properties.{
ArchitectureVerdict,
Criticality,
DataClassification,
Description,
HasProperties,
Property
}
import com.innovenso.townplanner.model.meta.{Key, SortKey}
import org.apache.poi.ss.usermodel.{Cell, Row, Sheet}
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import scala.util.Try
trait PropertiesExcelIO[
PropertyHolderType <: HasProperties,
PropertyType <: Property
] extends WorksheetIO {
def propertyClass: Class[PropertyType]
def propertyHolderClass: Class[PropertyHolderType]
def sheetName: String
def headerLabels: List[String]
private def allHeaderLabels: List[String] =
List(KEY) ::: headerLabels ::: List(SORT_KEY, CONCEPT_KEY)
def cellValues(property: PropertyType): List[String]
private def allCellValues(
property: PropertyType,
conceptKey: Key
): List[String] = List(property.key.value) ::: cellValues(property) ::: List(
property.sortKey.value.getOrElse(""),
conceptKey.value
)
def properties(holder: PropertyHolderType): List[PropertyType]
override def worksheet(
townPlan: TownPlan,
workbook: XSSFWorkbook
): Option[Sheet] = for {
sheet <- prepareSheet(workbook, sheetName)
header <- prepareHeader(
sheet,
allHeaderLabels
)
rows <- propertyRows(sheet, townPlan)
} yield sheet
def conceptProperties(holder: PropertyHolderType): List[(PropertyType, Key)] =
properties(holder).map(p => (p, holder.key))
def propertyRows(sheet: Sheet, townPlan: TownPlan): Option[List[Row]] = if (
townPlan.components(propertyHolderClass).isEmpty
) None
else
Some(
townPlan
.components(propertyHolderClass)
.flatMap(conceptProperties)
.zipWithIndex
.flatMap(tuple3 =>
row(sheet, tuple3._2 + 1, tuple3._1._2, tuple3._1._1)
)
)
private def row(
sheet: Sheet,
index: Int,
conceptKey: Key,
property: PropertyType
): Option[Row] =
Option(sheet.getRow(index))
.orElse(Some(sheet.createRow(index)))
.flatMap(r => cells(r, conceptKey, property))
private def cells(
row: Row,
conceptKey: Key,
property: PropertyType
): Option[Row] = {
allCellValues(property, conceptKey).zipWithIndex.foreach(value =>
cell(row, value._2, value._1)
)
Some(row)
}
private def inputWorksheet(workbook: XSSFWorkbook): Option[Sheet] =
Option(workbook.getSheet(sheetName))
override def read(
enterpriseArchitecture: EnterpriseArchitecture,
workbook: XSSFWorkbook
): Unit =
inputWorksheet(workbook)
.foreach(sheet => readProperties(Some(sheet), enterpriseArchitecture))
private def readProperties(
worksheet: Option[Sheet],
enterpriseArchitecture: EnterpriseArchitecture
): Unit =
listOfRows(worksheet).foreach(row =>
try {
readProperty(values(worksheet, Some(row)), enterpriseArchitecture)
} catch {
case e: Throwable =>
println(
s"Could not import worksheet ${worksheet
.map(_.getSheetName)
.getOrElse("-")}, row ${row.getRowNum}: ${e.getMessage}"
)
}
)
protected def readProperty(
props: PropertyProperties,
enterpriseArchitecture: EnterpriseArchitecture
): Unit
private def values(
worksheet: Option[Sheet],
row: Option[Row]
): PropertyProperties =
PropertyProperties(
allHeaderLabels
.map(hl => (hl, columnIndex(worksheet, hl)))
.map(tuple =>
(tuple._1, getCellValue(worksheet, row, tuple._2).getOrElse(""))
)
.toMap
)
}
case class PropertyProperties(cellValues: Map[String, String]) {
def apply(key: String): String = cellValues.getOrElse(key, "")
def key: Key = Key.fromString(apply(KEY))
def conceptKey: Key = Key.fromString(apply(CONCEPT_KEY))
def sortKey: SortKey = Option(apply(SORT_KEY)) match {
case Some(string) if !string.isBlank => SortKey(Some(string))
case _ => SortKey.next
}
def bool(key: String): Boolean = apply(key) match {
case "yes" | "true" | "1" | "Yes" | "YES" | "True" | "TRUE" => true
case _ => false
}
def option(key: String): Option[String] = Option(apply(key)) match {
case Some(string) if !string.isBlank => Some(string)
case _ => None
}
def title: String = apply(TITLE)
def name: String = apply(NAME)
def descriptions: List[Description] =
apply(DESCRIPTION).split("\n\n").map(Description).toList
def descriptionOption: Option[String] =
descriptions.headOption.map(_.value)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy