

### Some text for the introduction
TEXT_intro <- "Write intro text here + link template"

Bdy_clean_names <- function(any_words){
  any_words %>%
    #iconv(., to="ASCII//TRANSLIT") %>%
    tolower %>%
    stringr::str_replace_all(., " ", "_")  %>%
    stringr::str_replace_all(., "'", "_") %>%
    stringr::str_replace_all(., "-", "_") %>%
    stringr::str_replace_all(., ":", "") %>%
    stringr::str_replace_all(., "/", "") %>%
    stringr::str_replace_all(., "«", "") %>%
    stringr::str_replace_all(., "»", "") %>%
    stringr::str_replace_all(., "\\.", "_") %>%
    stringr::str_replace_all(., "___", "_") %>%
    stringr::str_replace_all(., "__", "_")
}

### Log function (print message and timestamp in the console)
Bdy_log<-function(MSG){cat(paste0(MSG, " - ", as.character(Sys.time()), "\n"))}


### Load shapefile
Bdy_UploadShapefile <- function(shp_path){

  # Save files in StoredShapefiles folder
  for(i in 1:nrow(shp_path)){file.rename(shp_path$datapath[i], shp_path$name[i])}

  # Check we have all needed files, and a single shapefile, return error otherwise
  Extensions <- tools::file_ext(shp_path$name)

  if(length(unique(substr(shp_path$name, 1, nchar(shp_path$name)-4)))>1){
    MSG <- "<b>Le shapefile n'est pas valide: </b><br> Le nom des différents fichiers chargés ne correspond pas (le nom des 4 fichiers doit être identique avec seulement l'extension qui varie entre .prj, .dbf, .shp, .shx"
  }

  if(length(which(Extensions == "shp"))>1){
    MSG <- "<b>Le shapefile n'est pas valide: </b><br> Merci de ne charger qu'un shapefile à la fois (en incluant les fichiers .prj, .dbf, .shx et .shp)"
  }

  if((! "dbf" %in% Extensions) | (! "shp" %in% Extensions) | (! "shx" %in% Extensions) | (! "shx" %in% Extensions)){
    MSG <- "<b>Le shapefile n'est pas valide: </b><br> Merci de vérifier que vous avez chargé les fichiers .prj, .dbf, .shx et .shp de votre shapefile"
  }

  if(exists("MSG")){
    return(HTML(paste0("<p style='color:red'>", MSG, "</p>")))
  }

  # Read shapefile
  ShapeName <- paste0(shp_path$name[substr(shp_path$name, (nchar(shp_path$name)-3), nchar(shp_path$name))==".shp"])
  Shape <- st_read(ShapeName)

  # Check st_crs is available
  if(grepl("Undefined", st_crs(Shape)$input) | is.na(st_crs(Shape)) | st_crs(Shape)==""){
    return(HTML(paste0("<p style='color:red'>Le shapefile chargé n'a pas de CRS (Coordinate Reference System) et ne peut donc pas etre lu.</p>")))
  }

  # Transform shapefile (CRS and geometry type) + set leaflet_id
  Shape <- Shape %>% st_transform(., "+init=epsg:4326")
  Shape <- rbind(Shape[st_geometry_type(Shape) != "MULTIPOLYGON",], st_cast(Shape[st_geometry_type(Shape) == "MULTIPOLYGON",], "POLYGON"))
  Shape <- rbind(Shape[st_geometry_type(Shape) != "MULTIPOINT",], st_cast(Shape[st_geometry_type(Shape) == "MULTIPOINT",], "POINT"))
  Shape$leaflet_id <- paste0("Uploaded_", sample(1:10000,1), "_row_", 1:nrow(Shape))

  # Remove local files
  unlink(shp_path$name)

  # Return
  return(Shape)
}



### Create empty map
Bdy_CreateMap <- function(EXT=c(-6, 42, 8.6, 51.5)){
  Leaf <- leaflet() %>%
    addProviderTiles("Esri.OceanBasemap", options = list(minZoom=5, maxZoom=9)) %>%
    fitBounds(EXT[1], EXT[2], EXT[3], EXT[4]) %>%
    setMaxBounds(lng1 = -7, lat1 = 40, lng2 = 10, lat2 = 54) %>%
    addLayersControl(baseGroups=c("OpenStreetMap"), position="bottomleft") %>%
    addScaleBar(position="bottomright") %>%
    addMouseCoordinates() %>%
    addPmToolbar(
      targetGroup = "Parc",
      toolbarOptions = pmToolbarOptions(drawMarker=TRUE, drawPolyline = FALSE, drawPolygon = FALSE, drawRectangle = F, drawCircle = F, cutPolygon=F, editMode=F, removalMode=F),
      editOptions=pmEditOptions(preventVertexEdit=F)) %>%
    htmlwidgets::onRender("function(el, x){
            document.querySelector('.leaflet-pm-edit').remove();
                          document.querySelector('.leaflet-draw-draw-marker') .setAttribute('title', 'Ajouter un parc');
                          document.querySelector('.leaflet-draw-edit-remove') .setAttribute('title', 'Supprimer un parc');
                          }")

  EDITS <- callModule(
    editMod,
    leafmap = Leaf,
    id = "map",
    record = FALSE,
    editor="leafpm",
    sf = TRUE
  )

  return(EDITS)
}




### Add popup to spatial parcs
Bdy_MapPopup <- function(parcs){

  textIn <- function(parcs) { # From this post: https://stackoverflow.com/questions/79791011/what-is-the-equivalent-of-onclick-for-textinput-in-r-shiny-leaflet-popup
    textInput(
      paste0("EditName_", parcs$leaflet_id),
      label = "",
      value = parcs$NAME
    ) %>% sub(
      'type="text"',
      'type="text" onchange="Shiny.onInputChange(\'text_onchange\', {id: this.id, value: this.value})"',
      .)
  }

  parcs$Popup <- NA
  for(i in 1:nrow(parcs)){
    parcs$Popup[i] <- as.character(paste0(
      "<b>Nom du parc:</b>",
      textIn(parcs[i,]),
      as.character(actionButton(paste0("Delete_", parcs$leaflet_id[i]), label="", icon=icon("trash"), onclick="Shiny.onInputChange( \"button_RmPolygon\" , this.id)"))
    ))
  }

  return(parcs$Popup)
}



### Make pretty result tables interactive with DT
Bdy_InteractiveResultTable <- function(Pretty_table, type){

  # Add button to get more results
  if(type=="national"){
    shinyInput <- function(SPs) {
      inputs <- character(length(SPs))
      for (i in 1:length(SPs)) {
        inputs[i] <- as.character(actionButton(paste0("button_", gsub(" ", "_", SPs[i])), label = "+", onclick = 'Shiny.onInputChange(\"select_button\",  this.id, {priority: "event"})')) # Priority is needed to enable clicking the same button twice in a row
      }
      inputs
    }

    Pretty_table$Details <- shinyInput(Pretty_table$Espece)
  }

  # Prepare tooltips. Warning: don't put apostrophe in tooltips, use this character instead ’
  Tab_tooltips <- revalue(names(Pretty_table), c(
    "Espece"="Nom francais de l’espece concernee",
    "Groupe_colonies"="Groupe de colonies (voir la carte détaillée pour leur position)",
    "Parc_proche"="Parc le plus proche du groupe de colonies et distance au parc (euclidienne ou par la mer selon les espèces)",
    "Population_initiale"="Population estimee en 2021 (mediane et IC95%)",
    "Nombre_collisions"="Nombre de collisions annuelles estimées",
    "Impact_Relatif"="Impact estimé des parcs éoliens sur la population à 30 ans (%)",
    "Augmentation_Extinction"="Augmentation de la probabilité d'extinction de la population due aux parcs éoliens (%)",
    "MAX_Impact_relatif"="Impact relatif estimé des parcs éoliens sur le groupe de colonies le plus impacté (%)",
    "MAX_Augmentation_extinction"="Augmentation de la probabilité d'extinction du groupe de colonies le plus impacté (%)",
    "Details"="Cliquez pour avoir les résultats détaillés par groupe de colonies d’une espèce"
  ), warn_missing = F) %>% gsub("'", "’", .)

  # Format in DT
  if(type=="national"){
    DT_table <- DT::datatable(Pretty_table,
                              escape = FALSE,
                              filter="none",
                              selection = 'none',
                              options = list(pageLength = 50,
                                             dom="t"),
                              rownames=FALSE,
                              callback = DT::JS(paste0("var tips = ['", paste0(Tab_tooltips, collapse = "','"),"'], header = table.columns().header(); for (var i = 0; i < tips.length; i++) {$(header[i]).attr('title', tips[i]);}"))
    )
  } else {
    DT_table <- DT::datatable(Pretty_table,
                              escape = FALSE,
                              filter="none",
                              selection = 'none',
                              options = list(pageLength = 10,
                                             dom = 'tp' # dom='tp' is to remove the search bar but keep table and pagination
                              ),
                              rownames=FALSE,
                              callback = DT::JS(paste0("var tips = ['", paste0(Tab_tooltips, collapse = "','"),"'], header = table.columns().header(); for (var i = 0; i < tips.length; i++) {$(header[i]).attr('title', tips[i]);}"))
    )
  }

  # Return
  return(DT_table)

}



### Prepare summary results map
Bdy_SummaryMap <- function(mod_out, Raw_ResTables, parcs, BufferForaging){

  ### Create empty map
  Leaf <- leaflet() %>%
    addProviderTiles("Esri.OceanBasemap", options = list(maxZoom=9)) %>%
    fitBounds(-6, 42, 8.6, 51.5) %>%
    addLayersControl(baseGroups=c("OpenStreetMap"), position="bottomleft") %>%
    addScaleBar(position="bottomright") %>%
    addMouseCoordinates()

  ### Add colonies
  for(SP in 1:length(mod_out)){

    # Get if colony in range of a parc
    Dist <- mod_out[[SP]]$distanceBIN %>% data.frame()
    Dist$Parcs_foraging <- apply(Dist, 1, function(x) paste0(names(data.frame(mod_out[[SP]]$distance))[x == T], collapse = ";"))

    # Distance to parcs
    Dist_qtt <- mod_out[[SP]]$distance %>%
      data.frame() %>%
      mutate(
        Dist_min = apply(., 1, min, na.rm=T),
        Parc_min = names(.)[apply(., 1, which.min)]
      )

    # Load colonies
    Colonies_SP <- mod_out[[SP]]$colonies %>%
      st_transform(., st_crs(4326)) %>%
      mutate(Lon=st_coordinates(.)[,1], Lat=st_coordinates(.)[,2]) %>%
      mutate(Species=names(mod_out)[SP])
    Colonies_SP$Popup <- paste0(Colonies_SP$Colonie, ifelse(Colonies_SP$sous_unite=="", "", " - "), Colonies_SP$sous_unite)
    Colonies_SP$Parcs_foraging <- Dist$Parcs_foraging[match(Colonies_SP$code_colonie, rownames(Dist))]
    Colonies_SP$Dist_min <- Dist_qtt$Dist_min[match(Colonies_SP$code_colonie, rownames(Dist_qtt))]
    Colonies_SP$Parc_min <- Dist_qtt$Parc_min[match(Colonies_SP$code_colonie, rownames(Dist_qtt))]

    GrColo_SP_MCP <- Colonies_SP %>%
      st_buffer(., 1) %>%
      group_by(group) %>%
      summarise(geometry=st_union(geometry),
                colonies=paste0(unique(Popup), collapse=", "),
                Dist_min=min(Dist_min, na.rm=T),
                Parc_min=Parc_min[which.min(Dist_min)],
                Parcs_foraging=Parcs_foraging %>% strsplit(., ";") %>% unlist(.) %>% unique(.) %>% sort(.) %>% paste0(., collapse=", ") %>% ifelse(.=="", "aucun", .)
                ) %>%
      st_make_valid() %>%
      st_convex_hull()
    GrColo_SP <- st_centroid(GrColo_SP_MCP)

    # Add Relative Impact and PopInit
    Raw_ResSP <- subset(Raw_ResTables$Tableau_Subpop, Species==names(mod_out)[SP])
    GrColo_SP$RelImpact <- Raw_ResSP$RelImpact_med[match(GrColo_SP$group, Raw_ResSP$GrColo)]
    GrColo_SP$PopInit <- Raw_ResSP$Pop_Init_med[match(GrColo_SP$group, Raw_ResSP$GrColo)]


    # Add popup
    Res_match <- Raw_ResSP[match(GrColo_SP$group, Raw_ResSP$GrColo),]
    GrColo_SP$Popup <- paste0(
      "<h2>", names(mod_out)[SP], "</h2>",
      "<b>Groupe de colonies n°", GrColo_SP$group, "</b><br>",
      "<b>Colonies : </b>", GrColo_SP$colonies, "<br>",
      "<b>Parc le plus proche : </b>", GrColo_SP$Parc_min, " (", GrColo_SP$Dist_min, "km)<br>",
      "<b>Parcs dans zone d'alimentation: </b>", GrColo_SP$Parcs_foraging, "<br><br>",

      "<p style='color:FireBrick'><b>Impact relatif sur les tendances : </b>", round(Res_match$RelImpact_med,2), "% [", round(Res_match$RelImpact_2.5,2), " ; ", round(Res_match$RelImpact_97.5,2), "]<br>",
      "<b>Augmentation de la probabilité d'extinction : </b>", round(Res_match$Ext_Relative,2), "%</p>",

      "<b>Population en 2021 : </b>", Res_match$Pop_Init_med, " [", Res_match$Pop_Init_2.5, " ; ", Res_match$Pop_Init_97.5, "]<br>",
      "<b>Nombre de collisions : </b>", round(Res_match$Mortality_med,2), " [", round(Res_match$Mortality_2.5,2), " ; ", round(Res_match$Mortality_97.5,2), "]<br>", # Verifier que ca correspond bien a "Mortality"

      "<b>Tendance sans parc : </b>", 100*round(Res_match$Trend_no_med,3), "% [", 100*round(Res_match$Trend_no_2.5,3), " ; ", 100*round(Res_match$Trend_no_97.5,3), "]<br>",
      "<b>Tendance avec parc : </b>", 100*round(Res_match$Trend_impact_med,3), "% [", 100*round(Res_match$Trend_impact_2.5,3), " ; ", 100*round(Res_match$Trend_impact_97.5,3), "]<br>",

      "<b>Probabilité d'extinction sans parc : </b>", 100*round(Res_match$Ext_Noimpact,3), "%<br>",
      "<b>Probabilité d'extinction avec parc : </b>", 100*round(Res_match$Ext_Withimpact,3), "%<br>",
      "<i>Les tendances estimées pour certaines espèces sont sujettes à caution, cela n'empêche pas les impacts relatifs d'être robustes"
    )

    # Prepare Buffer
    Buff_toplot <- BufferForaging[BufferForaging$Espece==names(mod_out)[SP],] %>% st_transform(., st_crs(GrColo_SP_MCP))

    # Prepare color and size
    ColPal <- colorNumeric("Reds", domain=c(0,100))
    GrColo_SP$LeafSize <- 20 * log10(GrColo_SP$PopInit) / max(log10(GrColo_SP$PopInit), na.rm=T)

    # Add colonies to leaflet map
    Leaf <- Leaf %>%
      addPolygons(data=Buff_toplot, fill=F, fillOpacity=0, stroke=T, weight=2, dashArray="5, 5", color="#8c2d04", group=names(mod_out)[SP]) %>%
      #addPolygons(data=GrColo_SP_MCP, fillOpacity=0.7, fillColor="#f1b6da", stroke=F, group=names(mod_out)[SP]) %>%
      #addCircleMarkers(lng=Colonies_SP$Lon, lat=Colonies_SP$Lat, color = "#8e0152", fillOpacity=0.7, label = paste0("Colonie : ", Colonies_SP$Popup), group=names(mod_out)[SP], radius=6) %>%
      addCircleMarkers(data=GrColo_SP, radius=GrColo_SP$LeafSize, color=ifelse(GrColo_SP$Parcs_foraging=="aucun", "#7fbc41", "#8e0152"), fill=T, fillColor = ColPal(GrColo_SP$RelImpact), label=paste0("Cliquez pour les résultats du groupe de colonies n°", GrColo_SP$group), fillOpacity=1, popup = GrColo_SP$Popup, group=names(mod_out)[SP])
  }

  ### Add control layer per species
  Leaf <- Leaf %>%
    hideGroup(., group=names(mod_out)) %>%
    addPolygons(data=st_buffer(parcs, 1000), fill="black", col="black", fillOpacity=1, label=paste0("Parc éolien : ", parcs$NAME)) %>%
    addLayersControl(baseGroups = c("", names(mod_out)), position="bottomleft", options = layersControlOptions(collapsed = F))%>%
    addLegend(pal=ColPal, values=c(0,100), title="Impact relatif (%)") %>%
    addLegend(colors=HTML("black; width:20px; height:20px; border:3px solid black; border-radius:0%"), opacity=1, labels="Parc éolien") %>%
    addLegend(colors=HTML("#white; width:20px; height:20px; border:3px dashed #8c2d04; border-radius:0%"), labels="Zone d'alimentation") %>%
    addLegend(colors=c(HTML("white; border:5px solid #d01c8b; border-radius:50%"), HTML("white; border:5px solid #b8e186; border-radius:50%")), labels=c("Groupe impacté", "Groupe non impacté"))

  return(Leaf)
}




### Prepare outputs
Bdy_PrepareOutputs <- function(FOLDER_name,mortality,parcs, Version_app, Res_list, Bdy_Interpretation){

  ### Clean outputs with same name (unlikely but just in case)
  unlink(paste0("Outputs/", FOLDER_name, ".zip"), recursive = T)
  unlink(paste0("Outputs/", FOLDER_name), recursive = T)
  dir.create(paste0("Outputs/", FOLDER_name), recursive = T)

  ### Remove old ZIP files (> 3 days)
  tryCatch({
    toremove <- list.files("Outputs") %>% subset(., !grepl(gsub("-", ".", as.character(Sys.Date())), .)) %>% subset(., !grepl(gsub("-", ".", as.character(Sys.Date()-1)), .)) %>% subset(., !grepl(gsub("-", ".", as.character(Sys.Date()-2)), .))
    if(length(toremove>0)){unlink(paste0("Outputs/", toremove), recursive=T)}
  }, error=function(e){"Erreur en supprimant les vieux ZIP"})

  ### Save results
  write.csv(Res_list$Raw_ResTables$Tableau_Subpop, paste0("Outputs/", FOLDER_name, "/Resultats_bruts_", FOLDER_name, ".csv"), row.names=F)
  parcs$Popup <- parcs$CoverLimit_France <- parcs$CoverLimit_Europe <- parcs$Color <- NULL

  if(length(unique(st_geometry_type(parcs)))>1){
    parcs <- rbind(
      parcs[st_geometry_type(parcs) != "POINT", ],
      st_buffer(parcs[st_geometry_type(parcs) == "POINT", ], 1000) # Buffer points by 1000m as shapefiles cannot include POINT and POLYGON simultaneously
    )
  }

  st_write(parcs, paste0("Outputs/", FOLDER_name, "/Parcs_ShapeFile_", FOLDER_name,".shp"), append=F)
  write.csv(mortality,paste0("Outputs/", FOLDER_name, "/Tableau_de_mortalite_", FOLDER_name, ".csv"),row.names=F,quote=F)
  
  ### Save report
  print("Start RMD")
  tryCatch({
    render("Bird_Dynamic_CreateMarkDownReport.rmd",
           output_format="html_document",
           output_file=paste0("Rapport_", FOLDER_name,".html"),
           output_dir=paste0("Outputs/", FOLDER_name)
    )}, error=function(e){cat("TryCatch: RMarkDown failed")})

  ### Save tracker
  tryCatch({
    Parcs_coord <- parcs %>% st_centroid(.) %>% st_transform(., st_crs(4326)) %>% st_coordinates(.) %>% as.data.frame() %>% mutate(Coords=paste(round(.$X,2), round(.$Y,2), sep=","))
    ToSave <- data.frame(Date=Sys.time(),
                         Parcs=paste0(unique(parcs$NAME), collapse=" + "),
                         Parcs_coords=paste0(Parcs_coord$Coords, collapse=";"),
                         Especes=paste0(unique(Res_list$Raw_ResTables$Tableau_Subpop$Species), collapse = " + "))
    write.csv(x=ToSave, file=paste0("Tracker_files/tracker_", FOLDER_name, ".csv"), row.names=F)
    # drive_upload(paste0("www/tracker_", FOLDER_name, ".csv"), paste0("Birdynamic_Stockage_utilisation/", FOLDER_name, ".csv"))
    # unlink(paste0("www/tracker_", FOLDER_name, ".csv"))
  }, error=function(e){cat("TryCatch: Tracker failed")})

  ### Create ZIP
  zip(zipfile = paste0("Outputs/", FOLDER_name, ".zip"), files = paste0("Outputs/", FOLDER_name), extras = '-j')
  unlink(paste0("Outputs/", FOLDER_name), recursive=T)

}



### Texte interpretation des graphiques
Bdy_Interpretation <- data.frame(
  Tableau_national = "Le tableau présenté dans l'onglet 'Tableau national' est le résultat principal de l'analyse, estimant l'impact à l'échelle nationale des parcs éoliens étudiés. Il présente notamment l'impact relatif des parcs sur les tendances de population (un impact relatif de 10 % signifie que la population nationale dans 30 ans sera 10% moins importante avec les parcs éoliens, par rapport à un scénario sans les parcs éoliens) et l’augmentation de la probabilité d'extinction de la population nationale (une augmentation de la probabilité d'extinction de 10% signifie que la population a 10% de plus de chance de s'éteindre d'ici 30 ans). Dans certains cas, un impact relatif important n’est pas associé à une augmentation de la probabilité d’extinction ; cela signifie que bien que les populations diminuent, les effectifs restent positifs dans toutes les simulations à l’horizon de 30 ans et que c’est à plus long terme que la probabilité d’extinction a augmenté. Ces deux résultats sont également déclinés par colonie, en cliquant sur le bouton ‘+’ dans la colonne ‘Détails’.",
  Tendances_temporelles = "Le graphique présenté dans l'onglet 'Tendances temporelles' montre l'impact relatif des parcs sur l'évolution de la population dans les 30 prochaines années. La tendance sans parc (en vert) est fixée à 100% tandis que la tendance avec parc (en rose) est relative à la population sans parc. La différence entre les deux correspond donc à l'impact relatif tel qu'il est défini dans le tableau national. Si vous placez votre souris sur la courbe rose, l'impact relatif et l'augmentation de la probabilité d'extinction à l'échelle nationale apparaissent.",
  Carte_detaillee = "La carte présentée dans l'onglet 'Carte détaillée' présente le détail par espèce de l'impact sur chaque groupe de colonies. Un groupe de colonie est représenté par un gros rond, dont la taille dépend du nombre d'individus, la couleur extérieure est rose si au moins un parc éolien est dans la zone d'alimentation de l'espèce et vert sinon, et la couleur intérieure dépend de l'impact relatif des parcs sur ce groupe de colonies. Le détail des colonies est visible sous ces gros ronds si vous zoomez suffisamment (les colonies composant le groupe apparaissent, reliées par un polygone rose). En cliquant sur un groupe de colonies, vous obtenez tous les détails de l'impact mesuré sur ce groupe. Les lignes pointillées marron sur la carte interactive montrent la zone que l'espèce peut atteindre en recherche alimentaire depuis sa colonie; les parcs situés hors de cette zone ont un impact nul."
)



