#include <qpainter.h>
#include "skinpanel.h"
#include "skin.h"
#include "skinnedbutton.h"
#include "skinnedlabel.h"
#include "seekbar.h"

SkinPanel::SkinPanel(Skin::PartsType type, const SkinManager *skinmgr, QWidget *parent, const char *name)
	:	QWidget(parent, name),
		type_(type),
		sections_(NULL)
{
	setFocusPolicy(NoFocus);
	setBackgroundMode(NoBackground);
	setWFlags(Qt::WRepaintNoErase | Qt::WResizeNoErase);

	setSkin(skinmgr->skin());
	connect(skinmgr, SIGNAL(skinChanged(const Skin *)), this, SLOT(setSkin(const Skin *)));
}

SkinPanel::~SkinPanel()
{
}

void SkinPanel::setSkin(const Skin *skin)
{
	skin_ = skin;
	
	const SkinParts *parts = skin_->lookup(type_);
	
	backgroundImage_ = &parts->image();
	
	if (parts->data())
		sections_ = static_cast<SkinSections *>(parts->data());
	else
		sections_ = NULL;
	
	setFixedHeight(backgroundImage_->size().height());
	
	updateSections();
	
	move(0, 0);
}

QSize SkinPanel::sizeHint() const
{
	QSize size = backgroundImage_->size();
	size.setWidth(10);
	return size;
}

QSizePolicy SkinPanel::sizePolicy() const 
{
	return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
}

void SkinPanel::updateSections()
{
	if (sections_)
	{
		internalSections_.resize(sections_->count());
		internalSections_.setAutoDelete(true);

		uint totalFixedSectionsWidth = 0;
		uint lastFlexibleSectionIndex = -1;
		
		for (uint i = 0; i < sections_->count(); ++i)
		{
			SkinSection *section = sections_->at(i); 
			
			if (section->type() == SkinSection::Fixed)
				totalFixedSectionsWidth += section->width();
			else if (section->type() == SkinSection::FlexibleTiled)
				lastFlexibleSectionIndex = i;
		}
		
		uint totalFlexibleSectionsWidth = backgroundImage_->width() - totalFixedSectionsWidth;
		uint totalInternalFlexibleSectionsWidth = width() - totalFixedSectionsWidth;
		uint remainingInternalFlexibleSectionWidth = totalInternalFlexibleSectionsWidth;
		
		uint xPos = 0;
		
		for (uint i = 0; i < sections_->count(); ++i)
		{
			SkinSection *section = sections_->at(i);
			SkinSection *internalSection = internalSections_.at(i);
			
			uint internalSectionWidth;

			if (!internalSection)
			{
				internalSection = new SkinSection();
				internalSections_.insert(i, internalSection);
			}
		
			if (section->type() == SkinSection::FlexibleTiled)
			{
				// if this is the last flexible section, use the remaining
				// width for it to work around rounding errors.
				if (i == lastFlexibleSectionIndex)
					internalSectionWidth = remainingInternalFlexibleSectionWidth;
				else
				{
					internalSectionWidth = (uint)(((float)section->width() / (float)totalFlexibleSectionsWidth) * totalInternalFlexibleSectionsWidth);
					remainingInternalFlexibleSectionWidth -= internalSectionWidth;
				}
			}
			else if (section->type() == SkinSection::Fixed)
			{
				internalSectionWidth = section->width();
			}
			
			internalSection->setType(section->type());
			internalSection->setX(xPos);
			internalSection->setWidth(internalSectionWidth);
		
			xPos += internalSectionWidth;
		}
	}
}

const QRect SkinPanel::calculateGeometry(const SkinParts *parts) const
{
	if (sections_)
	{
		QRect rect = parts->geometry();
		SkinSection *section = sections_->at(parts->section());
		SkinSection *internalSection = internalSections_.at(parts->section());
		
		rect.moveBy(internalSection->x(), 0);
		
		if (parts->length() != 0)
		{
			if (internalSection->type() == SkinSection::Fixed)
			{
				rect.setWidth(parts->length());
			}
			else if (internalSection->type() == SkinSection::FlexibleTiled)
			{
				int rightMargin = section->width() - parts->geometry().x() - parts->length();
				int scaledLength = internalSection->width() - parts->geometry().x() - rightMargin;
				rect.setWidth(scaledLength);
			}
		}
		
		return rect;
	}
	else
		return parts->geometry();
}

void SkinPanel::resizeEvent(QResizeEvent *)
{
	updateSections();
	emit resized();
}

void SkinPanel::paintSkin(QPainter &painter)
{
	if (!sections_)
		painter.drawPixmap(0, 0, *backgroundImage_);
	else
	{
		for (uint i = 0; i < internalSections_.count(); ++i)
		{
			SkinSection *section = sections_->at(i);
			SkinSection *internalSection = internalSections_.at(i);
		
			if (section->type() == SkinSection::FlexibleTiled)
			{
				uint drawnWidth = 0;
				uint xToDrawTo = internalSection->x();
				
				// This will avoid using multiplication and modulo...
				while (drawnWidth < internalSection->width() && xToDrawTo < this->width())
				{
					drawnWidth += section->width();

					uint widthToDraw = section->width();
					if (drawnWidth > internalSection->width())
						widthToDraw -= drawnWidth - internalSection->width();
					
					painter.drawPixmap(xToDrawTo, 0, *backgroundImage_, section->x(), 0, widthToDraw, backgroundImage_->height());
					
					xToDrawTo += widthToDraw;
				}
			}
			else if (section->type() == SkinSection::Fixed)
				painter.drawPixmap(internalSection->x(), 0, *backgroundImage_, section->x(), 0, section->width(), backgroundImage_->height());
		}				
	}
}

void SkinPanel::paintEvent(QPaintEvent *)
{
	QPainter painter(this);
	paintSkin(painter);
}