/***************************************************************************
                          MatrixWriter.h  -  description
                             -------------------
    begin                : Dec 18, 2013
    copyright            : (C) 2013 by Tomas Oberhuber
    email                : tomas.oberhuber@fjfi.cvut.cz
 ***************************************************************************/

/* See Copyright Notice in tnl/Copyright */

#pragma once

#include <ostream>
#include <iostream>
#include <TNL/String.h>

namespace TNL {
namespace Matrices {

/**
 * \brief Helper class for exporting of matrices to different output formats.
 *
 * Currently it supports:
 *
 * 1. [Coordinate MTX Format](https://math.nist.gov/MatrixMarket/formats.html#coord) is supported.
 * 2. Gnuplot format for matrix visualization in [Gnuplot](http://www.gnuplot.info).
 * 3. EPS format for matrix pattern visualization in [Encapsulated PostScript](https://en.wikipedia.org/wiki/Encapsulated_PostScript)
 *
 * \tparam Matrix is a type of matrix into which we want to import the MTX file.
 * \tparam Device is used only for the purpose of template specialization.
 *
 * \par Example
 * \include Matrices/MatrixWriterReaderExample.cpp
 * \par Output
 * \include MatrixWriterReaderExample.out
 *
 */
template< typename Matrix, typename Device = typename Matrix::DeviceType >
class MatrixWriter
{
   public:

      /**
       * \brief Type of matrix elements values.
       */
      using RealType = typename Matrix::RealType;

      /**
       * \brief Device where the matrix is allocated.
       */

      using DeviceType = typename Matrix::RealType;

      /**
       * \brief Type used for indexing of matrix elements.
       */
      using IndexType = typename Matrix::IndexType;

      /**
       * \brief Method for exporting matrix to file with given filename using Gnuplot format.
       *
       * \param fileName is the name of the target file.
       * \param matrix is the source matrix.
       * \param verbose controls verbosity of the matrix export.
       */
      static void writeGnuplot( const TNL::String& fileName,
                                const Matrix& matrix,
                                bool verbose = false );

      /**
       * \brief Method for exporting matrix to STL output stream using Gnuplot format.
       *
       * \param file is the output stream.
       * \param matrix is the source matrix.
       * \param verbose controls verbosity of the matrix export.
       */
      static void writeGnuplot( std::ostream& str,
                                const Matrix& matrix,
                                bool verbose = false );

      /**
       * \brief Method for exporting matrix to file with given filename using EPS format.
       *
       * \param fileName is the name of the target file.
       * \param matrix is the source matrix.
       * \param verbose controls verbosity of the matrix export.
       */
      static void writeEps( const TNL::String& fileName,
                            const Matrix& matrix,
                            bool verbose = false );

      /**
       * \brief Method for exporting matrix to STL output stream using EPS format.
       *
       * \param file is the output stream.
       * \param matrix is the source matrix.
       * \param verbose controls verbosity of the matrix export.
       */
      static void writeEps( std::ostream& str,
                            const Matrix& matrix,
                            bool verbose = false );

      /**
       * \brief Method for exporting matrix to file with given filename using MTX format.
       *
       * \param fileName is the name of the target file.
       * \param matrix is the source matrix.
       * \param verbose controls verbosity of the matrix export.
       */
      static void writeMtx( const TNL::String& fileName,
                            const Matrix& matrix,
                            bool verbose = false );

      /**
       * \brief Method for exporting matrix to STL output stream using MTX format.
       *
       * \param file is the output stream.
       * \param matrix is the source matrix.
       * \param verbose controls verbosity of the matrix export.
       */
      static void writeMtx( std::ostream& str,
                            const Matrix& matrix,
                            bool verbose = false );

   protected:
      using HostMatrix = typename Matrix::template Self< RealType, TNL::Devices::Host >;
};

/// This is to prevent from appearing in Doxygen documentation.
/// \cond HIDDEN_CLASS
template< typename Matrix >
class MatrixWriter< Matrix, TNL::Devices::Host >
{
   public:

   typedef typename Matrix::IndexType IndexType;
   typedef typename Matrix::RealType RealType;

   static void writeGnuplot( const TNL::String& fileName,
                             const Matrix& matrix,
                             bool verbose = false );


   static void writeGnuplot( std::ostream& str,
                             const Matrix& matrix,
                             bool verbose = false );

   static void writeEps( const TNL::String& fileName,
                         const Matrix& matrix,
                         bool verbose = false );

   static void writeEps( std::ostream& str,
                         const Matrix& matrix,
                         bool verbose = false );

   static void writeMtx( const TNL::String& fileName,
                         const Matrix& matrix,
                         bool verbose = false );

   static void writeMtx( std::ostream& str,
                         const Matrix& matrix,
                         bool verbose = false );

   protected:

   static void writeEpsHeader( std::ostream& str,
                               const Matrix& matrix,
                               const int elementSize );

   static void writeEpsBody( std::ostream& str,
                             const Matrix& matrix,
                             const int elementSize,
                             bool verbose );
};
/// \endcond

} // namespace Matrices
} // namespace TNL

#include <TNL/Matrices/MatrixWriter.hpp>
