All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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