#ifndef MATRIX_UTIL
#define MATRIX_UTIL

#include <vector>
#include <ostream>

#include "Header.hh"
#include "AdvMessage.hh"

#include "AdvVectorGSLVectorConv.hh"

/**
 *  Utility for Matrix
 *  
 *  @author  TANIMORI Souichirou
 *  @version 0.0
 */
class AdvMatrixUtil : public AdvVectorGSLVectorConv {
    public:
        /** output a matrix so as to pack as many elements as possible */
        void outputMatrix(std::ostream &os,
                          const UInt4 indentWidth, const std::vector< std::vector<Double> > &m,
                          const UInt4 rowFirst, const UInt4 nRow, const UInt4 colFirst, const UInt4 nCol,
                          const Bool fixForm, const UInt4 prec, const Bool withRowNo, const Bool withColNo,
                          const UInt4 lineLength) ;

        /** output a matrix with row headers */
        void outputMatrixWithUsersRowHeader(
                          std::ostream &os,
                          const UInt4 indentWidth, const std::vector< std::vector<Double> > &m, const std::vector<Int4> &rowNo,
                          const UInt4 rowFirst, const UInt4 nRow, const UInt4 colFirst, const UInt4 nCol,
                          const Bool fixForm, const UInt4 prec, const Bool withColNo, const UInt4 lineLength) ;

        /** output a matrix so as to pack as many elements as  psssible, for gsl_matrix */
        void outputMatrix(std::ostream &os,
                          const UInt4 indentWidth, const gsl_matrix *m,
                          const UInt4 rowFirst, const UInt4 nRow, const UInt4 colFirst, const UInt4 nCol,
                          const Bool fixForm, const UInt4 prec, const Bool withRowNo, const Bool withColNo,
                          const UInt4 lineLength) ;
        
        /** output a specified matrix with column headers, for gsl_matrix */
        void outputMatrixWithUsersRowHeader(
                          std::ostream &os,
                          const UInt4 indentWidth, const gsl_matrix *m, const std::vector<Int4> &rowNo,
                          const UInt4 rowFirst, const UInt4 nRow, const UInt4 colFirst, const UInt4 nCol,
                          const Bool fixForm, const UInt4 prec, const Bool withColNo, const UInt4 lineLength) ;
    private:
        /** the digits number for a integer */
        UInt4 digitNum(Int4  n);
        /** the digits number for a unsigned integer */
        UInt4 digitNum(UInt4 n);

        /** width per matrix element */
        UInt4 widthPerElement(const Bool fix, const UInt4 prec);

        /** outpur a header line for */
        void outpurHeaderLine(std::ostream &os,
                              const UInt4 indentWidth, const Bool wittRowNo,     const UInt4 rowNoWidth,
                              const UInt4 colMin,      const UInt4 nElemPerLine, const UInt4 widthPerElem) ;

        /** output column No. headers given by user */
        void outputUserHeader(std::ostream &os,
                              const UInt4 indentWidth, const Bool withRowNo, const UInt4 rowNoWidth,
                              const std::vector<Int4> &columnNo, const UInt4 form, const UInt4 nElemPerLine, const UInt4 widthElemCol) ;


        /** output n successive columns of a row of a matrix from the given column */
        void outputPartialRow(std::ostream &os,
                              const UInt4 indentWidth,   const Bool withRowNo,     const UInt4 widthRowNo,   const UInt4 rowNo,
                              const std::vector<Double> &row, const UInt4 colMin,       const UInt4 nElemPerLine,
                              const Bool fixForm,        const UInt4 widthElemCol, const Int4 prec) ;

        /** output specified columns of a matrix */
        void outputPartialMatrix(std::ostream &os,
                                  const std::vector< std::vector<Double> > &m, const UInt4 colMin, const UInt4 elemPerLine,
                                 const Bool fixForm, const UInt4 widthPerElem, const UInt4 prec,
                                 const Bool withRowNo, const UInt4 rowNoWidth, const Bool withColNo,
                                 const UInt4 indentWidth) ;


};
#endif // MATRIX_UTIL
