#' @title Generate data from BD-Topo-dwelling for the so-ii communes
#' 
#' @description 
#' The function extracts the data from the the BD-Topo-dwelling
#' created by the R library [floodam.data](https://floodam.org/floodam.data/)
#' for the so-ii communes. Then it summarizes the data and creates the database
#' that serves as input for the analysis ["Typologie des bâtiments résidentiels
#' sur le territoire so-ii"](https://so-ii.org/analyse/analyse/logement-bd-topo-so-ii.html)
#' available in the [so-ii website](https://so-ii.org)
#'
#' @param dataset data from BD-Topo-dwelling. See details.
#' @param vintage edition (as date) of the BD-Topo® used in `dataset`.
#' @param path character, the name of the file to save the plot. Graphical
#'  device is chosen depending on extension.
#' @param retrieve logical, should the result be returned?. default to FALSE
#'
#' @return subject to the value of parameter `retrieve`:
#' - FALSE (default): the function does not return an object. It stores the
#' database (csv.gz file) and the metadata (yml file) in path.
#' - TRUE: the function returns a list with two slots, one for the data (as
#' data.frame) and one for the metadata (as character). It also stores the
#' database (csv.gz file) and the metadata (yml file) in path.
#' 
#' @details
#' A workflow integrating libraries [floodam.data](https://floodam.org/floodam.data/)
#' and [so-ii](https://floodam.org/so.ii/) is proposed in the
#' [so-ii website](https://so-ii.org/methode/tutoriel/donnees_bd_topo_so-ii.html)
#' We strongly recomend to visit the web page and follow the steps described 
#' there.
#' 
#' @export 
#'
#' @encoding UTF-8
#' 
#' @examples
#' 
#' \dontrun{
#' # To be added (soon)
#' }

generate_db_typology = function(
    dataset,
    vintage,
    path,
    retrieve = FALSE
) {
    # subset so-ii territory in processed data from department 34
    dataset = sf::st_drop_geometry(
        dataset[dataset[["commune"]] %in% so.ii::so_ii_collectivity[["commune"]], ]
    )
    dataset[["commune"]] = droplevels(dataset[["commune"]])

    # relabeling NA data in typology variable as NC (not classified)
    dataset[["typology"]][is.na(dataset[["typology"]])] = "NC"

    # aggregate data by so-ii's commune
    building = table(dataset[["commune"]], dataset[["typology"]], useNA = "ifany")
    building = data.frame(
        matrix(
            building, 
            nrow = dim(building)[1], 
            dimnames = dimnames(building)
        )
    )
    building[["commune"]] = rownames(building)

    building_eaip = table(
        dataset[["commune"]], 
        dataset[["typology"]], 
        dataset[["eaip"]], 
        useNA = "ifany"
    )
    building_eaip =  data.frame(
        array(
            building_eaip[, ,"TRUE"], 
            dim = dim(building_eaip)[1:2],
            dimnames = dimnames(building_eaip)[1:2]
        )
    )
    colnames(building_eaip) = sprintf("eaip_%s", colnames(building_eaip))
    building_eaip[["commune"]] = rownames(building_eaip)

    dwelling = stats::aggregate(
        dwelling ~ commune + typology, 
        dataset, 
        sum, 
        na.rm = TRUE, 
        drop = FALSE
    )
    dwelling = stats::reshape(
        dwelling, 
        direction = "wide", 
        timevar = "typology", 
        idvar = "commune",
        v.names = "dwelling", 
        sep = "_"
    )

    dwelling_eaip = stats::aggregate(
        dwelling ~ commune + typology + eaip, 
        dataset, 
        sum, 
        na.rm = TRUE, 
        drop = FALSE
    )
    dwelling_eaip = dwelling_eaip[dwelling_eaip[["eaip"]] == TRUE,]
    dwelling_eaip[["eaip"]] = NULL
    dwelling_eaip = stats::reshape(
        dwelling_eaip, 
        direction = "wide", 
        timevar = "typology", 
        idvar = "commune",
        v.names = "dwelling", 
        sep = "_eaip_"
    )

    # compose result database
    result = Reduce(
        function(x, y) merge(x, y, all.x = TRUE),
        list(building, building_eaip, dwelling, dwelling_eaip)
    )
    result[["commune"]] = as.character(result[["commune"]])

    # save database
    data_file_name = "bdtopo-dwelling-so-ii.csv.gz"
    data.table::fwrite(
        result,    
        file.path(path, data_file_name),
        yaml = TRUE,
    )

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    # generate and save metadata
    metadata_file_name = "metadata_bdtopo-dwelling-so-ii.yml"
    metadata = c(
        'data: typology of buildings of residential use',
        paste0("processed_with: floodam.data v", utils::installed.packages()["floodam.data","Version"]),
        paste0("vintage: BD-Topo\\uc2ae ", vintage),
        'data_curator: so.ii',
        'contact: so-ii@so-ii.org',
        paste0('citation: "Observatoire so-ii (', format(Sys.Date(), "%Y"),') : Analyse du parc immobilier \\uc3a0 destination r\\uc3a9sidentielle du territoire so-ii \\uc3a0 partir de la BD-Topo\\uc2ae, mill\\uc3a9sime ', vintage, '"'),
        'column_meaning:',
        '   commune: INSEE code',
        '   AB: number of buildings with more than 10 dwellings with common areas',
        '   MFH: number of buildings with less than 10 dwellings with common areas',
        '   NC: number of unclassified buildings',
        '   SFH: number of single-dwelling house with no common wall with adjacent houses',
        '   TH: number of single-dwelling house with one or more common walls with adjacent houses',
        '   eaip_AB: number of buildings of type AB in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   eaip_MFH: number of buildings of type MFH in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   eaip_NC: number of buildings of type NC in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   eaip_SFH: number of buildings of type SFH in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   eaip_TH: number of buildings of type TH in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   dwelling_AB: number of dwellings by building of type AB',
        '   dwelling_MFH: number of dwellings by building of type MFH',
        '   dwelling_NC: number of dwellings by building of type NC',
        '   dwelling_SFH: number of dwellings by building of type SFH',
        '   dwelling_TH: number of dwellings by building of type TH',
        '   dwelling_eaip_AB: number of dwellings in buildings of type AB in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   dwelling_eaip_MFH: number of dwellings in buildings of type MFH in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   dwelling_eaip_NC: number of dwellings in buildings of type NC in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   dwelling_eaip_SFH: number of dwellings in buildings of type SFH in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        '   dwelling_eaip_TH: number of dwellings in buildings of type TH in flooding area according to the \\"Enveloppe Approch\\uc3a9e des inondations Potentielles (Estimated Envelope of Potential Flooding)\\"',
        'column_units:',
        '   commune: no unit | character',
        '   AB: units (buildings) | integer',
        '   MFH: units (buildings) | integer',
        '   NC: units (buildings) | integer',
        '   SFH: units (buildings) | integer',
        '   TH: units (buildings) | integer',
        '   eaip_AB: units (buildings) | integer',
        '   eaip_MFH: units (buildings) | integer',
        '   eaip_NC: units (buildings) | integer',
        '   eaip_SFH: units (buildings) | integer',
        '   eaip_TH: units (buildings) | integer',
        '   dwelling_AB: units (dwellings) | integer',
        '   dwelling_MFH: units (dwellings) | integer',
        '   dwelling_NC: units (dwellings) | integer',
        '   dwelling_SFH: units (dwellings) | integer',
        '   dwelling_TH: units (dwellings) | integer',
        '   dwelling_eaip_AB: units (dwellings) | integer',
        '   dwelling_eaip_MFH: units (dwellings) | integer',
        '   dwelling_eaip_NC: units (dwellings) | integer',
        '   dwelling_eaip_SFH: units (dwellings) | integer',
        '   dwelling_eaip_TH: units (dwellings) | integer',
        paste0('R_info: "to load this data base in R as data.frame: data.table::fread(\\"path/to/file/bdtopo-dwelling-',vintage,'-soii.csv\\", data.table = FALSE, yaml = TRUE)"')
    )

    writeLines(metadata, file.path(path, metadata_file_name))

    # return objects if demanded  
    if(isTRUE(retrieve)) return(list(data = result, metadata = metadata))
}
