!> @file
!!   Basic routines for i/o based on ntpoly.
!! @author
!!   Copyright (C) 2016 CheSS developers
!!
!!   This file is part of CheSS.
!!   
!!   CheSS is free software: you can redistribute it and/or modify
!!   it under the terms of the GNU Lesser General Public License as published by
!!   the Free Software Foundation, either version 3 of the License, or
!!   (at your option) any later version.
!!   
!!   CheSS 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 Lesser General Public License for more details.
!!   
!!   You should have received a copy of the GNU Lesser General Public License
!!   along with CheSS.  If not, see <http://www.gnu.org/licenses/>.


!> Basic routines for i/o based on ntpoly.
module bigpoly_io
  use futile
  use dmatrixmodule, only : matrix_ldr, constructmatrixdfroms, destructmatrix
  use processgridmodule, only : constructprocessgrid, destructprocessgrid
  use psmatrixmodule, only : matrix_ps, constructmatrixfrommatrixmarket, &
     constructmatrixfrombinary, gathermatrixtoprocess, &
     writematrixtomatrixmarket, writematrixtobinary, destructmatrix
  use smatrixmodule, only : matrix_lsr, destructmatrix
  use sparsematrix_base, only : sparse_matrix, matrices
  implicit none
  private

  !> Public routines
  public :: bigpoly_read_to_dense
  public :: bigpoly_write_matrix

  contains

    !> Read a matrix to a dense local array.
    subroutine bigpoly_read_to_dense(dense, filename, comm, binary)
      !> The dense matrix (preallocated)
      real(8), dimension(:,:) :: dense
      !> The name of the file to read from.
      character(len=*), intent(in) :: filename
      !> The communicator to distribute along.
      integer, intent(in) :: comm
      !> True if it's a binary matrix.
      logical, intent(in) :: binary
      ! Local variables
      type(matrix_ps) :: ntinmat
      type(matrix_lsr) :: local_sparse
      type(matrix_ldr) :: local_dense

      ! Create the process grid
      call constructprocessgrid(comm)

      ! Read NTPoly
      if (binary) then
         call constructmatrixfrombinary(ntinmat, filename)
      else
         call constructmatrixfrommatrixmarket(ntinmat, filename)
      end if

      ! Check that the sizes match.
      if (size(dense, 1) /= ntinmat%actual_matrix_dimension .or. &
          size(dense, 2) /= ntinmat%actual_matrix_dimension) then
         call f_err_throw('Saved file has the wrong dimension.')
      end if


      ! Convert to a dense local matrix
      call gathermatrixtoprocess(ntinmat, local_sparse)
      call constructmatrixdfroms(local_sparse, local_dense)

      ! Extract
      dense = local_dense%data

      ! Cleanup
      call destructmatrix(ntinmat)
      call destructmatrix(local_sparse)
      call destructmatrix(local_dense)

      call destructprocessgrid()
    end subroutine bigpoly_read_to_dense

    !> Write a matrix to matrix market.
    subroutine bigpoly_write_matrix(inmat, inval, filename, comm, binary)
      !> Input CheSS sparse matrix type
      type(sparse_matrix), intent(in):: inmat
      !> Input CheSS matrix of data.
      type(matrices), intent(in) :: inval
      !> The name of the file to write to.
      character(len=*), intent(in) :: filename
      !> The communicator to distribute along.
      integer, intent(in) :: comm
      !> True if it's a binary matrix.
      logical, intent(in) :: binary
      ! Local variables
      type(matrix_ps) :: ntinmat

      call f_routine(id='write_matrix_mtx')

      ! Create the process grid
      call constructprocessgrid(comm)

      ! Conversion of input matrix.
      call chess_to_ntpoly(inmat, inval, ntinmat)

      ! Write
      if (binary) then
         call writematrixtobinary(ntinmat, filename)
      else
         call writematrixtomatrixmarket(ntinmat, filename)
      end if

      ! Cleanup
      call destructmatrix(ntinmat)
      call destructprocessgrid()

      call f_release_routine()
    end subroutine bigpoly_write_matrix

end module bigpoly_io
