/***************************************************************************
 *   Copyright (C) 2005 by Tavarez Arnaud Bakoula                          *
 *   tbakoula@yahoo.fr                                                     *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "cellmanager.h"

#include "cell.h"
#include "cellrow.h"

#include <qdrawutil.h>
#include <iostream>

CellManager::CellManager( uint r, uint c, QWidget* parent, const char* name )
    :  QFrame( parent, name, WNoAutoErase ), row(r), col(c)
{
    margin = 4;
    read_only  = FALSE;
    dragging   = FALSE;
    delivered  = FALSE;
    dirty      = FALSE;
    active_ctr = 0;
    intern_ctr = 0;
    activeRow  = 0;
    m_showLabels = FALSE;
    m_showHLabel = FALSE;
    m_showVLabel = FALSE;
    hLabel = 0;
    vLabel = 0;

    showLabels( TRUE, TRUE );

    cellrow_list = new std::vector<CellRow*>();

}

CellManager::~CellManager()
{
    cellrow_iterator it = cellrow_list->begin();
    for ( ; it != cellrow_list->end() ; it++ )
      delete *it;

    delete cellrow_list;
    cellrow_list = 0;
    activeRow  = 0;
}

void CellManager::resizeEvent( QResizeEvent* )
{
    placeRows();
    refreshPixmap();
}
QSize
CellManager::minimumSizeHint() const
{
    int sz = Cell::getSize();
    int w = sz * col + 2 * margin + vLabel;
    int h = sz * row + 2 * margin + hLabel;
    return QSize( w, h );
}

QSize
CellManager::sizeHint() const
{
    int sz = Cell::getSize();
    int w = (sz + 2) * col + 2 * margin + vLabel;
    int h = sz * row + 2 * margin + hLabel;
    return QSize( w, h );
}

/**
   This function places all the rows of the widget
 */
void CellManager::placeRows()
{
    if ( cellrow_list->empty() )
      return;

    uint i=0;
    dirty = true;
    cellrow_iterator it = cellrow_list->begin();
    for ( ; it != cellrow_list->end(); it++, i++ )
    {
      (*it)->updateMe();
      computePosition( (*it), i );
      (*it)->placeCells();
    }
    setMinimumSize( sizeHint() );
}

/**
   This function computes the position of the specified row whose
   row index is \a r.
 */
void CellManager::computePosition( CellRow* cellrow, uint r )
{
    QPoint point;
    int hr = height() - 2*margin - hLabel;
    int hc = Cell::getSize();
    int space = int((hr - row*hc) / (row+1));
    int y = margin + space + r*(space + hc);

    point.setX( margin + vLabel );
    point.setY( y );

    cellrow->rect().moveTopLeft( point );
    cellrow->rect().setWidth( width() - 2*margin - vLabel );
}

/**
   This function is in charged of removing the specified number
   of rows. After this function has been called the widget must
   be repainted and resized so the appropriated form.
 */
void CellManager::removeCellRow( uint rm )
{
    if ( cellrow_list->empty() )
      return;

    uint i=0;
    for ( ; i < rm; i++ )
    {
       cellrow_list->pop_back();
    }
    row -= rm;
    setMinimumSize( sizeHint() );
    placeRows();
    // the widget must be redrawn
    refreshPixmap();
}

/**
   This function adds the specified number of cells. More
   precisely, it adds \a rm columns to each row.
 */
void CellManager::appendCells( uint ap )
{
    if ( cellrow_list->empty() )
      return;

    cellrow_iterator it = cellrow_list->begin();
    for ( ; it != cellrow_list->end() ; it++ )
    {
      (*it)->appendCells( ap );
    }
    col += ap;
    setMinimumSize( sizeHint() );
    placeRows();
    // the widget must be redrawn
    refreshPixmap();
}

/**
   This function removes the specified number of cells. More
   precisely, it removes the \a rm last columns of each row.
 */
void CellManager::removeCells( uint rm )
{
    if ( cellrow_list->empty() )
      return;

    cellrow_iterator it = cellrow_list->begin();
    for ( ; it != cellrow_list->end() ; it++ )
    {
      (*it)->removeCells( rm );
    }
    col -= rm;
    setMinimumSize( sizeHint() );
    placeRows();
    // the widget must be redrawn
    refreshPixmap();
}

/**
   Returns the cell at the specified (row=r, column=c).
 */
Cell*
CellManager::getCellAt( uint r, uint c )
{
    if ( cellrow_list->empty() )
      return 0;
    return getCellRowAt(r)->getCellAt(c);
}

/**
   Returns the row of cells whose index is \a idx.
 */
CellRow*
CellManager::getCellRowAt( uint idx )
{
    if ( cellrow_list->empty() )
      return 0;
    return cellrow_list->at( idx );
}

/**
   Returns the row of cells which is located at the specified
   coordinates.
 */
CellRow*
CellManager::getCellRowAt( int x, int y )
{
    if ( cellrow_list->empty() )
      return 0;

    cellrow_iterator it = cellrow_list->begin();
    for ( ; it != cellrow_list->end() ; it++ )
    {
       if ( (*it)->rect().contains( x, y ) )
         return (*it);
    }
    return 0;
}

CellRow*
CellManager::getCellRowAt( QPoint p )
{
    return getCellRowAt( p.x(), p.y() );
}

void CellManager::resetAll()
{
    dragging   = FALSE;
    delivered  = FALSE;
    active_ctr = 1;
    intern_ctr = 0;

    if ( cellrow_list->empty() )
      return;

    cellrow_iterator it = cellrow_list->begin();
    activeRow = cellrow_list->at( row-1);
    for ( ; it != cellrow_list->end() ; it++ )
    {
      (*it)->reset();
    }
    dirty = true;
    refreshPixmap();
}

void CellManager::nextRow()
{
    if ( active_ctr != row + 1 )
    {
      active_ctr++;
      activeRow = getCellRowAt( row - active_ctr );
      intern_ctr = 0;
    }
}

void CellManager::showReady()
{
    if ( activeRow )
    {
      activeRow->ready();
      dirty = true;
      refreshPixmap();
    }
}

void CellManager::paintEvent( QPaintEvent* )
{
    QPainter p(this);

    p.drawPixmap( contentsRect().topLeft(), my_pixmap );
    drawFrame( &p );
}

void CellManager::paintCellRow( CellRow* cellrow, QPainter* p )
{
    for ( uint i=0; i < col; i++ )
    {
      paintCell( cellrow->getCellAt(i), p );
    }
}

void CellManager::drawCellContent( QPainter* painter )
{
    if ( cellrow_list->empty() )
      return;

    cellrow_iterator it = cellrow_list->begin();
    for ( ; it != cellrow_list->end() ; it++ )
    {
      paintCellRow( (*it), painter );
    }
}

void CellManager::refreshPixmap()
{
    // use the double buffering method
    if ( dirty )
    {
      my_pixmap.resize( contentsRect().size() );
      my_pixmap.fill( this, contentsRect().topLeft() );
      QPainter painter( &my_pixmap, this );

      drawLabels( &painter );
      drawCellContent( &painter );
      repaint( contentsRect(), FALSE);

      dirty = false;
    }
}

/**
   This function is in charged of erasing the specified
   cell. So it repaints the background at the location of
   the cell.
 */
void CellManager::eraseCell( Cell* )
{
    // Draw the background pixmap where the cell is located
}

void CellManager::eraseCellRow( CellRow* cellrow )
{
    for ( uint i=0; i < col; i++ )
    {
      eraseCell( cellrow->getCellAt(i) );
    }
}

void CellManager::addItem()
{
    intern_ctr++;
    if ( intern_ctr == col )
      emit ready( TRUE );
}

void CellManager::delItem()
{
    if ( intern_ctr == col )
      emit ready( FALSE );
    intern_ctr--;
}

void CellManager::updateMe()
{
    dirty = true;
    refreshPixmap();
}

void CellManager::showLabels( bool b, bool link )
{
    m_showLabels = b;
    if ( link )
    {
      showHLabel( b );
      showVLabel( b );
      return;
    }

    hLabel = (m_showLabels && m_showHLabel) ? 22 : 0;
    vLabel = (m_showLabels && m_showVLabel) ? 22 : 0;
}

void CellManager::showHLabel( bool b )
{
    m_showHLabel = b;
    hLabel = b ? 22 : 0;
}

void CellManager::showVLabel( bool b )
{
    m_showVLabel = b;
    vLabel = b ? 22 : 0;
}


void CellManager::drawLabels( QPainter* p )
{
    if ( m_showLabels )
    {
      drawVLabel( p );
      drawHLabel( p );
    }
}

void CellManager::drawHLabel( QPainter* p )
{
    if ( m_showHLabel )
    {
      p->setPen( palette().active().background() );
      p->setBrush( palette().active().background() );
      p->drawRect( 0, height() - hLabel, width(), hLabel );
      qDrawShadeLine( p, 0, height() - hLabel,
                      width(), height() - hLabel,
                      palette().active(), FALSE, 1, 1 );
      for ( uint i=0; i<col; i++ )
      {
        int sz = Cell::getSize();
        int xPos = cellrow_list->at(row-1)->getCellAt( i )->rect().topLeft().x();
        QRect rect( xPos, height() - hLabel, sz, hLabel );
        p->setPen( palette().active().foreground() );
        p->drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter, QString::number( i+1 ) );
      }
    }
}

void CellManager::drawVLabel( QPainter* p )
{
    if ( m_showVLabel )
    {
      p->setPen( palette().active().background() );
      p->setBrush( palette().active().background() );
      p->drawRect( 0, 0, vLabel, height() );
      qDrawShadeLine( p, vLabel, 0, vLabel, height() - hLabel,
                      palette().active(), FALSE, 1, 1 );
      for ( uint j=0; j<row; j++ )
      {
        int sz = Cell::getSize();
        int yPos = getCellRowAt( j )->rect().topLeft().y();
        QRect rect( 0, yPos, vLabel, sz );
        p->setPen( palette().active().foreground() );
        p->drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter, QString::number( row-j ) );
      }
    }
}

#include "cellmanager.moc"
