#Remove stocks depending on missing threshold. (0.5 maximo 50% NA, 0.2 maximo 0.2 NA)
del.Umbr.nas<-function(DF,Umb){ 
  
  stock.nas<-apply(DF,2,function(x) sum(is.na(x)))
  
  return(DF[,stock.nas<Umb*nrow(DF)])
}




#Compute object FD  for stacoks with missings.
calc.FD.faltantes<-function(DF.miss,mat,fbasis){
  
  good.args<-apply(DF.miss,2,function(x) which(!is.na(x)))
  
  
  DF.miss.FD<-list() #Lista con los FD de las acciones con NAs.
  L<-length(index.missing)
  for (i in 1:L){
    posiciones<-good.args[[i]]
    nombre=names(good.args[i])
    Y<-mat[posiciones,nombre]
    
    FD.m<-Data2fd(argvals = posiciones,y=mat[posiciones,nombre]  ,basisobj = fbasis,fdnames = list("Dia","Accion","Valor"))
    
    DF.miss.FD[[i]]<-FD.m
    
  }
  
  names(DF.miss.FD)<-names(DF.miss)
  
  return(DF.miss.FD)
}




insertar.coef.faltantes<-function(FD,DF.miss.FD){
  Coefs<-t(FD$coefs) #Coefficients are extracted and inserted those computed for NaNs.
  
  for(nombre in names(DF.miss.FD)){
    
    linea_coeficientes<-t(DF.miss.FD[[nombre]]$coefs)
    
    Coefs[nombre,]<-linea_coeficientes
  }
  FD$coefs<-t(Coefs)
  return(FD)
}



calc.RMS_i<-function(fd_i,data_i,args){
  
  fd.values<-eval.fd(evalarg = args,fdobj = fd_i)
  r.values<-data_i
  dif<-fd.values-r.values
  RMS_i<-sqrt(mean(dif^2))
  return(RMS_i)
  
}

calc.RMS.total<-function(FD,DF,args){
  J<-ncol(DF)
  vRMS<-vector(length = J)
  for (j in 1:J){
    vRMS[j]<-calc.RMS_i(FD[j,],DF[,j],args)
    
  }
  
  return(mean(vRMS,na.rm=T))
  
}



insertar.coeficientes.faltantes.Bi<-function(tempfd,List.miss.FD){
  
  Coefs<-(tempfd$coefs) #Coefficients are extracted and inserted those computed for NaNs.
  dim(List.miss.FD[[1]]$coefs)
  dim(Coefs)
  
  
  List.miss.FD[[1]]$coefs
  
  for(nombre in names(List.miss.FD)){
    
    coeficientes_1<-List.miss.FD[[nombre]]$coefs[,1] #Coeficientes buenos en cada dimensión
    coeficientes_2<-List.miss.FD[[nombre]]$coefs[,2]
    
    #los insertamos donde corresponde
    
    Coefs[,,1][,nombre]<-coeficientes_1
    Coefs[,,2][,nombre]<-coeficientes_2
  }
  tempfd$coefs<-Coefs
  return(tempfd)
}




gen.FD.object.BI<-function(N,Betas,retornos){ #Compute FD object for certain year with con N basis.
  # ARRAY###########
  
  
  this.Beta250<-Betas
  this.r250<-retornos
  
  
  filt.Beta250<-this.Beta250[rownames(this.Beta250)%in%rownames(this.r250),]
  filt.r250<-this.r250[rownames(this.r250)%in%rownames(this.Beta250),]
  
  stocks_ok<-intersect(names(filt.Beta250),names(filt.r250))
  
  filt.Beta250<-filt.Beta250[stocks_ok]
  filt.r250<-filt.r250[stocks_ok]
  
  
  data.array<-array(0,dim = c(dim(filt.r250),2))
  
  data.array[,,1]<-as.matrix(filt.r250)
  data.array[,,2]<-as.matrix(filt.Beta250)
  
  rownames(data.array)<-as.character(rownames(filt.Beta250))
  colnames(data.array)<-colnames(filt.r250)
  
  
  #Arguments#
  
  
  data.Length<-nrow(data.array)
  args<-c(1:data.Length)
  
  
  
  # Bspline basis and penalty matrix
  
  
  fbasis<-create.bspline.basis(rangeval = c(1,data.Length),nbasis = N)
 
  
  PM=eval.penalty(fbasis)
  
  
  # FD is created
  
  
  tempfd <- Data2fd(args,data.array, fbasis)
  
  
  #Index with missings.
  
  index.missing<-which(is.na(apply(data.array,2,mean)))
  
  List.miss.FD<-list() #List with (correct) FD for stocks with NAs.
  L<-length(index.missing)
  
  if(L==0) return(tempfd)   #End here, if no missings.
  
  
  
  array.miss<-data.array[,index.missing, ,drop=F]
  good.args<-apply(array.miss[,,1,drop=F],2,function(x) which(!is.na(x)))
  
  
  for (i in 1:L){
    if(L==1){
      posiciones<-as.numeric(good.args)
      nombre=colnames(good.args)
    }
    if(L>1){
      posiciones<-good.args[[i]]
      nombre=names(good.args[i])
    }
    # print(paste0("Faltantes:",L))
    
    Y<-data.array[posiciones,nombre,]
    
    
    FD.m<-Data2fd(argvals = posiciones,y=Y  ,basisobj = fbasis,fdnames = list("Dia","Accion","Valor"))
    
    List.miss.FD[[i]]<-FD.m
    
  }
  
  names(List.miss.FD)<-colnames(array.miss)
  
  
 #insert in the corresponding place
  
  tempfd<-insertar.coeficientes.faltantes.Bi(tempfd,List.miss.FD)
  
  
  return(tempfd)
}