/***************************************************************************
 *   Copyright (C) 2003-2005, 2006 by Carsten Niehaus                            *
 *   cniehaus@kde.org                                                      *
 *                                                                         *
 *   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 "periodictableview.h"
#include "prefs.h"
#include "element.h"
#include "kalziumutils.h"
#include "kalziumdataobject.h"
#include "kalziumpainter.h"
#include "kalziumtabletype.h"

#include <klocale.h>
#include <kdebug.h>

#include <QApplication>
#include <QPixmap>
#include <QPoint>
#include <QCursor>
#include <QMouseEvent>
#include <QPainter>
#include <QRect>
#include <QDrag>
#include <QSvgGenerator>

PeriodicTableView::PeriodicTableView( QWidget *parent )
  : QWidget( parent )
{
    // No selection
    m_currentElement = 0;

    setMouseTracking( true );

    //eliminates flicker on redraw
    setAttribute( Qt::WA_OpaquePaintEvent, true );

    table = 0;
    table2 = new QPixmap();

    //Start with a full draw
    doFullDraw = true;

    m_startDrag = QPoint();

    m_hoverTimer.setSingleShot( true );
    connect( &m_hoverTimer, SIGNAL( timeout() ), this, SLOT( slotMouseover() ) );
    m_prevHoverElement = 0;

    KalziumTableType *tt = KalziumTableTypeFactory::instance()->build( "Short" );
    m_painter = new KalziumPainter( tt );

    setMinimumSize( tt->size() );

    update();
}

PeriodicTableView::~PeriodicTableView()
{
	delete table;
	delete table2;

	delete m_painter;
}

void PeriodicTableView::activateColorScheme( const int nr )
{
    m_painter->setScheme( nr );

    emit SchemeChanged( m_painter->scheme() ); 

    setFullDraw();
    update();
}

KalziumSchemeType* PeriodicTableView::scheme() const
{
	return m_painter->scheme();
}

void PeriodicTableView::setMode( KalziumPainter::MODE m )
{
	m_painter->setMode( m );

    emit ModeChanged( m );

	setFullDraw();
	update();
}

KalziumPainter::MODE PeriodicTableView::mode() const
{
	return m_painter->mode();
}

void PeriodicTableView::generateSvg(const QString& filename)
{
        QSvgGenerator *svgGen = new QSvgGenerator();

        svgGen->setFileName( filename );

        m_painter->begin( svgGen );
        m_painter->drawAll();
        m_painter->end();
        delete svgGen;
}

void PeriodicTableView::paintEvent( QPaintEvent * e )
{
	if ( doFullDraw )
	{
		delete table;
		table = new QPixmap( size() );

		m_painter->begin( table );
		m_painter->drawAll();
		m_painter->end();

		doFullDraw = false;
	}

	*table2 = *table;

	if ( m_currentElement > 0 )
	{
		m_painter->begin( table2 );
		m_painter->drawElementSelector( m_currentElement );
		m_painter->end();
	}

	QPainter p( this );
	p.drawPixmap( e->rect().topLeft(), *table2, e->rect() );
	p.end();
}

void PeriodicTableView::mousePressEvent( QMouseEvent * event )
{
	int elementnumber = m_painter->currentTableType()->elementAtCoords( event->pos() );
	
	if ( ( elementnumber > 0 ) && ( event->button() == Qt::LeftButton ) )
	{
		m_startDrag = event->pos();
	}
}

void PeriodicTableView::mouseMoveEvent( QMouseEvent *event )
{
	int num = m_painter->currentTableType()->elementAtCoords( m_startDrag );

	if ( ( QApplication::mouseButtons() & Qt::LeftButton ) && ( ( event->pos() - m_startDrag ).manhattanLength() > QApplication::startDragDistance() ) && ( num > 0 ) )
	{
		Element* pointedElement = KalziumDataObject::instance()->element( num );

		QDrag *drag = new QDrag( this );
		QMimeData *mimeData = new QMimeData;

		mimeData->setText( pointedElement->dataAsString( ChemicalDataObject::name ) );
		drag->setMimeData( mimeData );

		QRect elrect = m_painter->currentTableType()->elementRect( num );
		elrect.translate( -elrect.topLeft() );
		QPixmap pix( elrect.size() + QSize( 1, 1 ) );
		pix.fill( palette().color( QPalette::Window ) );
		m_painter->begin( &pix );
		m_painter->drawElement( num, elrect );
		m_painter->end();

		drag->setPixmap( pix );

		drag->start( Qt::CopyAction | Qt::MoveAction );

		m_startDrag = QPoint();
	}
	else
	{
		if ( m_hoverTimer.isActive() )
			m_hoverTimer.stop();
		m_hoverTimer.start( 200 );
	}
}

void PeriodicTableView::mouseReleaseEvent( QMouseEvent *mouse )
{
	int elem = m_painter->currentTableType()->elementAtCoords( mouse->pos() );
	if ( elem > 0 )
	{
		emit ElementClicked( elem );
		selectElement( elem );
	}
	else
		unSelect();
}

void PeriodicTableView::unSelect()
{
	m_currentElement = 0;
	update();
}

void PeriodicTableView::selectPoint( const QPoint& point )
{
	m_painter->currentTableType()->elementAtCoords( point );
}

void PeriodicTableView::selectElement( int num )
{
	m_currentElement = num;
	update();
}

void PeriodicTableView::setValueLimit( int value, ChemicalDataObject::BlueObelisk type )
{
	//remove the value of the type if possible
	m_sliderValueList.remove( type );

	//now add the new type/value
	m_sliderValueList.insert( type, value );
}

int PeriodicTableView::sliderValue( ChemicalDataObject::BlueObelisk type )
{
	return m_sliderValueList.contains( type ) ? m_sliderValueList.value( type ) : 0;
}

QBrush PeriodicTableView::brushForElement( int element ) const
{
	return m_painter->brushForElement( element );
}

KalziumTableType* PeriodicTableView::tableType() const
{
	return m_painter->currentTableType();
}

void PeriodicTableView::slotChangeTable(int table)
{
    KalziumTableType *tt = KalziumTableTypeFactory::instance()->build( table );
    m_painter->setTableType(tt);

    emit TableTypeChanged( tt );

    setMinimumSize( tt->size() );
    setFullDraw();
    update();
}

void PeriodicTableView::slotMouseover()
{
	int num = m_painter->currentTableType()->elementAtCoords( mapFromGlobal( QCursor::pos() ) );
	if ( ( num > 0 ) && ( num != m_prevHoverElement ) )
		emit MouseOver( num );
	m_prevHoverElement = num;
}

void PeriodicTableView::setNumeration( int which )
{
	m_painter->setNumeration( which );
	setFullDraw();
	update();
}

KalziumGradientType* PeriodicTableView::gradient() const
{
	return m_painter->gradient();
}

void PeriodicTableView::setGradient( int which )
{
    m_painter->setGradient( which );

    emit GradientTypeChanged( m_painter->gradient() );
    setFullDraw();
    update();
}

void PeriodicTableView::setTemperature( int temp )
{
	m_painter->setTemperature( temp );
	setFullDraw();
	update();
}

void PeriodicTableView::setTime( int time )
{
	m_painter->setTime( time );
	setFullDraw();
	update();
}

void PeriodicTableView::setFullDraw()
{
	doFullDraw = true;
}

#include "periodictableview.moc"
