#ifndef CONTAINER_DUMP_TOOL
#define CONTAINER_DUMP_TOOL

/**  print the title and column headers.
 *   the class is a part of the method "dump".
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
class OutputTypeTitle {

    public:
        OutputTypeTitle() {};
        ~OutputTypeTitle() {};

        // titile
        void title(const UInt4 indentWidth, const type_info& info) {
            if (indentWidth > 0) {
                std::cout << std::setw(indentWidth) << " ";
            }
            if (info == typeid(Bool)) {
                std::cout << "Bool";
            } else if (info == typeid(Int4)) {
                std::cout << "Int4";
            } else if (info == typeid(UInt4) ) {
                std::cout << "UInt4";
            } else if (info == typeid(Double) ) {
                std::cout << "Double";
            //} else if (info == typeid(PeakData) ) {
            //    std::cout << "PeakData";
            } else if (info == typeid(std::vector< Double >)) {
                std::cout << "std::vector<Double>";
            //} else if (info == typeid(std::vector< FuncBase* >)) {
            //    std::cout << "std::vector<Double>";
            } else if (info == typeid(std::vector< std::vector< Double > >)) {
                std::cout << "std::vector< std::vector<Double> >";
            //} else if (info == typeid(std::vector< std::vector< FuncBase* > >)) {
            //    std::cout << "std::vector< std::vector<FuncBase*> >";
            }
            std::cout << " type parameter(s)" << std::endl;
        };

        // print column header
        void header(const UInt4 indentWidth, const UInt4 maxKeyWidth, const std::string& keyTitle, const UInt4 maxSizeWidth, const std::string& sizeTitle, const std::string& valueTitle) {
            std::cout << std::setw(indentWidth) << " ";
            // print keyTitle left-aligned
            std::cout << keyTitle;
            if (maxKeyWidth - keyTitle.size() > 0) {

                std::cout << std::setw(maxKeyWidth-keyTitle.size()) << " ";
            }
            if (maxSizeWidth > 0) {
                std::cout << " ";
                // print sizeTitle left-aligned
                std::cout << sizeTitle;
                if (maxSizeWidth - sizeTitle.size() > 0) {
                    std::cout << std::setw(maxSizeWidth-sizeTitle.size()) << " ";
                }
            }
            std::cout << " ";
            // print valueTitle left-aligned
            std::cout << valueTitle;
            std::cout << std::endl;
        };
};

/** print a key left-aligned in the specified width.
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
struct OutputKey {
    public:
        void operator() (const UInt4 maxKeyWidth, const std::string& key) {
            std::cout << key;
            if ( maxKeyWidth - key.size() > 0) {
                std::cout << std::setw(maxKeyWidth - key.size()) << " ";
            }
        };
};

/** print the vector size right-aligned in the specified width.
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
struct OutputVectorSize {
    public:
        void operator() (const UInt4 maxSizeWidth, const UInt4 i) {
            std::cout << " " << std::setw(maxSizeWidth) << i;
        };
};

/** print the matrix size right-aligned in the specified width.
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
struct OutputMatrixSize {
    public:
        void operator() (const UInt4 maxRowWidth, const UInt4 rowSize, const UInt4 maxColWidth, const UInt4 colSize) {
            std::cout << " " << std::setw(maxRowWidth) << rowSize << "*" << std::setw(maxColWidth) << colSize;
        };
};

/** print a element of a vector or a matrix
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
template<typename _ELEMENT_TYPE>
struct OutputElement {
    void operator() ( _ELEMENT_TYPE value) {
           std::cout << " " << value;
    };
};

/** orint a row of a matrix
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
template<typename _ELEMENT_TYPE >
struct OutputRow {
    void operator() (const std::vector< _ELEMENT_TYPE >& row) {
        std::cout << "(";
        for_each(row.begin(), row.end(), OutputElement< _ELEMENT_TYPE >());
        std::cout << ")";
    };
};

/** print a scaler type entry.
 *  the class is a part of the method dump for a scaler container.
 *  pass to the for_each loop function.
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
template<typename _SCALER_TYPE >
class OutputScalerEntry {
    private:
       UInt4 indentWidth;
       UInt4 maxKeyWidth;

    public:
       OutputScalerEntry(const UInt4 indentWidth, const UInt4 maxKeyWidth) : indentWidth(indentWidth), maxKeyWidth(maxKeyWidth) { };
       ~OutputScalerEntry() {};

       void operator() (std::pair<const std::string, _SCALER_TYPE >& item) {
           
           std::cout << std::setw(indentWidth) << " ";
           std::cout << item.first;
           if (maxKeyWidth - item.first.size() > 0) {
               std::cout << std::setw(maxKeyWidth - item.first.size()) << " ";
           }
           std::cout << " ";
           std::cout << item.second;
           std::cout << std::endl;
       }
};

/** print a vector type entry.
 *  the class is a part of the method dump for a vector container.
 *  pass to the for_each loop function.
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
template<typename _ELEMENT_TYPE >
class OutputVectorEntry {
    private:
        size_t indentWidth;
        size_t maxKeyWidth;
        size_t maxSizeWidth;

    public:
        OutputVectorEntry(const UInt4 indentWidth, const UInt4 maxKeyWidth, const UInt4 maxSizeWidth) : indentWidth(indentWidth), maxKeyWidth(maxKeyWidth), maxSizeWidth(maxSizeWidth) {};
        ~OutputVectorEntry() {};

        void operator() (std::pair<const std::string, std::vector< _ELEMENT_TYPE > >& item ) {
            std::cout << std::setw(indentWidth) << " ";
            std::cout << item.first;
            if (maxKeyWidth - item.first.size() > 0) {
                std::cout << std::setw(maxKeyWidth - item.first.size()) << " ";
            }
            std::cout << " ";
            std::cout << std::setw(maxSizeWidth) << item.second.size();
            std::cout << " ";
            std::cout << "(";
            for_each(item.second.begin(), item.second.end(), OutputElement< _ELEMENT_TYPE >());
            std::cout << ")";
            std::cout << std::endl;
        };

};

/** print a matrix type entry.
 *  the class is a part of the method dump for a matrix (std::vector&gt; vecotr&gt; &lt; &lt;) container.
 *  pass to the for_each loop function.
 *
 *  print the key, the row size, the column size and elements of the matrix.
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.9
 */
template<typename _ELEMENT_TYPE>
class OutputMatrixEntry {
    private:
        size_t indentWidth;
        size_t maxKeyWidth;
        size_t maxRowWidth;
        size_t maxColWidth;

    public:
        OutputMatrixEntry< _ELEMENT_TYPE >(const UInt4 indentWidth, const UInt4 maxKeyWidth, const UInt4 maxRowWidth, const UInt4 maxColWidth) :
            indentWidth(indentWidth), maxKeyWidth(maxKeyWidth), maxRowWidth(maxRowWidth), maxColWidth(maxColWidth) {};

        ~OutputMatrixEntry< _ELEMENT_TYPE >() {};

        void operator() (const std::pair<const std::string, std::vector< std::vector< _ELEMENT_TYPE> > >& item) {
            std::cout << std::setw(indentWidth) << " ";
            std::cout << item.first;
            if ( maxKeyWidth - item.first.size() > 0) {
                std::cout << std::setw(maxKeyWidth - item.first.size()) << " ";
            }
            std::cout << " " << std::setw(maxRowWidth) << item.second.size() << "*" << std::setw(maxColWidth) << item.second.at(0).size();
            std::cout << " (";
            for_each(item.second.begin(), item.second.end(), OutputRow< _ELEMENT_TYPE >());
            std::cout << ")";
            std::cout << std::endl;
        };
        
};



#endif // CONTAINER_DUMP_TOOL
