#Computes the value of the test statistics for the ACD(1,1) model with different innovation distributions; see Section 2.1 and 3.2 of Meintanis, Milosevic and Obradovic.
#EPPS-PULLEY TEST
acd.EP.test<-function(x,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  #CMLE estimation 
modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
if ('try-error'%in% class(modelOut)) {
  if (errmes==TRUE) print('Error fitting acd model')
  return(FALSE)
}

#Extracting residuals
res<-modelOut$residual
n<-length(res)

#Calculation of test statistic 
y<-res/mean(res)
EP<-sqrt(48*n)*(mean(exp(-y)-0.5))

#Output
return(list(statistic=EP,model.coef=modelOut$mPara))
}

#BARINGHAUS-HENZE TEST
acd.BH.test<-function(x,a=1,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  y<-res/mean(res)
  BH<-0
  for(j in 1:n){
    BH<-BH+sum((1-y)*(1-y[j])/(y+y[j]+a))-sum((y+y[j])/(y+y[j]+a)^2)+sum((2*y*y[j])/(y+y[j]+a)^2)+sum((2*y*y[j])/(y+y[j]+a)^3)
  }
  
  #Output
  return(list(statistic=BH/n,model.coef=modelOut$mPara))
}
#COX-OAKES
acd.CO.test<-function(x,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  y<-res/mean(res)
  CO<-n+sum((1-y)*log(y))
  
  #Output
  return(list(statistic=CO,model.coef=modelOut$mPara))
}

#HENZE-MEINTANIS TEST
acd.HM.test<-function(x,a=1,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  y<-res/mean(res)
  HM<-0
  for(j in 1:n){
    HM<-HM+sum((1+(y+y[j]+a+1)^2)/(y+y[j]+a)^3)
  }
  HM=HM/n-2*sum((1+y+a)/(y+a)^2)+n/a
  
  #Output
  return(list(statistic=HM,model.coef=modelOut$mPara))
}
#TEST "VO" BASED ON ROSSBERG CHARACTERIZATION
acd.VO.test<-function(x,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  y<-sort(res)
  VO<-0
  for(j in 2:(n-1)){
    pool<-c(y,(y[j]-y[1:(j-1)]))
    VO<-VO+(sum(rank(pool)[1:n])-n*(n+1)/2)*(n-j)
  }
  N<-choose(n,3)
  VO<-VO/n/N-(2*n+2)/3/n
  
  #Output
  return(list(statistic=VO,model.coef=modelOut$mPara))
}
#TEST "MI" BASED ON OBRADOVIC CHARACTERIZATION
acd.MI.test<-function(x,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  y<-sort(res)
  MI<-0
  for(j in 2:(n-1)){
    MI<-MI+sum((n-n*ecdf(y)(y[j]+y))*(6*(j-1)*(n-j)+3*(j-1)+3*(n-j)+1))
  }
  MI<-MI+sum((n-n*ecdf(y)(y[1]+y))*(3*(n-1)+1))+sum((n-n*ecdf(y)(y[n]+y))*(3*(n-1)+1))
  MI<--MI/n^5+(n+1)^2/4/n^2
  
  #Output
  return(list(statistic=MI,model.coef=modelOut$mPara))
}
#TEST "MO" BASED ON PURI-RUBIN CHARACTERIZATION
acd.MO.test<-function(x,a=1,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  y<-res/mean(res)
  MO<-0
  for(j in 1:(n-1)){
    MO<-MO+sum(2/(a+abs(y[(j+1):n]-y[j]))-1/(a+y[(j+1):n])-1/(y[j]+a))
  }
  
  #Output
    return(list(statistic=MO/n/(n-1),model.coef=modelOut$mPara))
}
#TEST "LO" BASED ON MAXIMUM ENTROPY
acd.LO.test<-function(x,L=1000,m=5,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  adjust<-10^(-7)
  mx<-matrix(runif(L*m),ncol=m)
  w<-mx/rowSums(mx)
  y<-pexp(res)
  Fy<-ecdf(y)
  diffs<-(Fy((1:m)/m)-Fy((0:(m-1))/m)+adjust)*log(Fy((1:m)/m)-Fy((0:(m-1))/m)+adjust)
  LO<-max(abs(w%*%diffs))*sqrt(n)
  
  #Output
  return(list(statistic=LO,model.coef=modelOut$mPara))
}
#TEST "FG" BASED ON KERNEL DENSITY ESTIMATION
acd.FG.test<-function(x,distrib,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #Choice the innovation distribution
  if(distrib=="exp"){
    
    #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  }
  
  #Choice the innovation distribution
else if(distrib=="gamma"){
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='gengamma',startPara=c(0.3,0.3,0.4,2,1),fixedParamPos=c(FALSE,FALSE,FALSE,FALSE,TRUE),
                             optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
}
else {print('Error: distrib must be "exp" or "gamma"')
  return(FALSE)}
  n<-length(res)
  
  #Calculation of test statistic
  if(distrib=="gamma") alpha<-modelOut$dPara[1] else alpha<-1
  FG<-mean(evmix::dbckden(x=sort(res),kerncentres=res,lambda=1/log(n)*1/4^(-1/5)*n^(-4/9),bcmethod="gamma1")-dgamma(sort(res),shape=alpha,rate=alpha))
  
  #Output
  return(list(statistic=FG,model.coef=modelOut$mPara,dist.param=modelOut$dPara))
}
#CRAMER-VON-MISES TEST
acd.CM.test<-function(x,distrib,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #Choice the innovation distribution
  if(distrib=="exp"){
    
    #CMLE estimation
    modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  }   
  
  
  
  #Choice the innovation distribution
  else if(distrib=="gamma"){
    
    #CMLE estimation
    modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='gengamma',startPara=c(0.3,0.3,0.4,2,1),fixedParamPos=c(FALSE,FALSE,FALSE,FALSE,TRUE),
                               optimFnc='optim',output=FALSE),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  } 
  
  
  
  #Choice the innovation distribution
  else if(distrib=="lognormal"){
    
    #CMLE estimation
    modelOut<-try(acd.Lognormal(durations=x,order=order,param=c(0.3,0.3,0.4,1)),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  }
  else {print('Error: distrib must be "exp", "gamma" or "lognormal')
    return(FALSE)}
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  if(distrib=="exp")
    CM<-goftest::cvm.test(res,"pexp",1)$statistic
  else if(distrib=="gamma")
    CM<-goftest::cvm.test(res,"pgamma",shape=modelOut$dPara[1],rate=modelOut$dPara[1])$statistic
  else if(distrib=="lognormal")
    CM<-goftest::cvm.test(res,"plnorm",meanlog=-modelOut$dPara[1]^2/2,sdlog=modelOut$dPara[1])$statistic
  
  #Output
  return(list(statistic=CM,model.coef=c(modelOut$mPara,modelOut$dPara[1])))
}

#KOLMOGOROV-SMIRNOV TEST
acd.KS.test<-function(x,distrib,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #Choice the innovation distribution
  if(distrib=="exp"){
    
    #CMLE estimation
        modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  }   
  
  
  
  #Choice the innovation distribution
  else if(distrib=="gamma"){
    
    #CMLE estimation
    modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='gengamma',startPara=c(0.3,0.3,0.4,2,1),fixedParamPos=c(FALSE,FALSE,FALSE,FALSE,TRUE),
                               optimFnc='optim',output=FALSE),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  } 

  
  
  #Choice the innovation distribution
  else if(distrib=="lognormal"){
    
    #CMLE estimation
    modelOut<-try(acd.Lognormal(durations=x,order=order,param=c(0.3,0.3,0.4,1)),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  }
  else {print('Error: distrib must be "exp", "gamma" or "lognormal')
    return(FALSE)}
    
    #Extracting residuals
    res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  if(distrib=="exp")
    KS<-ks.test(res,"pexp",1)$statistic
  else if(distrib=="gamma")
    KS<-ks.test(res,"pgamma",shape=modelOut$dPara[1],rate=modelOut$dPara[1])$statistic
  else if(distrib=="lognormal")
    KS<-ks.test(res,"plnorm",meanlog=-modelOut$dPara[1]^2/2,sdlog=modelOut$dPara[1])$statistic
  
  #Output
  return(list(statistic=KS,model.coef=c(modelOut$mPara,modelOut$dPara[1])))
}
#ANDERSON-DARLING TEST
acd.AD.test<-function(x,distrib,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #Choice the innovation distribution
  if(distrib=="exp"){
    
    #CMLE estimation
    modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='exp',optimFnc='optim',output=FALSE),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  }   
  
  
  
  #Choice the innovation distribution
  else if(distrib=="gamma"){
    
    #CMLE estimation
    modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='gengamma',startPara=c(0.3,0.3,0.4,2,1),fixedParamPos=c(FALSE,FALSE,FALSE,FALSE,TRUE),
                               optimFnc='optim',output=FALSE),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  } 
  
  
  
  #Choice the innovation distribution
  else if(distrib=="lognormal"){
    
    #CMLE estimation
    modelOut<-try(acd.Lognormal(durations=x,order=order,param=c(0.3,0.3,0.4,1)),silent=TRUE)
    if ('try-error'%in% class(modelOut)) {
      if (errmes==TRUE) print('Error fitting acd model')
      return(FALSE)
    }
  }
  else {print('Error: distrib must be "exp", "gamma" or "lognormal')
    return(FALSE)}
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  if(distrib=="exp")
    AD<-goftest::ad.test(res,"pexp",1)$statistic
  else if(distrib=="gamma")
    AD<-goftest::ad.test(res,"pgamma",shape=modelOut$dPara[1],rate=modelOut$dPara[1])$statistic
  else if(distrib=="lognormal")
    AD<-goftest::ad.test(res,"plnorm",meanlog=-modelOut$dPara[1]^2/2,sdlog=modelOut$dPara[1])$statistic
  
  #Output
  return(list(statistic=AD,model.coef=c(modelOut$mPara,modelOut$dPara[1])))
}
#TEST "HE_a^{(1)}" of Henze-Meintanis-Ebner for Gamma Innovations
acd.HE1.test<-function(x,a=1,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='gengamma',startPara=c(0.3,0.3,0.4,2,1),fixedParamPos=c(FALSE,FALSE,FALSE,FALSE,TRUE),optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  #Calculation of test statistic
  theta<-modelOut$dPara[1]
  y<-res*theta
  HE<-0
  for(j in 1:n){
    HE<-HE+sum((y*y[j]-theta*(y+y[j])+theta^2)/(y+y[j]+a)+(2*y*y[j]-theta*(y+y[j]))/(y+y[j]+a)^2+2*y[j]*y/(y[j]+y+a)^3)
  }
  HE=HE/n
  
  #Output
  return(list(statistic=HE,model.coef=c(modelOut$mPara,modelOut$dPara[1])))
}
#TEST "HE_a^{(2)}" of Henze-Meintanis-Ebner for Gamma Innovations
acd.HE2.test<-function(x,a=1,order=c(1,1),errmes=FALSE){
  if(min(x)<=0){
    if (errmes==TRUE) print('Durations must be positive')
    return(FALSE)
  }
  
  #CMLE estimation
  modelOut<-try(ACDm::acdFit(durations=x,order=order,dist='gengamma',startPara=c(0.3,0.3,0.4,2,1),fixedParamPos=c(FALSE,FALSE,FALSE,FALSE,TRUE),optimFnc='optim',output=FALSE),silent=TRUE)
  if ('try-error'%in% class(modelOut)) {
    if (errmes==TRUE) print('Error fitting acd model')
    return(FALSE)
  }
  
  #Extracting residuals
  res<-modelOut$residual
  n<-length(res)
  
  
  
  #Approximation of appearing Error function
  psi<-function(x){
    b0<-0.2316419
    b1<-0.319381530
    b2<--0.356563782
    b3<-1.781477937
    b4<--1.821255978
    b5<-1.330274429
    
    return((x<5)*(2-2*pnorm(x))*exp(x^2/2*(x<5))+(x>=5)*(2*(b1/(1+b0*x)+b2/(1+b0*x)^2+b3/(1+b0*x)^3+b4/(1+b0*x)^4+b5/(1+b0*x)^5)/sqrt(2*pi)))
  }
  
  #Calculation of auxillary integrals
  I0<-function(x,a){
    return(psi(x/sqrt(2*a))*sqrt(pi)/2/sqrt(a))
  }
  
  I1<-function(x,a){
    return((2*sqrt(a)+sqrt(pi)*(2*a-x)*psi(x/sqrt(2*a)))/4/a^(3/2))
  }
  
  I2<-function(x,a){
    return((1/a-x/4/a^2+sqrt(pi)*(4*a^2+a*(2-4*x)+x^2)*psi(x/sqrt(2*a))/8/a^(5/2)))
  }
  
  #Calculation of test statistic
  theta<-modelOut$dPara[1]
  y<-res*theta
    HE<-0
  for(j in 1:n){
     HE<-HE+sum((y*y[j]*I2(y+y[j],a)+theta^2*I0(y+y[j],a)-2*theta*y[j]*I1(y+y[j],a))/n)
    }

  
  #Output
  return(list(statistic=HE,model.coef=c(modelOut$mPara,modelOut$dPara[1])))
}
