/***************************************************************************
**                                                                        **
**  GridView, a simple GridView made with Qt4                             **
**  Copyright (C) 2013 Sacha Schutz                                       **
**                                                                        **
**  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 3 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, see http://www.gnu.org/licenses/.   **
**                                                                        **
****************************************************************************
**           Author : Sacha Schutz                                        **
**           Website: http://www.labsquare.org                            **
**           Email  : sacha@labsquare.org                                 **
**           Date   : 12.03.12                                            **
****************************************************************************/

#ifndef GRIDVIEW_H
#define GRIDVIEW_H

#include <QtGui>
#include <QWidget>
#include <QScrollArea>
#include <QVector>

class GridWidget;

///
/// GridWidget:
/// Shows a GridView without scrolling. If you want to have Scroll option, use
/// GridView instead. GridWidget also supports mouse selection, sends the signal
/// cellClicked with the associated grid coordinates.
///
class GridWidget : public QWidget
{
    Q_OBJECT
public:

    /// \fn GridWidget::GridWidget(int rowCount, int columnCount, QWidget *parent):
    /// \~English
    /// \brief Constructor which receives the number of rows and columns in the grid
    /// \param rowCount number of rows in the grid
    /// \param columnCount number of columns in the grid
    /// \param parent parent window
    /// \~English
    /// \brief Constructor que recibe el numero de filas y columnas en la cuadricula
    /// \param rowCount numero de filas en la cuadricula
    /// \param columnCount numero de columnas en la cuadricula
    /// \param parent ventana padre
    explicit GridWidget(int rowCount = 100, int columnCount =100,QWidget *parent = 0);

    /// \fn GridWidget::GridWidget(QWidget *parent)
    /// \~English
    /// \brief Default constructor. The properties of the grid are set as follows:
    ///* mCellSize: Sets the size of the cell to 10px
    ///* mRowCount: Sets the number of rows in the grid to 39
    ///* mColumnCount: Sets the number of columns in the grid to 27
    ///* Tool and ToolSize: Sets the Tool which is going to be used to draw the grid
    ///* frontColor: The color which will be used to paint to black
    ///* backColor: Current clicked square
    ///* background: Sets the background color to white
    /// \~English
    /// \brief Constructor por defecto. Las propiedades de el grid se ajustan como sigue:
    /// * mCellSize: Ajusta el tamano de la celda a 10px
    /// * mRowCount: Ajusta el numero de filas en la cuadricula a 39
    /// * ColumnCount: Ajusta el numero de columnas en el grid a 27
    /// * Tool and ToolSize: Ajusta la herramiento que se va a utilizar para dibujar
    /// el grid.
    /// * frontColor: El color que se utilizara para pintar a negro
    /// * backColor: Cuadrado marcado actualmente
    /// * background: El color del fondo en blanco
    GridWidget(QWidget *parent);

    /// \fn void GridWidget::setGridSize(int rowCount, int columnCount)
    /// \~English
    /// \brief Sets the number of columns and rows of the grid
    /// \param rowCount number of rows
    /// \param columnCount number of columns
    /// \~Spanish
    /// \brief Ajusta el numero de columnas y fileas de la cuadricula
    /// \param rowCount numero de filas
    /// \param columnCount numero de columnas
    void setGridSize(int rowCount, int columnCount);

    /// \fn void GridWidget::switchOn(int x, int y, const QColor &color)
    /// \~English
    /// \brief Saves the given color and position in the vector
    /// that represents the painted cells of the grid
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param color color to paint cell
    /// \~Spanish
    /// \brief Guarda el color y la posicion dados en el vector que
    /// representa las celdas pintadas en la cuadricula
    /// \param x coordenada x de la celda en el cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param color color to paint cell
    void switchOn(int x,int y, const QColor& color);

    /// \fn QColor GridWidget::getCellColor(int x, int y) ;
    /// \~English
    /// \brief Returns the color of the cell in position (x,y)
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \return the color of the cell
    /// \~Spanish
    /// \brief Devuelve el color de la celda en la posicion (x,y)
    /// \param x coordenada x de la celda en el cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \return el color de la celda
    QColor getCellColor(int x, int y) ;


    /// \fn void GridWidget::switchOff(int x, int y)
    /// \~English
    /// \brief Removes the given position from the vector that
    /// represents the painted cells of the grid
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \~Spanish
    /// \brief Remueve la posicion dada del vector que representa
    /// las celdas pintadas en la cuadricula
    /// \param x coordenada x de la celda en el cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    void switchOff(int x, int y);


    /// \fn int GridWidget::getGridColumns() ;
    /// \~English
    /// \brief Returns the number of columns in the grid
    /// \return number of columns in the grid
    /// \~Spanish
    /// \brief Devuelve el numero de columnas en la cuadricula
    /// \return el numero de columnas en la cuadricula
    int getGridColumns() ;

    /// \fn int GridWidget::getGridRows() ;
    /// \~English
    /// \brief Returns the number of rows in the grid
    /// \return number of rows in the grid
    /// \~Spanish
    /// \brief Devuelve el numero de filas en la cuadricula
    /// \return el numero de filas en la cuadricula
    int getGridRows() ;

    /// \fn void GridWidget::clear()
    /// \~English
    /// \brief Clears the grid and sets it to its initial state
    /// \~Spanish
    /// \brief Limpa la cuadricula y la pone en su estado inicial.
    void clear();

    /// \fn void GridWidget::setCellSize(int size)
    /// \~English
    /// \brief Sets the size of the cells in the grid
    /// \param size cell size
    /// \~Spanish
    /// \brief Ajusta el tamano de las celdas de la cuadricula
    /// \param size tamano de la celda
    void setCellSize(int size);

    /// \fn void GridWidget::setTool(QString tool)
    /// \~English
    /// \param tool choosen tool
    /// \brief Sets the tool
    /// \param tool herramienta escogida
    /// \~Spanish
    /// \brief Ajusta la herramienta
    void setTool(QString tool);

    /// \fn void GridWidget::setFront(QString front)
    /// \~English
    /// \brief Sets the color of the brush
    /// \param front brush color
    /// \~Spanish
    /// \brief Ajusta el color de la brocha
    /// \param front color de la brocha
    void setFront(QString front);

    /// \fn void GridWidget::setBack(QString back)
    /// \~English
    /// \brief Sets the color of the background
    /// \param back background color
    /// \~Spanish
    /// \brief Ajusta el color del fondo
    /// \param back color para el fondo
    void setBack(QString back);

    /// \fn void GridWidget::setToolSize(int size)
    /// \~English
    /// \brief Sets the size of the tool
    /// \param size tool size
    /// \~Spanish
    /// \brief Ajusta el tamano de la herramienta
    /// \param size tamano de la herramienta
    void setToolSize(int size);

    /// \fn void GridWidget::identifyTool(QString tool, int x, int y)
    /// \~English
    /// \brief This function is called on each mousePressEvent inside the grid.
    /// It identifies the way the grid will be painted calling the function of the
    /// tool received in the parameters (dot, rowfill, column fill, diagonal, square,
    /// triangles and circles).
    /// \param tool the tool to be called by the funtion
    /// \param x coordinate x of the cell in the grid.
    /// \param y coordinate y of the cell in the grid.
    /// \~Spanish
    /// \brief Esta funcion es llamada en cada evento de el mouse presionado dentro
    /// de la cuadricula.  Identifica la forma en que el grid va a ser pintado llamando
    /// la funcion del tool recibido en los parametros (dot, rowfill, column fill, diagonal, square,
    /// triangles and circles).
    /// \param tool la herramienta a llamar por la funcion
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celde en la cuadricula
    void identifyTool(QString tool, int x, int y);

    /// \fn void GridWidget::Dot(int x, int y, QColor toolColor)
    /// \~English
    /// \brief Receives the coordinates of the grid where the user clicked
    /// and paints that cell with the color of the tool.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param toolColor color of the cells painted by the tool
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco
    /// y pinta la celda con el color del tool
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param toolColor color de las celdas pintadas por el tool
    void Dot(int x, int y, QColor colorSelected);

    /// \fn void GridWidget::RowMajorFill(int x, int y, QColor colorClicked, QColor toolColor, int cols)
    /// \~English
    /// \brief Receives the coordinates of the grid where the user clicked
    /// and paints (from that point left and right) the longest row of the same color
    /// of the cell that was clicked with the color of the tool.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param colorClicked current color of the clicked cell
    /// \param toolColor color of the cells painted by the tool
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco
    /// y pinta (desde ese punto hacia la izq o derecha) la fila mas larga del mismo color
    /// de la celda que fue marcada con el color de la herramienta.
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param colorClicked el color de la celda marcada
    /// \param toolColor color de las celdas pintadas por el tool
    void RowMajorFill(int x, int y, QColor colorClicked, QColor toolColor);

    /// \fn void GridWidget::ColMajorFill(int x, int y, QColor colorClicked, QColor toolColor)
    /// \~English
    /// \brief Receives the coordinates of the grid where the user clicked
    /// and paints (from that point up and down) the longest column of the same color
    /// of the cell that was clicked with the color of the tool.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param colorClicked current color of the clicked cell
    /// \param toolColor color of the cells painted by the tool
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco
    /// y pinta (desde ese punto hacia la arriba o abajo) la columna mas larga del mismo color
    /// de la celda que fue marcada con el color de la herramienta.
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param colorClicked el color de la celda marcada
    /// \param toolColor color de las celdas pintadas por el tool
    void ColMajorFill(int x, int y, QColor colorClicked, QColor toolColor);

    /// \fn void GridWidget::DiagonalLeft(int x, int y, QColor colorClicked, QColor toolColor)
    /// \~English
    /// \brief Recieves the coordinates of the grid where the user clicked
    /// and paints (from that point) the longest left-diagonal of the color
    /// of the cell that was clicked with the color of the tool.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param colorClicked current color of the clicked cell
    /// \param toolColor color of the cells painted by the tool
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco
    /// y pinta (desde ese punto diagonal) la diagonal izquierda mas larga del mismo color
    /// de la celda que fue marcada con el color de la herramienta.
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param colorClicked el color de la celda marcada
    /// \param toolColor color de las celdas pintadas por el tool
    void DiagonalLeft(int x, int y, QColor colorClicked, QColor toolColor);

    /// \fn void GridWidget::DiagonalRight(int x, int y, QColor colorClicked, QColor toolColor)
    /// \~English
    /// \brief Recieves the coordinates of the grid where the user clicked
    /// and paints (from that point) the longest right-diagonal of the color
    /// of the cell that was clicked with the color of the tool.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param colorClicked current color of the clicked cell
    /// \param toolColor color of the cells painted by the tool
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco
    /// y pinta (desde ese punto diagonal) la diagonal derecha mas larga del mismo color
    /// de la celda que fue marcada con el color de la herramienta.
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param colorClicked el color de la celda marcada
    /// \param toolColor color de las celdas pintadas por el tool
    void DiagonalRight(int x, int y, QColor colorClicked, QColor toolColor);

    /// \fn void GridWidget::square(int x, int y, QColor toolColor, int toolSize)
    /// \~English
    /// \brief Receives the coordinates of the grid where the user clicked
    /// and paints a square of the size and with the color of the tool.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param toolColor color of the cells painted by the tool
    /// \param toolSize size of the tool to be painted
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco
    /// y pinta un cuadrado de el tamano y color de la herramienta.
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param toolColor color de las celdas pintadas por el tool
    /// \param toolSize tamano de la herramienta a ser pintada
    void square(int x, int y, QColor toolColor, int toolSize);

    /// \fn void GridWidget::triangle(int x, int y, QColor toolColor, int toolSize)
    /// \~English
    /// \brief Receives the coordinates of the grid where the user clicked
    /// and paints a triangle of the size and with the color of the tool.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param toolColor color of the cells painted by the tool
    /// \param toolSize size of the tool to be painted
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco
    /// y pinta un triangulo de el tamano y color de la herramienta.
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param toolColor color de las celdas pintadas por el tool
    /// \param toolSize tamano de la herramienta a ser pintada
    void triangle(int x, int y, QColor toolColor, int toolSize);

    /// \fn void GridWidget::circle(int x, int y, QColor toolColor, int toolSize)
    /// \~English
    /// \brief Receives the coordinates of the grid where the user clicked
    /// and paints a circle of the size and with the color of the tool.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param toolColor color of the cells painted by the tool
    /// \param toolSize size of the tool to be painted
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco
    /// y pinta un circulo de el tamano y color de la herramienta.
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param toolColor color de las celdas pintadas por el tool
    /// \param toolSize tamano de la herramienta a ser pintada
    void circle(int x, int y, QColor toolColor, int toolSize);

    /// \fn void GridWidget::undo()
    /// \~English
    /// \brief When the undo button is pressed the current state is pushed into
    /// the redo vector(newStates) and the last state in the undo vector(oldStates)
    /// is painted on the grid.
    /// \~Spanish
    /// \brief Cuando el boton es apretado el estado acutual es empujado en
    /// el vector(newStates) de redo y el ultimo estado en el vector(oldStates) undo es
    /// pintado en la cuadricula
    void undo();


    /// \fn void GridWidget::redo()
    /// \~English
    /// \brief When the redo button is pressed the current state is pushed into
    /// the undo vector(oldStates) and the last state in the redo vector(newStates)
    /// is painted on the grid.
    /// \~Spanish Cuando el boton redo es marcado el estado actual es empujado en
    /// el vector(oldStates) undo y el ultimo estado en el vector redo(newStates) es
    /// pintaod en el grid.
    void redo();

    /// \fn void GridWidget::flood_fill(int x, int y, QColor toolColor, QColor ColorClicked)
    /// \~English
    /// \brief Receives the coordinates of the grid where the user clicked
    /// and floods the grid with the color selected.
    /// \param x coordinate x of the cell in the grid
    /// \param y coordinate y of the cell in the grid
    /// \param toolColor color of the cell painted by the tool
    /// \param ColorClicked current color of the clicked cell
    /// \~Spanish
    /// \brief Recibe las coordenadas de la cuadricula donde el usuario marco e
    /// inunda la cuadricula del color seleccionado
    /// \param x coordenada x de la celda en la cuadricula
    /// \param y coordenada y de la celda en la cuadricula
    /// \param toolColor color de las celdas pintadas por el tool
    /// \param ColorClicked el color de la celda marcada
    void flood_fill(int x, int y, QColor toolcolor, QColor ColorClicked);

protected:

    /// \fn void GridWidget::drawGrid(QPaintDevice *device)
    /// \~English
    /// \brief Function that first sets the size of the GridWidget, then paints the cells
    /// with the color selected for the background and finally paints
    /// the lines to form the grid.
    /// \param device the panel to paint the grid
    /// \~Spanish
    /// \brief Funcion que primero ajusta el tamano del widget de la cuadricula, luego pinta
    /// las celdas con el color seleccionado en el background y finalmente pinta las lineas
    /// para formar el grid.
    /// \param device el panel para pintar la cuadricula
    void drawGrid(QPaintDevice * device);

    /// \fn void GridWidget::paintEvent(QPaintEvent *event)
    /// \~English
    /// \brief This function is automatically invoked each time the widget or
    /// its parent receives a repaint signal.
    /// \param event received event reference
    /// \~Spanish
    /// \brief Esta funcion es invocada automaticmente cada ves que el widget o
    /// el padre recibe una senal de repintar.
    /// \param event referencia a un evento recibido
    virtual void paintEvent(QPaintEvent *);

    /// \fn void GridWidget::mousePressEvent(QMouseEvent * event)
    /// \~English
    /// \brief When the mouse is clicked on a cell of the grid it gets the x,y
    /// coordinates of the mouse and uses them to paint the tool at that
    /// location.
    /// \param event received event reference
    /// \~Spanish
    /// \brief Cuando el raton (mouse) is marcada en una celda de la cuadricula
    /// obtiene las coordenadas x, y del raton y los usa para pintar la herramienta en
    /// ese lugar.
    virtual void mousePressEvent(QMouseEvent *);

signals:

    void cellClicked(QPoint pos);

    void canUndo(bool can);

    void canRedo(bool can);

private:

    int mCellSize; /**< cell size / tamano del la celda*/

    int mRowCount; /**< row number / numero de filas*/

    int mColumnCount; /**< column number / numero de columnas */

    QPixmap mGridPix; /**< to paint the grid / para pintar la cuadricula */

    QHash<int, QColor > mColors; /**< Hash of colors with  the painted cells and their colors
                                    / Hash de colores con las celdas pintadas y sus colores */

    QString Tool; /**< name of the tool selected / nombre de la herramienta seleccionada */

    int ToolSize; /**< tool size / tamano del a herramienta */

    QColor frontColor; /**< color of the front cell / color de la celda de frente */

    QColor backColor; /**< background color of the cell / color del fondo de la celda */

    QColor background; /**< cell size / tamano del la celda */

    QVector < QHash<int, QColor > > oldStates; /**< vetor to implement undo/redo */

    QVector < QHash<int, QColor > > newStates; /**< vector to implement undo/redo */

};
#endif // GRIDVIEW_H
