/***************************************************************************
 *   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 "tickmanager.h"
#include "tick.h"
#include "tickrow.h"
#include "dragmark.h"
#include "utilities.h"

TickManager::TickManager( uint r, uint c, QWidget* parent, const char* name )
    :  CellManager( r, c, parent, name )
{
    activeCell = 0;
    showVLabel( FALSE );
    setMinimumSize( minimumSizeHint() );
    setAcceptDrops( TRUE );
}

TickManager::~TickManager()
{
    activeCell = 0;
}

/**
   This function must be called after the instanciation of the
   widget. So it will create the appropriate type of cells it
   has to manage.
 */
void TickManager::createRows()
{
    for ( uint i=0; i<row; i++ )
    {
      CellRow* cellrow = new TickRow( i, col );
      cellrow_list->push_back( cellrow );
      computePosition( cellrow, i );
      cellrow->createCells();
    }
    activeRow = (TickRow*) cellrow_list->at(row-1);
}

/**
   This function adds the specified number of rows.
 */
void TickManager::appendCellRow( uint ap )
{
    for ( uint i=0; i<ap; i++ )
    {
      CellRow* cellrow = new TickRow( row+i, col );
      cellrow_list->push_back( cellrow );
      computePosition( cellrow, row+i );
      cellrow->createCells();
    }
    row += ap;
    setMinimumSize( minimumSizeHint() );
    placeRows();
    // the widget must be redrawn
    refreshPixmap();
}

/**
   Installs the content of the row \a cellrow in the active row
   of this manager.
   The cellrow argument must be of type TickRow for the expected
   behaviour. If it is not the case there's no warranty on its
   behaviour.
 */
bool TickManager::installActiveRow( CellRow* cellrow )
{
    uint i;
    uint dim = activeRow->getDim();

    if( dim != cellrow->getDim() )
      return false;

    for ( i=0; i < dim; i++ )
    {
      Tick* tick1 = (Tick*) cellrow->getCellAt( i );
      Tick* tick2 = (Tick*) activeRow->getCellAt( i );
      tick2->setState( tick1->getState() );
    }
    dirty = true;
    refreshPixmap();
    return true;
}

/**
   This is an overload of the previous function.
   Use this function to specify the number \a black of well placed
   pieces in the combination and the number \a white of misplaced.
   So, there's no correspondance between the place of the mark
   and the place of the piece.
   If \a hard is true, the well placed piece are considered as
   misplaced.
 */
bool TickManager::installActiveRow( uint black, uint white, bool hard )
{
    uint i;
    uint dim = activeRow->getDim();

    if ( black + white > dim )
      return false;

    for ( i=0; i < black; i++ )
    {
      Tick* tick = (Tick*) activeRow->getCellAt( i );
      if ( hard )
        tick->setState( MISPLACED );
      else
        tick->setState( PLACED );
    }

    for ( i=black; i < (white + black); i++ )
    {
      Tick* tick = (Tick*) activeRow->getCellAt( i );
      tick->setState( MISPLACED );
    }
    dirty = true;
    refreshPixmap();
    return true;
}

void TickManager::paintCell( Cell* cell, QPainter* p )
{
    cell->draw( p, cell->rect().topLeft() );
}

void TickManager::drawReady( Cell* )
{
}

/**
 *  This reimplementation is used to start the displacement the tick of a cell
 *  to another one or to remove it.
 */
void TickManager::mousePressEvent( QMouseEvent* event )
{
    if ( read_only )
      return;

    delivered = FALSE;
    TickRow* cellrow = (TickRow*) getCellRowAt( event->x(), event->y() );

    if ( activeRow == cellrow )
    {
      activeCell = (Tick*) activeRow->getCellAt( event->x(), event->y() );
      if ( activeCell && !activeCell->isEmpty() )
      {
        dragging = TRUE;
      }
    }
}

void TickManager::mouseMoveEvent( QMouseEvent* )
{
    if ( read_only )
      return;

    if ( dragging /*activeCell*/ )
    {
      DragMark* d = new DragMark( activeCell->getState(), this, "mark" );
      d->setPixmap( stateToPixmap( activeCell->getState() ), QPoint(8,8) );
      d->dragMove();

      if ( !delivered )  // has it been delivered
      {
        activeCell->setState( ABSENT );
        activeCell->empty( TRUE );
        dirty = true;
        delItem();
        refreshPixmap();
      }
      activeCell = 0;
      dragging = FALSE;
    }
}

void TickManager::mouseReleaseEvent( QMouseEvent* )
{
    dragging = FALSE;
    activeCell = 0;
}

void TickManager::dragEnterEvent( QDragEnterEvent* event )
{
    if ( read_only )
      return;
    event->accept( DragMark::canDecode(event) );
}

void TickManager::dropEvent( QDropEvent* event )
{
    uint state;
    // where the mouse was it dropped ?
    int x = event->pos().x();
    int y = event->pos().y();
    // on which cellrow ?
    TickRow* cellrow = (TickRow*) getCellRowAt( x, y );

    if ( !DragMark::decode( event, state ) )
    {
      activeCell = 0;
      return;
    }

    // if the row is the active one we can
    // continue to process the event
    if ( cellrow && cellrow == activeRow )
    {
      // we retrieve the cell at the specified position
      Tick* cell = (Tick*) activeRow->getCellAt( x, y );

      // can the cell receive the drag ?
      if ( cell )
      {
        if ( cell->isEmpty() )
        {
          // the drag comes from another tick
          if( activeCell && cell != activeCell )
          {
            activeCell->setState( ABSENT );
            activeCell->empty( TRUE );
            delivered = TRUE;
            // the internal counter must NOT be modified
            // and the ready state must be displayed
          }
          else{ /* the internal counter MUST be modified*/
            addItem();
          }
          cell->setState( state );
          cell->empty( FALSE );
          // the cell must be drawn
          dirty = true;
          refreshPixmap();
        }
        else
        {
          // we cancel the operation
          delivered = TRUE;
        }
      }
      else if( !cell && activeCell )
      {
        // we want to remove the mark from the activeCell
        // cause we drag it on a invalid cell
        activeCell->setState( ABSENT );
        activeCell->empty( TRUE );
        dirty = true;
        refreshPixmap();
      }
    }
}
