/*
 * Copyright (c) 2007      Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
 *
 *  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 "outputgraphicsitem.h"
#include "randroutput.h"
#include "randr.h"

#include <QPen>
#include <QBrush>
#include <QFont>
#include <QGraphicsScene>
#include <KGlobalSettings>

OutputGraphicsItem::OutputGraphicsItem(RandROutput *output)
	: QGraphicsRectItem(output->rect())
{
	m_output = output;

	m_left = m_right = m_top = m_bottom = NULL;

	setPen(QPen(Qt::black));
	if(output->isActive())
		setBrush(QColor(0, 255, 0, 128));
	else setBrush(QColor(128, 128, 128, 0));

	setFlag(QGraphicsItem::ItemIsMovable, false);
	setFlag(QGraphicsItem::ItemIsSelectable, true);
	
	m_text = new QGraphicsTextItem( this );

	QFont font = KGlobalSettings::generalFont();
	font.setPixelSize(72);
	m_text->setFont(font);
    
	updateText();

}

OutputGraphicsItem::~OutputGraphicsItem()
{
	disconnect();
}

OutputGraphicsItem *OutputGraphicsItem::left() const
{
	return m_left;
}

OutputGraphicsItem *OutputGraphicsItem::right() const
{
	return m_right;
}

OutputGraphicsItem *OutputGraphicsItem::top() const
{
	return m_top;
}

OutputGraphicsItem *OutputGraphicsItem::bottom() const
{
	return m_bottom;
}

void OutputGraphicsItem::setTop(OutputGraphicsItem *output)
{
	// if we already have that output at top, then just return
	if (m_top == output)
	return;
   
   OutputGraphicsItem *oldTop = m_top;
   m_top = output;

   // if we currently have a top item, set the given item as the bottom of our old item
   if (oldTop)
	   oldTop->setBottom(output);

   // check whether we have a left->top or a right->top to update the pointers
   if (m_left && m_left->top())
   {
	   OutputGraphicsItem *item = m_left->top();
	   if (item->right())
	   qDebug("Oops, this should not happen");
	item->setRight(output);
	if (output)
		output->setLeft(item);
   }

   if (m_right && m_right->top())
   {
	   OutputGraphicsItem *item = m_right->top();
	   if (item->left())
	   qDebug("Oops, this should not happen");
	   item->setLeft(output);
	   if (output)
		   output->setRight(item);
   }
}

void OutputGraphicsItem::setBottom(OutputGraphicsItem *output)
{
	// if we already have that output at bottom, just return
	if (m_bottom == output)
	return;
   
   OutputGraphicsItem *oldBottom = m_bottom;
   m_bottom = output;

   // if we currently have a bottom item, set the given item as the top of our old item
   if (oldBottom)
	oldBottom->setTop(output);

   // check whether we have a left->bottom or a right->bottom to update the pointers
   if (m_left && m_left->bottom())
   {
	   OutputGraphicsItem *item = m_left->bottom();
	   if (item->right())
	   qDebug("Oops, this should not happen");
	item->setRight(output);
	if (output)
		output->setLeft(item);
   }

   if (m_right && m_right->bottom())
   {
	   OutputGraphicsItem *item = m_right->bottom();
	   if (item->left())
	   qDebug("Oops, this should not happen");
	   item->setLeft(output);
	   if (output)
		   output->setRight(item);
   }
}

void OutputGraphicsItem::setLeft(OutputGraphicsItem *output)
{
	// if we already have that output at left, then just return
	if (m_left == output)
	return;
   
   OutputGraphicsItem *oldLeft = m_left;
   m_left = output;

   // if we currently have a left item, set the given item as the right of our old item
   if (oldLeft)
	oldLeft->setRight(output);

   // check whether we have a top->left or a bottom->left to update the pointers
   if (m_top && m_top->left())
   {
	   OutputGraphicsItem *item = m_top->left();
	   if (item->bottom())
	   qDebug("Oops, this should not happen");
	item->setBottom(output);
	if (output)
		output->setTop(item);
   }

   if (m_bottom && m_bottom->left())
   {
	   OutputGraphicsItem *item = m_bottom->left();
	   if (item->top())
	   qDebug("Oops, this should not happen");
	   item->setTop(output);
	   if (output)
		   output->setBottom(item);
   }
}

void OutputGraphicsItem::setRight(OutputGraphicsItem *output)
{
	// if we already have that output at right, then just return
	if (m_right == output)
	return;
   
   OutputGraphicsItem *oldRight = m_right;
   m_right = output;

   // if we currently have a right item, set the given item as the left of our old item
   if (oldRight)
	oldRight->setLeft(output);

   // check whether we have a top->right or a bottom->right to update the pointers
   if (m_top && m_top->right())
   {
	   OutputGraphicsItem *item = m_top->right();
	   if (item->bottom())
	   qDebug("Oops, this should not happen");
	item->setBottom(output);
	if (output)
		output->setTop(item);
   }

   if (m_bottom && m_bottom->right())
   {
	   OutputGraphicsItem *item = m_bottom->right();
	   if (item->top())
	   qDebug("Oops, this should not happen");
	   item->setTop(output);
	   if (output)
		   output->setBottom(item);
   }
}

void OutputGraphicsItem::updateText()
{
	// An example of this description text with radeonhd on randr 1.2:
	// DVI-I_2/digital
	// 1680x1050 (60.0 Hz)

	int w = m_output->rect().width(), h = m_output->rect().height();

	QString refresh = QString::number(m_output->refreshRate(), 'f', 1);
	QString desc = m_output->name() + '\n' + 
				   QString("%1x%2 (%3 Hz)").arg(w).arg(h).arg(refresh);

	m_text->setPlainText(desc);

	QRectF textRect = m_text->boundingRect();
	QRect  outRect  = m_output->rect();
	// more accurate text centering
	m_text->setPos((outRect.width() - textRect.width()) / 2,
				   (outRect.height() - textRect.height()) / 2);

}

void OutputGraphicsItem::disconnect()
{
	// for now just disconnect everything
	if (m_top)
	{
		m_top->m_bottom = NULL;
		if (!m_top->isConnected())
			emit itemChanged(m_top);
	}
	if (m_bottom)
	{
		m_bottom->m_top = NULL;
		if (!m_bottom->isConnected())
			emit itemChanged(m_bottom);
	}
	if (m_left)
	{
		m_left->m_right = NULL;
		if (!m_left->isConnected())
			emit itemChanged(m_left);
	}
	if (m_right)
	{
		m_right->m_left = NULL;
		if (!m_right->isConnected())
			emit itemChanged(m_right);
	}

	m_top = m_bottom = m_left = m_right = NULL;
}

void OutputGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
	// disconnect from the current layout
	disconnect();

	QGraphicsRectItem::mousePressEvent(event);
}

void OutputGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
   QGraphicsRectItem::mouseReleaseEvent(event);
   emit itemChanged(this);
}

bool OutputGraphicsItem::isConnected()
{
	return (m_top != NULL || m_bottom != NULL || m_left != NULL || m_right != NULL);
}

#include "outputgraphicsitem.moc"
