# \\\
# Copyright 2021-2022 Louis Héraut*1
#
# *1   INRAE, France
#      louis.heraut@inrae.fr
#
# This file is part of ash R toolbox.
#
# ash R toolbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# ash R toolbox is distributed in the hope that it will be useful, but 
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ash R toolbox.  If not, see <https://www.gnu.org/licenses/>.
# ///
#
#
# plotting/layout.R
#
# Regroups general parameters about plotting like the theme used ang
# color management. It mainly deals with the calling to specific
# plotting functions and the organisation of each plot for the
# generation of the PDF.


# Usefull library
library(ggplot2)
library(scales)
library(qpdf)
library(gridExtra)
library(gridtext)
library(dplyr)
library(grid)
library(ggh4x)
library(RColorBrewer)
library(rgdal)
library(shadowtext)
library(png)


# Sourcing R file
source('plotting/datasheet.R', encoding='UTF-8')
source('plotting/map.R', encoding='UTF-8')
source('plotting/matrix.R', encoding='UTF-8')
source('plotting/break.R', encoding='UTF-8')
source('plotting/tools.R', encoding='UTF-8')


## 1. PERSONALISATION ________________________________________________
### 1.1. Personal theme ______________________________________________
theme_ash =
    theme(
        # White background
        panel.background=element_rect(fill='white'),
        # Font
        text=element_text(family='sans'),
        # Border of plot
        panel.border = element_rect(color="grey85",
                                    fill=NA,
                                    size=0.7),
        # Grid
        panel.grid.major.x=element_blank(),
        panel.grid.major.y=element_blank(),
        # Ticks marker
        axis.ticks.x=element_line(color='grey75', size=0.3),
        axis.ticks.y=element_line(color='grey75', size=0.3),
        # Ticks label
        axis.text.x=element_text(color='grey40'),
        axis.text.y=element_text(color='grey40'),
        # Ticks length
        axis.ticks.length=unit(1.5, 'mm'),
        # Ticks minor
        ggh4x.axis.ticks.length.minor=rel(0.5),
        # Title
        plot.title=element_blank(),
        # Axis title
        axis.title.x=element_blank(),
        axis.title.y=element_text(size=9, vjust=1.2, 
                                  hjust=0.5, color='grey20'),
        # Axis line
        axis.line.x=element_blank(),
        axis.line.y=element_blank(),
        )

### 1.2. Color palette _______________________________________________
palette_perso = c('#0f3b57', # cold
                  '#1d7881',
                  '#80c4a9',
                  '#e2dac6', # mid
                  '#fadfad',
                  '#d08363',
                  '#7e392f') # hot


## 2. USEFUL GENERICAL PLOT __________________________________________
### 2.1. Void plot ___________________________________________________
# A plot completly blank
void = ggplot() + geom_blank(aes(1,1)) +
    theme(
        plot.background = element_blank(), 
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        panel.border = element_blank(),
        panel.background = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.x = element_blank(), 
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_blank()
    )

### 2.2. Contour void plot ___________________________________________
# A plot completly blank with a contour
contour = void +
    theme(plot.background=element_rect(fill=NA, color="#EC4899"),
          plot.margin=margin(t=0, r=0, b=0, l=0, unit="mm"))


## 3. LAYOUT _________________________________________________________
# Generates a PDF that gather datasheets, map and summarize matrix about the trend analyses realised on selected stations
layout_panel = function (df_data, df_meta, layout_matrix,
                         what_plot=c('datasheet', 'matrix', 'map'),
                         figdir='', filedir_opt='', filename_opt='',
                         variable='', df_trend=NULL,
                         alpha=0.1, unit2day=365.25, var='',
                         type='', glose=NULL, trend_period=NULL,
                         mean_period=NULL, colorForce=FALSE,
                         axis_xlim=NULL,
                         missRect=TRUE, time_header=NULL,
                         info_header=NULL, foot_note=TRUE,
                         info_height=2.8, time_ratio=2,
                         var_ratio=3, foot_height=1.25,
                         df_shapefile=NULL,
                         resources_path=NULL,
                         logo_dir=NULL,
                         AEAGlogo_file=NULL,
                         INRAElogo_file=NULL,
                         FRlogo_file=NULL) {

    # Name of the document
    outfile = "Panels"
    # If there is an option to mention in the filename it adds it
    if (filename_opt != '') {
        outfile = paste(outfile, '_', filename_opt, sep='')
    }
    # Add the 'pdf' extensionto the name
    outfile = paste(outfile, '.pdf', sep='')

    # If there is not a dedicated figure directory it creats one
    outdir = file.path(figdir, filedir_opt, sep='')
    if (!(file.exists(outdir))) {
        dir.create(outdir)
    }

    # Names of a temporary directory to store all the independent pages
    outdirTmp = file.path(outdir, 'tmp')
    # Creates it if it does not exist
    if (!(file.exists(outdirTmp))) {
        dir.create(outdirTmp)
    # If it already exists it deletes the pre-existent directory
    # and recreates one
    } else {
        unlink(outdirTmp, recursive=TRUE)
        dir.create(outdirTmp)
    }

    # Number of type/variable
    nbp = length(df_data)

    # Convert data tibble to list of tibble if it is not the case
    if (all(class(df_data) != 'list')) {
        df_data = list(df_data)
    }

    if (all(class(df_trend) != 'list')) {
        df_trend = list(df_trend)
        if (length(df_trend) == 1) {

            df_trend = replicate(nbp, df_trend)
        }}

    if (all(class(alpha) != 'list')) {
        alpha = list(alpha)
        # If there is only one value
        if (length(alpha) == 1) {
            # Replicates the value the number of times that there
            # is of studied variables
            alpha = replicate(nbp, alpha)
        }}

    # Same
    if (all(class(unit2day) != 'list')) {
        unit2day = list(unit2day)
        if (length(unit2day) == 1) {
            unit2day = replicate(nbp, unit2day)
        }}

    if (all(class(var) != 'list')) {
        var = list(var)
        if (length(var) == 1) {
            var = replicate(nbp, var)
        }}

    if (all(class(glose) != 'list')) {
        glose = list(glose)
        if (length(glose) == 1) {
            glose = replicate(nbp, glose)
        }}
    
    if (all(class(type) != 'list')) {
        type = list(type)
        if (length(type) == 1) {
            type = replicate(nbp, type)
        }}

    if (all(class(missRect) != 'list')) {
        missRect = list(missRect)
        if (length(missRect) == 1) {
            missRect = replicate(nbp, missRect)
        }}

    # Creates a blank list to store all the data of each type of plot
    list_df2plot = vector(mode='list', length=nbp)

    # For all the type of graph / number of studied variables
    for (i in 1:nbp) {
        # Creates a list that gather all the info for one type of graph
        df2plot = list(data=df_data[[i]], 
                       trend=df_trend[[i]],
                       alpha=alpha[[i]],
                       unit2day=unit2day[[i]],
                       var=var[[i]], type=type[[i]],
                       glose=glose[[i]],
                       missRect=missRect[[i]])
        # Stores it
        list_df2plot[[i]] = df2plot
    }

    df_page = tibble(section='Sommaire', subsection=NA, n=1)
    
    # If map needs to be plot
    if ('map' %in% what_plot) {
        df_page = map_panel(list_df2plot, 
                            df_meta,
                            idPer_trend=length(trend_period),
                            trend_period=trend_period,
                            mean_period=mean_period,
                            colorForce=colorForce,
                            df_shapefile=df_shapefile,
                            foot_note=foot_note,
                            foot_height=foot_height,
                            resources_path=resources_path,
                            logo_dir=logo_dir,
                            AEAGlogo_file=AEAGlogo_file,
                            INRAElogo_file=INRAElogo_file,
                            FRlogo_file=FRlogo_file,
                            outdirTmp=outdirTmp,
                            df_page=df_page)
    }

    # If summarize matrix needs to be plot
    if ('matrix' %in% what_plot) {
        df_page = matrix_panel(list_df2plot,
                               df_meta,
                               trend_period,
                               mean_period,
                               colorForce=colorForce,
                               slice=19,
                               outdirTmp=outdirTmp,
                               A3=TRUE,
                               foot_note=foot_note,
                               foot_height=foot_height,
                               resources_path=resources_path,
                               logo_dir=logo_dir,
                               AEAGlogo_file=AEAGlogo_file,
                               INRAElogo_file=INRAElogo_file,
                               FRlogo_file=FRlogo_file,
                               df_page=df_page)
    }

    # If datasheets needs to be plot
    if ('datasheet' %in% what_plot) {
        df_page = datasheet_panel(list_df2plot,
                                  df_meta,
                                  trend_period=trend_period,
                                  mean_period=mean_period,
                                  axis_xlim=axis_xlim,
                                  colorForce=colorForce,
                                  info_header=info_header,
                                  time_header=time_header,
                                  foot_note=foot_note,
                                  layout_matrix=layout_matrix,
                                  info_height=info_height,
                                  time_ratio=time_ratio,
                                  var_ratio=var_ratio,
                                  foot_height=foot_height,
                                  resources_path=resources_path,
                                  logo_dir=logo_dir,
                                  AEAGlogo_file=AEAGlogo_file,
                                  INRAElogo_file=INRAElogo_file,
                                  FRlogo_file=FRlogo_file,
                                  outdirTmp=outdirTmp,
                                  df_page=df_page)
    }

    summary_panel(df_page,
                  foot_note,
                  foot_height,
                  resources_path,
                  logo_dir=logo_dir,
                  AEAGlogo_file,
                  INRAElogo_file,
                  FRlogo_file,
                  outdirTmp)

    # Combine independant pages into one PDF
    details = file.info(list.files(outdirTmp, full.names=TRUE))
    details = details[with(details, order(as.POSIXct(mtime))),]
    listfile_path = rownames(details)
    
    summary_path = listfile_path[length(listfile_path)]
    listfile_path = listfile_path[-length(listfile_path)]
    listfile_path = c(summary_path, listfile_path)
    
    pdf_combine(input=listfile_path,
                output=file.path(outdir, outfile))
} 


## 4. PDF ORGANISATION PANEL _________________________________________
### 4.1. Summary _____________________________________________________
summary_panel = function (df_page, foot_note, foot_height, resources_path, logo_dir, AEAGlogo_file, INRAElogo_file, FRlogo_file, outdirTmp) {
    
    text_title = paste(
        "<b>Analyse de Stationnarité Hydrologique</b>",
        sep='')
    
    text_subtitle = paste(
        "Bassin Adour-Garonnne",
        sep='')

    Sec_name = rle(df_page$section)$values
    nSec = length(Sec_name)
    
    text_sum1 = ''
    text_page1 = ''
    text_sum2 = ''
    text_page2 = ''
    
    nline = 0
    nline_max = 58
    for (idS in 1:nSec) {
        sec_name = Sec_name[idS]
        subSec_name = rle(df_page$subsection[df_page$section == sec_name])$values
        n_page = df_page$n[df_page$section == sec_name][1]

        line = paste("<b>", idS, ". ", sec_name, "</b>", "<br>", sep='')
        page = paste("<b>p.", n_page, "</b><br>", sep='')
        
        if (nline <= nline_max) {
            text_sum1 = paste(text_sum1, line, sep='')
            text_page1 = paste(text_page1, page, sep='')
        } else {
            text_sum2 = paste(text_sum2, line, sep='')
            text_page2 = paste(text_page2, page, sep='')
        }

        nline = nline + 1
        
        nSSec = length(subSec_name)
        for (idSS in 1:nSSec) {
            subsec_name = subSec_name[idSS]
            if (!is.na(subsec_name)) {
                n_page = df_page$n[df_page$section == sec_name &
                                   df_page$subsection == subsec_name][1]

                line = paste("<b>", idS, ".", idSS, ".</b> ",
                             subsec_name, "<br>", sep='')
                page = paste("p.", n_page, "<br>", sep='')
                
                if (nline <= nline_max) {
                    text_sum1 = paste(text_sum1, line, sep='')
                    text_page1 = paste(text_page1, page, sep='')
                } else {
                    text_sum2 = paste(text_sum2, line, sep='')
                    text_page2 = paste(text_page2, page, sep='')
                }

                nline = nline + 1
            }
        }
        if (nline <= nline_max) {
            text_sum1 = paste(text_sum1, "<br>", sep='')
            text_page1 = paste(text_page1, "<br>", sep='')
        } else {
            text_sum2 = paste(text_sum2, "<br>", sep='')
            text_page2 = paste(text_page2, "<br>", sep='')
        }
        nline = nline + 1
    }

    # text_sum1 = gsub(" ", "<span style='color:white'>&#95;</span>",
                     # text_sum1)
    text_sum1 = gsub('[.]', '&#46;', text_sum1)
    text_page1 = gsub('[.]', '&#46;', text_page1)
    
    # text_sum2 = gsub(" ", "<span style='color:white'>&#95;</span>",
                     # text_sum2)
    text_sum2 = gsub('[.]', '&#46;', text_sum2)
    text_page2 = gsub('[.]', '&#46;', text_page2)

    
    # Converts all texts to graphical object in the right position
    gtitle = richtext_grob(text_title,
                           x=0, y=1,
                           margin=unit(c(t=0, r=0, b=0, l=0), "mm"),
                           hjust=0, vjust=1,
                           gp=gpar(col="#00A3A8", fontsize=20))

    gsubtitle = richtext_grob(text_subtitle,
                           x=0, y=1,
                           margin=unit(c(t=0, r=0, b=0, l=0), "mm"),
                           hjust=0, vjust=1,
                           gp=gpar(col="#00A3A8", fontsize=15))

    gsum1 = richtext_grob(text_sum1,
                          x=0, y=1,
                          margin=unit(c(t=0, r=0, b=0, l=0), "mm"),
                          hjust=0, vjust=1,
                          gp=gpar(col="#00A3A8", fontsize=10))
    
    gpage1 = richtext_grob(text_page1,
                           x=0, y=1,
                           margin=unit(c(t=0, r=0, b=0, l=0), "mm"),
                           hjust=0, vjust=1,
                           gp=gpar(col="#00A3A8", fontsize=10))

    gsum2 = richtext_grob(text_sum2,
                          x=0, y=1,
                          margin=unit(c(t=0, r=0, b=0, l=0), "mm"),
                          hjust=0, vjust=1,
                          gp=gpar(col="#00A3A8", fontsize=10))
    
    gpage2 = richtext_grob(text_page2,
                           x=0, y=1,
                           margin=unit(c(t=0, r=0, b=0, l=0), "mm"),
                           hjust=0, vjust=1,
                           gp=gpar(col="#00A3A8", fontsize=10))
    
    
    # If there is a foot note
    if (foot_note) {
        footName = 'sommaire'
        foot = foot_panel(footName,
                          1, resources_path,
                          logo_dir,
                          AEAGlogo_file, INRAElogo_file,
                          FRlogo_file, foot_height)

        P = list(gtitle, gsubtitle, gsum1, gpage1, gsum2, gpage2, foot)
        LM = matrix(c(1, 1, 1, 1,
                      2, 2, 2, 2,
                      3, 4, 5, 6,
                      7, 7, 7, 7),
                    nrow=4, byrow=TRUE)
    } else {
        foot_height = 0
        P = list(gtitle, gsubtitle, gsum1, gpage1, gsum2, gpage2)
        LM = matrix(c(1, 1, 1, 1,
                      2, 2, 2, 2,
                      3, 4, 5, 6),
                    nrow=3, byrow=TRUE)
    }
    id_title = 1
    id_subtitle = 2
    id_page1 = 4
    id_page2 = 6
    id_foot = 7

    LMcol = ncol(LM)
    LMrow = nrow(LM)
    
    LM = rbind(rep(99, times=LMcol), LM, rep(99, times=LMcol))
    LMrow = nrow(LM)
    LM = cbind(rep(99, times=LMrow), LM, rep(99, times=LMrow))
    LMcol = ncol(LM)

    title_height = 0.75
    subtitle_height = 1.25
    margin_size = 0.5
    page_width = 2
    height = 29.7
    width = 21

    row_height = (height - 2*margin_size - foot_height - title_height - subtitle_height) / (LMrow - 5)

    Hcut = LM[, 2]
    heightLM = rep(row_height, times=LMrow)
    heightLM[Hcut == id_title] = title_height
    heightLM[Hcut == id_subtitle] = subtitle_height
    heightLM[Hcut == id_foot] = foot_height
    heightLM[Hcut == 99] = margin_size

    col_width = (width - 2*margin_size - 2*page_width) / (LMcol - 4)
    
    Wcut = LM[4,]
    widthLM = rep(col_width, times=LMcol)
    widthLM[Wcut ==  id_page1 | Wcut ==  id_page2] = page_width
    widthLM[Wcut == 99] = margin_size

    # Arranges the graphical object
    plot = grid.arrange(grobs=P, layout_matrix=LM,
                        heights=heightLM, widths=widthLM)
    
    # Saves the plot
    ggsave(plot=plot,
           path=outdirTmp,
           filename=paste('sommaire', '.pdf', sep=''),
           width=width, height=height, units='cm', dpi=100)
}

### 4.2. Foot note panel______________________________________________
foot_panel = function (name, n_page, resources_path, logo_dir, AEAGlogo_file, INRAElogo_file, FRlogo_file, foot_height) {
    
    text_page = paste(
        name, "  <b>p. ", n_page, "</b>",
        sep='')
    
    text_date = paste (
        format(Sys.Date(), "%B %Y"),
        sep='')

    # Converts all texts to graphical object in the right position
    gtext_page = richtext_grob(text_page,
                               x=1, y=0,
                               margin=unit(c(t=0, r=0, b=0, l=0), "mm"),
                               hjust=1, vjust=0.5,
                               gp=gpar(col="#00A3A8", fontsize=8))

    gtext_date = richtext_grob(text_date,
                               x=1, y=0.55,
                               margin=unit(c(t=0, r=0, b=0, l=0), "mm"),
                               hjust=1, vjust=0.5,
                               gp=gpar(col="#00A3A8", fontsize=6))
    
    AEAGlogo_path = file.path(resources_path, logo_dir, AEAGlogo_file)
    INRAElogo_path = file.path(resources_path, logo_dir, INRAElogo_file)
    FRlogo_path = file.path(resources_path, logo_dir, FRlogo_file)
    
    AEAGlogo_img = readPNG(AEAGlogo_path)
    AEAGlogo_grob = rasterGrob(AEAGlogo_img,
                               y=0.49,
                               vjust=0.5,
                               width=unit(0.7*foot_height, "cm"))
    
    INRAElogo_img = readPNG(INRAElogo_path)
    INRAElogo_grob = rasterGrob(INRAElogo_img,
                                y=0.565,
                                vjust=0.5,
                                width=unit(1.08*foot_height, "cm"))
    
    FRlogo_img = readPNG(FRlogo_path)
    FRlogo_grob = rasterGrob(FRlogo_img,
                             x=0, hjust=0,
                             width=unit(1*foot_height, "cm"))
    
    P = list(void,
             FRlogo_grob, INRAElogo_grob, AEAGlogo_grob,
             gtext_page, gtext_date)

    # Creates the matrix layout
    LM = matrix(c(1, 2, 3, 4, 5,
                  1, 2, 3, 4, 6),
                nrow=2, 
                byrow=TRUE)

    # And sets the relative width of each plot
    widths = rep(1, times=ncol(LM))
    widths[2] = 0.2
    widths[3] = 0.25
    widths[4] = 0.2
    
    # Arranges all the graphical objetcs
    plot = grid.arrange(grobs=P,
                        layout_matrix=LM,
                        widths=widths)
    
    # Return the plot object
    return (plot)
}