/*
 *  Copyright (C) 2003 by Unai Garro <ugarro@users.sourceforge.net>
 *  Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
 *  Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
 *  Copyright (C) 2004 by Oswald Buddenhagen <ossi@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 "tdmlayout.h"
#include "tdmconfig.h"
#include "tdmitem.h"

#include <kdebug.h>

#include <tqdom.h>
#include <tqrect.h>

KdmLayoutFixed::KdmLayoutFixed( const TQDomNode &/*node*/ )
{
	//Parsing FIXED parameters on 'node' [NONE!]
}

void
KdmLayoutFixed::update( const TQRect &parentGeometry, bool force )
{
	kdDebug() << timestamp() << " KdmLayoutFixed::update " << parentGeometry << endl;

	// I can't layout children if the parent rectangle is not valid
	if (parentGeometry.width() < 0 || parentGeometry.height() < 0) {
		kdDebug() << timestamp() << " invalid\n";
		return;
	}
	// For each child in list I ask their hinted size and set it!
	for (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it)
		(*it)->setGeometry( (*it)->placementHint( parentGeometry ), force );
}

KdmLayoutBox::KdmLayoutBox( const TQDomNode &node )
{
	//Parsing BOX parameters
	TQDomNode n = node;
	TQDomElement el = n.toElement();
	box.isVertical = el.attribute( "orientation", "vertical" ) != "horizontal";
	box.xpadding = el.attribute( "xpadding", "0" ).toInt();
	box.ypadding = el.attribute( "ypadding", "0" ).toInt();
	box.spacing = el.attribute( "spacing", "0" ).toInt();
	box.minwidth = el.attribute( "min-width", "0" ).toInt();
	box.minheight = el.attribute( "min-height", "0" ).toInt();
	box.homogeneous = el.attribute( "homogeneous", "false" ) == "true";
}

void
KdmLayoutBox::update( const TQRect &parentGeometry, bool force )
{
	kdDebug() << this << " update " << parentGeometry << endl;

	// I can't layout children if the parent rectangle is not valid
	if (!parentGeometry.isValid() || parentGeometry.isEmpty())
		return;

	// Check if box size was computed. If not compute it
	// TODO check if this prevents updating changing items
//	if (!hintedSize.isValid())
//		sizeHint();

//	kdDebug() << this << " hintedSize " << hintedSize << endl;

	//XXX why was this asymmetric? it broke things big time.
	TQRect childrenRect = /*box.isVertical ? TQRect( parentGeometry.topLeft(), hintedSize ) :*/ parentGeometry;
	// Begin cutting the parent rectangle to attach children on the right place
	childrenRect.addCoords( box.xpadding, box.ypadding, -box.xpadding, -box.ypadding );

	kdDebug() << this << " childrenRect " << childrenRect << endl;

	// For each child in list ...
	if (box.homogeneous) {
		int ccnt = 0;
		for (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it)
			if (!(*it)->isExplicitlyHidden())
				ccnt++;
		int height = (childrenRect.height() - (ccnt - 1) * box.spacing) / ccnt;
		int width = (childrenRect.width() - (ccnt - 1) * box.spacing) / ccnt;

		for (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) {
			if ((*it)->isExplicitlyHidden())
				continue;
			if (box.isVertical) {
				TQRect temp( childrenRect.left(), childrenRect.top(), childrenRect.width(), height );
				(*it)->setGeometry( temp, force );
				childrenRect.setTop( childrenRect.top() + height + box.spacing );
			} else {
				TQRect temp( childrenRect.left(), childrenRect.top(), width, childrenRect.height() );
				kdDebug() << timestamp() << " placement " << *it << " " << temp << " " << (*it)->placementHint( temp ) << endl;
				temp = (*it)->placementHint( temp );
				(*it)->setGeometry( temp, force );
				childrenRect.setLeft( childrenRect.left() + width + box.spacing );
			}
		}
	} else {
		for (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) {
			if ((*it)->isExplicitlyHidden())
				continue;

			TQRect temp = childrenRect, itemRect;
			if (box.isVertical) {
				temp.setHeight( 0 );
				itemRect = (*it)->placementHint( temp );
				temp.setHeight( itemRect.height() );
				childrenRect.setTop( childrenRect.top() + itemRect.size().height() + box.spacing );
			} else {
				temp.setWidth( 0 );
				itemRect = (*it)->placementHint( temp );
				kdDebug() << this << " placementHint " << *it << " " << temp << " " << itemRect << endl;
				temp.setWidth( itemRect.width() );
				childrenRect.setLeft( childrenRect.left() + itemRect.size().width() + box.spacing );
				kdDebug() << timestamp() << " childrenRect after " << *it << " " << childrenRect << endl;
			}
			itemRect = (*it)->placementHint( temp );
			kdDebug() << this << " placementHint2 " << *it << " " << temp << " " << itemRect << endl;
			(*it)->setGeometry( itemRect, force );
		}
	}
}

//FIXME truly experimental (is so close to greeter_geometry.c)
TQSize
KdmLayoutBox::sizeHint()
{
	// Sum up area taken by children
	int w = 0, h = 0;
	for (TQValueList<KdmItem *>::ConstIterator it = m_children.begin(); it != m_children.end(); ++it) {
		TQSize s = (*it)->placementHint( TQRect() ).size();
		if (box.isVertical) {
			if (s.width() > w)
				w = s.width();
			h += s.height();
		} else {
			if (s.height() > h)
				h = s.height();
			w += s.width();
		}
	}

	// Add padding and items spacing
	w += 2 * box.xpadding;
	h += 2 * box.ypadding;
	if (box.isVertical)
		h += box.spacing * (m_children.count() - 1);
	else
		w += box.spacing * (m_children.count() - 1);

	// Make hint at least equal to minimum size (if set)
	return TQSize( w < box.minwidth ? box.minwidth : w,
		      h < box.minheight ? box.minheight : h );
}
