# SQUIC.R
#
# Copyright (C) Aryan Eftekhari
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# Main function
SQUIC <- function(Y, lambda, max_iter=100, tol=1e-3,tol_inv=1e-4,verbose=1, M=NULL, X0=NULL, W0=NULL) {
  
  verbose <- min(verbose,1)
  
  Y <- as.matrix(Y)
  p <- nrow(Y)
  n <- ncol(Y)

  if(p<3){
	  stop('#SQUIC: number of random variables (p) must larger than 2')
  }
  if(n<2){
    stop('#SQUIC: number of samples (n) must be larger than 1 .')
  }
  if(lambda<=0){
	  stop('#SQUIC: lambda must be great than zero.')
  }
  if(max_iter<0){
	  stop('#SQUIC: max_iter cannot be negative.')
  }
  if(tol<=0){
	  stop('#SQUIC: tol must be great than zero.')
  }
  if(tol_inv<=0){
	  stop('#SQUIC: tol_inv must be great than zero.')
  }

  if(is.null(M)){
	  # Make empty sparse matrix of type dMatrix.
	  M <- as(Matrix::sparseMatrix(dims = c(p,p), i={}, j={}),"dMatrix")
  }else{

    if(nrow(M)!= p || ncol(M)!=p){
      stop('#SQUIC: M must be square matrix with size pxp.')
    } 

    # Make all postive, drop all zeros and force symmetric
    M <- Matrix::drop0(M)
    M <- abs(M)
  	M <- Matrix::forceSymmetric(M,uplo="L")
  }

  if(is.null(X0) || is.null(W0)){
	  # Make identity sparse matrix of type dMatrix.
	  X0 <- as(Matrix::sparseMatrix(dims = c(p,p), i=c(1:p), j=c(1:p) , x=rep(1, p)),"dMatrix")
	  W0 <- as(Matrix::sparseMatrix(dims = c(p,p), i=c(1:p), j=c(1:p) , x=rep(1, p)),"dMatrix")
  }else{

    if(nrow(X0)!= p || ncol(X0)!=p){
      stop('#SQUIC: X0 must be square matrix with size pxp.')
    } 

    if(nrow(W0)!= p || ncol(W0)!=p){
      stop('#SQUIC: W0 must be square matrix with size pxp.')
    } 

    # Force Symmetric
    X0 <- Matrix::forceSymmetric(X0,uplo="L")
    W0 <- Matrix::forceSymmetric(W0,uplo="L")
  }
  
  #Use block variant of SQUIC
  mode <- 0
  
  # tolerances
  term_tol <- tol
  inv_tol  <- tol_inv

  output <- SQUIC::SQUIC_R(
   	Y , 
   	lambda , 
   	max_iter , inv_tol , term_tol , 
   	verbose , mode , 
   	M , X0 , W0)

  return(output)
}
