#' Get Values from an Array
#'
#' @param A An array object
#' @param i Vector consisting of the subscripts for the 1st dimension
#' @param j Vector consisting of the subscripts for the 2nd dimension
#' @param k Vector consisting of the subscripts for the 3rd dimension
#' @param l Vector consisting of the subscripts for the 4th dimension
#'
#' @param subs string specifying the subscripts such as "1:2, , 4, 2:2" \cr
#' or a numeric vector consisting of the scalar subscript for each dim.
#'
#' @param value The value to be assigned.
#'
#' @details
#' It is assumed that \code{A} is an array. \cr
#' When \code{A} is a list of data frames, use \code{get_valL} instead.\cr
#' When numeric \code{subs} is given it must be a vector of length
#' \code{length(dim(A))} specifying a scalar element of \code{A}. \cr
#' \cr
#' \code{get_val(A,i,j,k,l)} returns \code{A[i,j,k,l]}. \cr
#' \code{put_val(A,i,j,k,l) <- value} puts the value at \code{A[i,j,k,l]}.
#' \cr
#' Therefore, when \code{A} is an array, better use \code{A[i,j,k,l]}.
#' \cr
#'
#' \code{get_val(A,i,j,k,l)} is equivalent to \code{get_val(A,subs=subs)}
#' \cr where \code{subs} contains the values of \code{i,j,k,l} as a string.
#' \cr For example, \cr
#' \code{get_val(A, 1:2, , 3)} is equivalent to
#' \code{get_val(A, subs="1:2, , 3")}. \cr
#' \cr
#' Use \code{subs=} when the # of dimensions is more than 5.
#' \cr
#'
#' \code{subs=} has priority over \code{i,j,k,l}.
#'
#' \cr
#' The result will be simplified to a matrix or vector if possible.
#'
#' @examples
#' # set up an array B
#' dims=c(5,4,3,2)
#' B <- array(0,dims)
#' B[,,,1] <- demomat(5,4,3)*10+1
#' B[,,,2] <- demomat(5,4,3)*10+2
#' dimnames(B) <-
#'  mapply( function(x,y){paste(x,1:y,sep="")}, letters[1:length(dims)],dims)
#'
#' # get B[5,4,3,2]
#' res1=get_val(B,5,4,3,2)
#' res2=get_val(B,subs=c(5,4,3,2))
#' res3=get_val(B,subs="5,4,3,2")
#' Print(res1,res2,res3)
#'
#' # get B[2,,3,]:  cannot use numeric subs here.
#' res1=get_val(B,2,,3)
#' res3=get_val(B,subs="2,,3,")
#' Print(res1, res3 )
#'
#' # modify B[,1,2:3,1]
#' ( temp <- B[,1,2:3,1] )
#' put_val(B,,1,2:3,1) <- -9999
#' B[,1,2:3,1]
#' put_val(B,subs=",1,2:3,1") <- temp
#' B[,1,2:3,1]
#' put_val(B,subs=c(1,1,1,2)) <- -9999
#' B[1,1,1,2]
#'
#'
#' @return
#'  \code{get_val(A, i,j.,k,l)} returns
#'  \code{A[i,j,k,l]}. \cr
#'  \code{put_val(A, i,j,k,l) <- value} replaces
#'  \code{A[i,j,k,l]} with \code{value}.
#'
#' @export
#'

get_val <- function( A, i=NULL, j=NULL, k=NULL, l=NULL, subs=NULL ){
 # get value of A at subs
 # Shin-ichi Mayekawa
 # 20160915c
 # i,j,k,l: 20171030
 #

 if( is.list(A) ){
  cat("\nerror1:(get_val) Use get_valL instead for list A.\n")
  stop()
 }

 # is subs given?
 if( !is.null(subs) ){

  cond=0
  if( all(is.numeric(subs)) && length(subs) == length(dim(A)) ){
   # numeric subs specifying a scalar element
   subs=paste(subs,collapse=",")
   cond=1
  }
  if( length(subs) == 1  && is.character(subs) ){
   # string subs
   cond=2
  }

 if( cond != 0 ){
  code=paste("Asub=A[",paste(subs,collapse=","),"]",sep="")
  eval(parse(text=code))
  return(Asub)
 }
 else{
   cat("\nerror1:(get_val) The length of numeric sub must be the same",
       "as the # of dimensions of A.\n")
   stop()
  }

 }

 # subs not given
 dimA=dim(A)
 ndim=length(dimA)

 if( ndim >= 5 ){
  cat("\nerror1:(get_val) Use subs= when length(dim(A)) >= 5. \n")
  stop()
 }

 code="Asub=A["
 for( s in 1:ndim ){  # 3 for i,j,k

  if( s == 1 ) ss=i
  else if( s == 2 ) ss=j
  else if( s == 3 ) ss=k
  else if( s == 4 ) ss=l

  if( !is.null(ss) ){
   isub=paste("c(", paste(ss,collapse=","),")", sep="")
  }
  else{
   isub=paste("c(", paste(1:dim(A)[s],collapse=","),")", sep="")
  }
  # Print(s,isub)
  code=paste(code,isub,collapse="")
  if( s < ndim ) code=paste(code, ",", collapse="")
  # Print(code)
 }
 code=paste(code, "]", collapse="")
 # Print(code)

 eval(parse(text=code))
 return(Asub)

} # end of get_val


#' @rdname get_val
#' @export
#'

`put_val<-` <- function( A, i=NULL, j=NULL, k=NULL, l=NULL, subs=NULL
                         , value ){
 # modify the value of A at subs
 # Shin-ichi Mayekawa
 # 20160915c
 # i,j,k,l: 20171030

 if( is.list(A) ){
  cat("\nerror1:(get_val) Use get_valL instead for list A.\n")
  stop()
 }

 if( !is.null(subs) ){

  cond=0
  if( all(is.numeric(subs)) && length(subs) == length(dim(A)) ){
   subs=paste(subs,collapse=",")
   cond=1
  }
  if( length(subs) == 1  && is.character(subs) ){
   cond=2
  }
  if( cond != 0 ){
   code=paste("A[",paste(subs,collapse=","),"]=value",sep="")
   eval(parse(text=code))
   return(A)
  }
  else{
   cat("\nerror1:(put_val) The length of numeric sub must be the same",
       "as the # of dimensions of A.\n")
   stop()
  }
 }



 # subs not given
 dimA=dim(A)
 ndim=length(dimA)

 if( ndim >= 5 ){
  cat("\nerror1:(put_val) Use subs= when length(dim(A)) >= 5. \n")
  stop()
 }

 code="A["
 for( s in 1:ndim ){  # 3 for i,j,k

  if( s == 1 ) ss=i
  else if( s == 2 ) ss=j
  else if( s == 3 ) ss=k
  else if( s == 4 ) ss=l

  if( !is.null(ss) ){
   isub=paste("c(", paste(ss,collapse=","),")", sep="")
  }
  else{
   isub=paste("c(", paste(1:dim(A)[s],collapse=","),")", sep="")
  }
  # Print(s,isub)
  code=paste(code,isub,collapse="")
  if( s < ndim ) code=paste(code, ",", collapse="")
  # Print(code)
 }
 code=paste(code, "]=value", collapse="")
 # Print(code)

 eval(parse(text=code))
 return(A)


} # end of `put_val<-`


