/******************************************************************************
 *
 * Project:  OpenCPN
 * Purpose:  OpenCPN Route table printout
 * Author:   Pavel Saviankou
 *
 ***************************************************************************
 *   Copyright (C) 2010 by David S. Register                               *
 *                                                                         *
 *   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 2 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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
 ***************************************************************************
 *
 *
 */
#include <iostream>
#include <vector>

#ifndef __PRINTTABLE_H__
#define __PRINTTABLE_H__

#include <wx/print.h>
#include <wx/datetime.h>
#include <wx/cmdline.h>
#include <wx/string.h>
#ifdef __WXMSW__
#include <wx/msw/private.h>
#endif

#include "ocpn_types.h"
#include "navutil.h"

/**
 * \brief
 *  Enumeration is used to notice the state of the table.
 *
 *  Different states are used to signalize different semanic of the data in
 *  the operator << of the class Table.
 *  If the state is "setup columns widths" -> then the data is used to store
 *  the width of the columns.
 *  If the state is "fill with data" -> then the data is the cell content.
 */
enum TableState { TABLE_SETUP_WIDTHS = 0, TABLE_FILL_DATA, TABLE_FILL_HEADER };


/**
 *  \brief Represents a NxM simple table with captions.
 *
 *  Input operator is "<<"
 *  Number of columns and rows are given dynamically by the input data.
 *  Captions are given by first input line.
 *  Every cell is given column by column.
 *  Next row is given by "<< '\n'" (or << endl)
 *
 *
 *
 */
class Table {
protected:
    int nrows;
    int ncols;

    bool create_next_row;

    std::vector< std::vector < wxString > > data;
    std::vector< double > widths;
    std::vector< wxString > header;
    TableState state;

    void Start();

    void NewRow();

public:
    Table();
    ~Table();

    Table& operator<<( const int& );
    Table& operator<<( const double& );
    Table& operator<<( const wxString& );

    std::vector< std::vector < wxString > > & GetData()
    {
        return data;
    };

    void StartFillData()
    {
        state = TABLE_FILL_DATA;
    };

    void StartFillHeader()
    {
        state = TABLE_FILL_HEADER;
    };

    void StartFillWidths()
    {
        state = TABLE_SETUP_WIDTHS;
    };

    int GetRowHeight( int i )
    {
        return widths[ i ];
    };
};

std::ostream& operator<<( std::ostream&,
            Table& );



/**
 *  \brief This class takes multilined string and modifies it to fit into given width
 *         for given device. If it is too wide for given DC (by class PrintTable )
 *        it introduces new lines between words
 *
 */

class PrintCell {
protected:
    // Copy of printing device
    wxDC* dc;

    // Target width
    int width;

    // Target height
    int height;

    // Cellpadding
    int cellpadding;

    // Content of a cell
    wxString content;

    // Result of modification
    wxString modified_content;

    // Rect for printing of modified string
    wxRect rect;

    // Stores page, where this cell will be printed
    int page;

    // Stores, if one has to ovveride property "weight" of the font with the value "bold" - used to print header of the table.
    bool bold_font;


    // Adjust text
    void Adjust();


public:

    // Constructor with content to print and device
    PrintCell ()
    {
    };

    // Constructor with content to print and device
    void Init( const wxString& _content,
          wxDC*           _dc,
          int             _width,
          int             _cellpadding,
          bool            bold_font = false );

    // Returns rect for printing
    wxRect GetRect()
    {
        return rect;
    };

    // Returns modified cell content
    wxString GetText()
    {
        return modified_content;
    };

    // Returns height of the cell
    int GetHeight()
    {
        return height;
    };

    // Returns width of the cell
    int GetWidth()
    {
        return width;
    };

    // sets the page to print
    void SetPage( int _page )
    {
        page = _page;
    };

    // sets the height
    void SetHeight( int _height )
    {
        height = _height;
    };

    // Returns the page, where this element should be painted
    int GetPage()
    {
        return page;
    };
};



/**
 *  \brief Extension of a class Table with printing into dc.
 *
 *   It takes all elements, takes DC as a printing device, takes  a maximal
 *   possible table width,  calculate width of every column.
 *   For printing of every cell it modifies its content so, that it fits into cell by inserting
 *   new lines.
 *
 */
class PrintTable : public Table {
protected:
    std::vector< std::vector < PrintCell > > contents;
    std::vector < PrintCell >           header_content;
    std::vector< int >                  rows_heights;
    int                            header_height;


    int number_of_pages;                // stores the number of pages for printing of this table. It is set by AdjustCells(...)

public:
    PrintTable();

    // creates internally std::vector of PrintCell's, to calculate columns widths and row sizes
    void AdjustCells( wxDC* _dc,
                 int   marginX,
                 int   marginY );

    // delivers content of the table
    std::vector< std::vector < PrintCell > >& GetContent()
    {
        return contents;
    };
    // delivers header  of the table
    std::vector < PrintCell > & GetHeader()
    {
        return header_content;
    };
    // returns the total number of needed pages;
    int GetNumberPages()
    {
        return number_of_pages;
    };

    // Returns the height of the header
    int GetHeaderHeight()
    {
        return header_height;
    };
};
#endif
