/***************************************************************************
 *   Copyright (C) 2005 by Ken Werner                                      *
 *   ken.werner@web.de                                                     *
 *                                                                         *
 *   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 "flowlayout.h"
#include "sources/source.h"

//#include "kdebug.h"
//#include <tqlabel.h> // debugging

class FlowLayoutIterator :public TQGLayoutIterator{
public:
	FlowLayoutIterator( TQPtrList<TQLayoutItem>* layoutItems ): 
		index(0),
		mLayoutItems(layoutItems){
	}
	uint count() const;
	TQLayoutItem* current();
	TQLayoutItem* next();
	TQLayoutItem* takeCurrent();
private:
	int index;
	TQPtrList<TQLayoutItem>* mLayoutItems;
};
TQLayoutItem* FlowLayoutIterator::current(){
	return index < int(mLayoutItems->count()) ? mLayoutItems->at(index) : 0;
	/*if(index < int(mLayoutItems->count())){
		TQLayoutItem* item = mLayoutItems->at(index);
		kdDebug() << "FlowLayoutIterator::current(index " << index << ") returns: " << item << endl;
		return item;
	}else{
		kdDebug() << "FlowLayoutIterator::current(index " << index << ") returns: NULL" << endl;
	 	return 0;
	}*/
}
TQLayoutItem* FlowLayoutIterator::next(){
	index++;
	//kdDebug() << "FlowLayoutIterator::next, index: " << index << endl;
	return current();
}
TQLayoutItem* FlowLayoutIterator::takeCurrent(){
	return index < int(mLayoutItems->count()) ? mLayoutItems->take(index) : 0;
	/*if(index < int(mLayoutItems->count())){
		TQLayoutItem* item = mLayoutItems->take(index);
		kdDebug() << "FlowLayoutIterator::takeCurrent(index " << index << ") returns: " << item << endl;
		return item;
	}else{
		kdDebug() << "FlowLayoutIterator::takeCurrent(index " << index << ") returns: NULL" << endl;
	 	return 0;
	}*/

}


FlowLayout::FlowLayout( TQWidget* parent, TQt::Orientation orientation, int border, int space, const char* name )
	: TQLayout( parent, border, space, name ),
	mOrientation(orientation), mLastItem(NULL){
}
FlowLayout::FlowLayout( TQLayout* parent, TQt::Orientation orientation, int space, const char* name )
	: TQLayout( parent, space, name ),
	mOrientation(orientation), mLastItem(NULL){
}
FlowLayout::FlowLayout( TQt::Orientation orientation, int space, const char* name )
	: TQLayout( space, name ),
	mOrientation(orientation), mLastItem(NULL){
}


FlowLayout::~FlowLayout(){
	deleteAllItems();
}

int FlowLayout::heightForWidth( int w ) const{
	FlowLayout* mthis = (FlowLayout*)this;
	int h = mthis->doLayout( TQRect(0,0,w,0), true );
	return h;
}

int FlowLayout::widthForHeight( int h ) const{
	FlowLayout* mthis = (FlowLayout*)this;
	int w = mthis->doLayout( TQRect(0,0,0,h), true );
	return w;
}

void FlowLayout::addItem(TQLayoutItem* item){
	//kdDebug() << "FlowLayout::addItem: " << (static_cast<TQLabel*>(item->widget()))->text() << ", width: " << item->widget()->width() << ", height: " << item->widget()->height()<< endl;
	// we are indirectly called from addSource. this
	// is a hint for addSource, to let it know which item
	// was added.
	mLastItem = item;
}

void FlowLayout::addSource(Source* src){
	add(src->getWidget());
	mSources[mLastItem] = src;
	src->getWidget()->show();

	// step back until we find an item which has a
	// smaller position stored in its config. then, we found
	// the right position for the new item.
	TQLayoutItem * qli = mLayoutItems.last();
	while(qli && mSources[qli]->getPosition() > src->getPosition())
		qli = mLayoutItems.prev();
	mLayoutItems.insert(mLayoutItems.at()+1, mLastItem);
}

void FlowLayout::remove(TQWidget* widget){
	//kdDebug() << "FlowLayout::remove: " << (static_cast<TQLabel*>(widget))->text() << endl;
	widget->hide();
	TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
	while(it.current() != NULL) { 
		if(it.current()->widget() == widget) {
			mSources.erase(it.current());
			mLayoutItems.remove(it.current());
			// removes and deletes only the TQLayoutItem
			// (TQWidgetItem)
			TQLayout::remove(widget);
			break;
		}
		++it;
	}
}

uint FlowLayout::count(){
	return mLayoutItems.count();
}

bool FlowLayout::moveItem(const TQLayoutItem* which, const TQLayoutItem* relate, DIRECTION direction){
	int newPos = mLayoutItems.findRef(relate);
	int oldPos = mLayoutItems.findRef(which);

	// check whether the widget is already at a correct position
	if(oldPos+1 == newPos && direction == ABOVE || oldPos-1 == newPos && direction == BELOW)
		return false;

	// remove the item
	mLayoutItems.remove(which);
	if(oldPos < newPos)
		newPos--;

	newPos += direction;
	// actually reinsert the item
	mLayoutItems.insert(newPos, which);
	activate(); // relayout
	// kdDebug() << "oldPos: " << oldPos << ", newPos: " << newPos << endl;
	return true;
}

void FlowLayout::updatePositions(TDEConfig * inTDEConfig){
	//kdDebug() << "updating all positions..." << endl;
	int pos = 0;
	TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
	while(it.current() != NULL) {
		mSources[it.current()]->setPosition(pos, inTDEConfig);
		++it;
		++pos;
	}
	//kdDebug() << "positions updated!" << endl;
}

bool FlowLayout::hasHeightForWidth() const{
	return mOrientation != TQt::Horizontal;
}

bool FlowLayout::hasWidthForHeight() const{
	return mOrientation == TQt::Horizontal;
}

TQSize FlowLayout::sizeHint() const{
	//return minimumSize();
	TQSize size(0,0);
	TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
	TQLayoutItem *o;
	while((o=it.current()) != 0){
		++it;
		size = size.expandedTo( o->sizeHint() );
	}
	return size;
}

TQSize FlowLayout::minimumSize() const{
	TQSize size(0,0);
	TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
	TQLayoutItem *o;
	while((o=it.current()) != 0){
		++it;
		size = size.expandedTo(o->minimumSize());
	}
	return size;
}

TQSizePolicy::ExpandData FlowLayout::expanding() const{
	return TQSizePolicy::NoDirection;
}

TQLayoutIterator FlowLayout::iterator(){
	return TQLayoutIterator(new FlowLayoutIterator(&mLayoutItems));
}

TQt::Orientation FlowLayout::getOrientation() const{
	return mOrientation;
}

void FlowLayout::setOrientation(TQt::Orientation orientation){
	mOrientation = orientation;
}

void FlowLayout::setGeometry( const TQRect& rect ){
	TQLayout::setGeometry( rect );
	doLayout( rect );
}

int FlowLayout::doLayout( const TQRect& rect, bool testonly ){
	if(mOrientation == TQt::Horizontal)
		return doLayoutHorizontal(rect, testonly);
	else
		return doLayoutVertical(rect, testonly);
}

int FlowLayout::doLayoutHorizontal( const TQRect& rect, bool testOnly ){
	//kdDebug() << "spacing: " << spacing() <<  endl;

	int x = rect.x();
	int y = rect.y();
	int width = 0; // width of this column so far
	int height = 0; // height of this column so far
	TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
	TQLayoutItem* layoutItem;
	TQPtrList<TQLayoutItem> column; // stores the items of one column
	while((layoutItem = it.current()) != 0){
		++it;
		//int nextY = y + layoutItem->sizeHint().height() + spacing(); // next y
		int nextY = y + layoutItem->sizeHint().height(); // next y
		//if( nextY - spacing() > rect.bottom() && width > 0 ) {
		if( nextY > rect.bottom() && width > 0 ) {
			// next column
			y = rect.y(); // reset y
			x = x + width + spacing(); // new x
			//nextY = y + layoutItem->sizeHint().height() + spacing(); // next y with changed y
			nextY = y + layoutItem->sizeHint().height(); // next y with changed y
			width = 0; // reset width for the next column
		}
		if(!testOnly){
			layoutItem->setGeometry( TQRect( TQPoint( x, y ), layoutItem->sizeHint() ) );
			column.append(layoutItem);
			height += layoutItem->sizeHint().height(); // add the height of the current item to the column height
			if( it.current() == 0 || nextY + it.current()->sizeHint().height() > rect.bottom() ){ // test it it's the last item (of this column)
				// calculate real needed width
				int rWidth = 0;
				for(TQLayoutItem* item = column.first(); item; item = column.next()){
					rWidth = TQMAX( rWidth, item->widget()->sizeHint().width() );
				}
				// relayout the items of the former column
				int space = (rect.height() - height) / (column.count() + 1);
				int i = 0; // counts the items of this column
				for(TQLayoutItem* item = column.first(); item; item = column.next()){
					TQRect r = item->geometry();
					item->setGeometry( TQRect(r.left(), r.top() + ((++i) * space), rWidth, r.height()) );
				}
				column.clear(); // remove the items of the former column
				height = 0; // reset height for the next column
			}
		}
		y = nextY;
		width = TQMAX( width, layoutItem->sizeHint().width() );
	}
	return x + width - rect.x(); // width
}

int FlowLayout::doLayoutVertical( const TQRect& rect, bool testOnly ){
	int x = rect.x();
	int y = rect.y();
	int height = 0; // height of this line so far
	TQPtrListIterator<TQLayoutItem> it(mLayoutItems);
	TQLayoutItem* layoutItem;
	while((layoutItem = it.current() ) != 0){
		++it;
		//int nextX = x + layoutItem->sizeHint().width() + spacing();
		int nextX = x + layoutItem->sizeHint().width();
		if(nextX - spacing() > rect.right() && height > 0) {
			// next line
			x = rect.x(); // reset x
			//y = y + height + spacing(); // new y
			y = y + height; // new y
			//nextX = x + layoutItem->sizeHint().width() + spacing(); // next x
			nextX = x + layoutItem->sizeHint().width(); // next x
			height = 0; // reset height for the next line
		}
		const int itemHeight = layoutItem->sizeHint().height();
		if(!testOnly)
			layoutItem->setGeometry(TQRect(x, y, rect.right(), itemHeight));
		x = nextX;
		height = TQMAX(height, itemHeight);
	}
	return y + height - rect.y(); // height
}

#include "flowlayout.moc"
