#' Generating Test Score Distribution according to Classical Test Theory
#'
#' This function generates a frequency distribution table
#'  of n discrete test scores in [minscore,maxscore].
#'
#' @param n # of observations.
#' @param minscore The minimum score.
#' @param maxscore The maximum score.
#' @param rho The reliability coefficient
#' @param meanX0 The mean of observed test score
#' @param varX0 The variance of observed test score
#' @param beta Vector of alpha and beta parameters for beta distribution
#' in [minscore,maxscore].
#' @param orth = 1 to orthogonalize T and E. (not yet available.)
#' @param discrete = 0 to use continuous random variables
#' @param seed The random number seed or NULL
#' @param print = 1 to print the result.
#' @param plot = 1 to plot the result.
#' @param title Title string to be used in plot.
#'
#' @details
#' This function generates a set of \cr
#'  (observed score X, true score T, error score E) \cr
#' of size n in [minscore <= X <= maxscore] according to
#' the Classical Test Theory.
#'
#' Continuous random numbers, either normal or generalized beta,
#' are first generated and then they are discretized by cut function.
#' Those values outside of [minscore,maxscore] will be set to minscore
#' or maxscore, resp.
#'
#' beta parameter has priority over nomal parameter.
#'
#' @examples
#'
#'
#' res=gen_test_score_CTT(n=10000, varX0=17^2, rho=0.60, seed=1701
#'                   , plot=1, print=1, minscore=0, maxscore=100)
#' seed=1701; set.seed(seed)
#' res=gen_test_score_CTT(n=10000, varX0=17^2, rho=0.60
#'                   , plot=1, print=1, minscore=0, maxscore=100)
#'
#' res=gen_test_score_CTT(n=10000, varX=18^2, rho=0.80, beta=c(5,2)
#'                   , plot=1, print=1, minscore=0, maxscore=100, seed=1701)
#' res=gen_test_score_CTT(n=10000, meanX0=60, varX=18^2, rho=0.80, beta=c(5,2)
#'                   , plot=1, print=1, minscore=0, maxscore=100, seed=1701)
#'
#' @return
#' A list of: \cr
#' rho The actual reliability \cr
#' meanX The actual mean of X \cr
#' stdX The actual standard deviation of X \cr
#' meanT The actual mean of T \cr
#' stdT The actual standard deviation of T \cr
#' meanE The actual mean of E \cr
#' stdE The actual standard deviation of E \cr
#' cor The correlation matrix of (X,T,E) \cr
#' XTE A matrix consisting of \code{X,T,E}. (n times 3 matrix) \cr
#' scoredist Score distribution of X \cr
#'
#' @export
#'

gen_test_score_CTT <- function( n, minscore=NULL, maxscore=NULL, rho0=0.9
                                , meanX0=NULL, varX0=15^2
                                , beta=NULL,  orth=0, discrete=1
                                , seed=NULL, print=0, plot=0, title=NULL ){

 # generation of test score according to CTT
 # Shin-ichi Mayekawa
 # 20190901,02,03,03dnc
 # comments: 20191029dnc
 # seed: 20191030,1101dnc
 # stanine removed: 20191106dnc
 # roxygen2 comment: 20200526
 #

 #
 # Args:
 #  n        = # of obs
 #  minscore = minimum score of X or NULL
 #  maxscore = maximum score of X or NULL
 #  rho0      = reliability of X:  Must be given.
 #  meanX0    = mean of X or NULL
 #  varX0     = variance of X:  Must be given.
 #  beta     = parameter vec of beta dist for T
 #  discrete = 1 to discretize X
 #

 # random number seed
 if( !is.null(seed) ) set.seed(seed)

 # mean of X
 # When beta is given, meanX must be specified carefully.
 if( is.null(meanX0) ){
  if( is.null(beta) ){
   meanX0=(minscore+maxscore)/2
  }
  else{
   meanX0=(maxscore-minscore)*beta[1]/sum(beta) + minscore
  }
 }

 # Given rho and varX, define stdE and stdT
 stdX0=sqrt(varX0)
 stdE0=sqrt( (1-rho0)*varX0 )
 stdT0=sqrt( rho0*varX0 )

 # generate true scores
 if( is.null(beta) ){
  T=rnorm(n,meanX0,stdT0)
 }
 else{
  T=rbeta(n,beta[1],beta[2])
  T=T*(maxscore-minscore)+minscore
  # T above is in [minscore,maxscore]
  stdt=sqrt((n-1)/n*var(T))
  T=T/stdt*stdT0
  # T above is in  [minscore,maxscore] / stdt*stdT
 }

 # error and obs score
 E=rnorm(n,0,stdE0)

 # orthogonalize T and E
 if( orth ){
 #########################
 }


 # obs score
 X=T+E

 # set mean and std of X exactly.
 meanx=mean(X)
 stdx=sqrt((n-1)/n*var(X))
 dd=stdX0/stdx
 X=(X-meanx)*dd+meanX0
 T=(T-meanx)*dd+meanX0
 E=dd*E
 T=T-mean(T)+meanx
 E=E+mean(T)-meanx


 # Print(mands(cbind(X,T,E)))

 # discretize
 if( discrete ){
  X=round(X)
 }


 # put all into [minscore,maxscore]
 if( !is.null(minscore) ){
  if( any( X < minscore ) ){
   loc=which(X<minscore)
   T[loc]=T[loc]+(minscore-X[loc])
   # E[loc]=E[loc]+(minscore-X[loc])
   X[loc]=minscore
  }
 } else minscore=min(X)
 if( !is.null(maxscore) ){
  if( any( X > maxscore ) ){
   loc=which(X > maxscore)
   T[loc]=T[loc]-(X[loc]-maxscore)
   # E[loc]=E[loc]-(X[loc]-maxscore)
   X[loc]=maxscore
  }
 } else maxscore=max(X)


 # sort X
 od=order(X)
 X=X[od]; T=T[od]; E=E[od]

 # stat
 XTE=cbind(X,T,E)
 ms=mands(XTE)

 if( print ){
  Print(rho0, meanX0, varX0, stdX0, discrete)
  Print(summary(XTE))
  Print(ms, fmt="10.3")
 }

 meanX=ms[1,1]; stdX=ms[2,1]; varX=ms[3,1]
 meanT=ms[1,2]; stdT=ms[2,2]; varT=ms[3,2]
 meanE=ms[1,3]; stdE=ms[2,3]; varE=ms[3,3]
 rho=varT/varX

 # corr
 cor=cor(XTE)


 # histogram
 score=seq(minscore,maxscore,length.out=maxscore-minscore+1)
 tt=table(X)
 # Print(score, names(tt), as.numeric(tt),as.numeric(names(tt))-minscore+1)
 freqx=numeric(length(score))
 freqx[as.numeric(names(tt))-minscore+1]=as.numeric(tt)
 scoredist=cbind(score,freqx)
 colnames(scoredist)=c("score","freq")

 if( print ){
  Print( rho0, meanX0, stdX0, stdT0, stdE0, fmt="6.3" )
  Print( rho, meanX, stdX, stdT, stdE, fmt="6.3" )
  if( print >= 2 ) Print(scoredist)
 }


 if( plot ){
  rhoc=formatC(rho,digits=2,format="f")
  meanXc=formatC(meanX,digits=2,format="f")
  stdXc=formatC(stdX,digits=2,format="f")
  stdEc=formatC(stdE,digits=2,format="f")
  title=paste( title, "  n = ", n, sep="" )
  title=paste(title, ",  mean =", meanXc, ", std =", stdXc, sep="")
  title=paste(title, ",  rho =", rhoc, ",  SEM =", stdEc, sep="")
  barplot(height=scoredist[,2], names.arg=as.character(scoredist[,1])
          , main=title, cex.names=.65, space=0, las=2)
 }


 if(0){
  ThatC=NULL; tabS=NULL; bpx=NULL; bpt=NULL; stat=NULL
 }


 return(
  named_list( rho, meanX, stdX, meanT, stdT, meanE, stdE
              , cor, XTE, scoredist )
  )


} # end of gen_test_score_CTT


