#'ADAMONT QQCorr computes quantile-quantile correction of seasonal or decadal forecast data
#'
#'@author Paola Marson, \email{paola.marson@meteo.fr} for PROSNOW version
#'@author Lauriane Batté, \email{lauriane.batte@meteo.fr} for CSTools adaptation
#'
#'@param exp dimensions c(dataset,member,sdate,ftime,lat,lon)
#'@param wt dimensions c(dataset,member,sdate,ftime)
#'@param qexp dimensions c(Nwt, Nq+2, nlat, nlon)
#'@param qobs dimensions c(Nwt, Nq+2, nlat_o, nlon_o)
#'@param NN list (output from Adamont_NearestNeighbors) maps (nlat, nlon) onto (nlat_o, nlon_o)
#'
#'@import qmap
#'@import multiApply
#'@import abind

.QQSlope <- function(qexp, qobs) {
   Nwt <- dim(qexp)[1]
   Nq <- dim(qexp)[2] - 2
   slope1 <- (qobs[,2]-qobs[,1])/(qexp[,2]-qexp[,1])
   slope2 <- matrix(1,nrow=Nwt,ncol=Nq+2)
   return(list(s1=slope1,s2=slope2))
}

AdamontQQCorr <- function(exp, wt, obs, wt_obs, NN, wetonly=FALSE, thres=1.,corrdims = c('member', 'sdate', 'ftime'), londim='lon', latdim='lat') {

   obsdims <- names(dim(obs$data))
   poslat <- which(obsdims == latdim)
   poslon <- which(obsdims == londim)
   nlat_o <- dim(obs$data)[poslat]
   nlon_o <- dim(obs$data)[poslon]
   ilat_o <- array(c(1:nlat_o))
   dim(ilat_o) <- c('lat') 
   ilon_o <- array(c(1:nlon_o))
   dim(ilon_o) <- c('lon') 
   # First step if obs data is higher resolution than exp data is to use nearest neighbor
   # to compute downscaling of exp data	
   exp_corr <- Apply(list(exp$data,ilat_o,ilon_o),target_dims=list(c(londim,latdim),'lat','lon'),.getNN,NN=NN)$output1

   # Reorder exp_corr dimensions to match exp dimensions


   # Both exp and obs data are now on the same grid
   # Use CST_QuantileMapping function for quantile mapping, depending on weather type

   # Reshape obs and exp data
   # Apply QuantileMapping with exp_cor output for each weather type
   

   # Reshaping obs and exp_corr data
    

   ## Data needs to be organized for use in qmap package
   ## Aim of correction is to have qexp data on the qobs grid, bias adjusted using QQ method
   dim_exp <- dim(exp)
   dim_qobs <- dim(qobs) # CHECKS TO BE DONE: Nwt, Nq should be consistent between exp and obs
   nlat_o <- dim_qobs[3]
   nlon_o <- dim_qobs[4]
   Nwt <- dim_qobs[1]
   Nq <- dim_qobs[2]-2
   exp_corr <- array(dim=c(nlat_o,nlon_o,dim_exp[1:4]))
   exp <- aperm(exp,c(5,6,1,2,3,4))
   for (ilat in 1:nlat_o){
      for (ilon in 1:nlon_o){
         qq_slope <- .QQSlope(qexp[,,NN$imin_lat[ilat],NN$imin_lon[ilon]],qobs[,,ilat,ilon])
         for (reg in 1:Nwt){
            modq <- as.matrix(qexp[reg,,NN$imin_lat[ilat],NN$imin_lon[ilon]],nrow=Nq+2)
            fitq <- as.matrix(qobs[reg,,ilat,ilon],nrow=Nq+2)
            fobjj<-list(par=list(modq=modq,
               fitq=fitq,
               slope=as.matrix(c(qq_slope$s1[reg],qq_slope$s2[reg]),nrow=2))
               )
            attr(fobjj$par$slope,"dimnames")<-list(c("lower","upper"))
            class(fobjj) <- "fitQmapRQUANT"
            indices <- which(wt==reg,arr.ind=TRUE)
            for (ind in 1:dim(indices)[1]){
               exp_corr[ilat,ilon,indices[ind,1],indices[ind,2],indices[ind,3],indices[ind,4]] <- doQmapRQUANT(exp[NN$imin_lat[ilat],NN$imin_lon[ilon],indices[ind,1],indices[ind,2],indices[ind,3],indices[ind,4]],fobjj,type="linear",wet.day=ifelse(wetonly==TRUE,thres,FALSE))
            }
         }
      }
   }
   exp_corr <- aperm(exp_corr,c(3,4,5,6,1,2))
   return(exp_corr)
}

.getNN <- function(exp,ilat,ilon,NN){
   return(exp[NN$imin_lat[ilat,ilon],NN$imin_lon[ilat,ilon]])
}

