/*************************************************************************\
*   Copyright (C) 2009 by Ulf Kreissig                                    *
*   udev@gmx.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 "panellayout.h"
#include "logger/streamlogger.h"

#include <KGlobalSettings>

//--- Vertical Panel Constants ---
#define PV_TODAYS_TEMP_HEIGHT		0.55f
#define PV_FORECAST_TEMP_HEIGHT		0.95f

#define PV_COMPACT_ICON_WIDTH		0.55f

//--- Desktop Layout Constants ---
#define YAWP_ORIG_SIZEX			273.0f
#define YAWP_ORIG_SIZEY			255.0f


AbstractPanelLayout::AbstractPanelLayout()
{
	m_iForecastDays   = 0;
	m_tTodaysFormat   = Yawp::PanelTemperature | Yawp::PanelIcon;
	m_tForecastFormat = Yawp::PanelTemperature | Yawp::PanelIcon;
}

AbstractPanelLayout::~AbstractPanelLayout()
{
}

/**********************************************************************\
*                                                                      *
*          H O R I Z O N T A L   P A N E L   L A Y O U T               *
*                                                                      *
\**********************************************************************/

HorizontalPanelLayout::HorizontalPanelLayout()
{
}

HorizontalPanelLayout::~HorizontalPanelLayout()
{
}

qreal
HorizontalPanelLayout::getScalingFactor() const
{
	return contentsRect().height() / 40.0;
}

void
HorizontalPanelLayout::setContentsRect( const QRectF & rect )
{
	AbstractPanelLayout::setContentsRect( rect );
	
	if( useCompactLayout() )
	{
		m_dTodaysTempWidth = getTemperatureWidth( (int)qRound(rect.height()*0.38f) );
		m_dForecastTempWidth = getTemperatureWidth( (int)qRound(rect.height()*0.25f),
			QString("-99%1/-99%1").arg(QChar(0xB0)) );
	}
	else
	{
		m_dTodaysTempWidth   = getTemperatureWidth( (int)qRound(rect.height()*0.62f) );
		m_dForecastTempWidth = getTemperatureWidth( (int)qRound(rect.height()*0.45f) );
	}
}

QSizeF
HorizontalPanelLayout::getSize( const QSizeF & size ) const
{
	dStartFunct();
	float dWidth(0.0f);
	const float dHeight( size.height() <= 0.01 ? 40.0f : qRound(size.height()) );
	dDebug() << "calculate Width for " << dHeight;
	
	if( useCompactLayout() )
	{
		const float dIconSize( size.height()*0.65f );
		float dTodaysTempWidth( getTemperatureWidth( (int)qRound(dHeight*0.38f) ) );
		float dForecastTempWidth( getTemperatureWidth( (int)qRound(dHeight*0.25f), QString("-99%1/-99%1").arg(QChar(0xB0))) );
		dWidth = qMax(dTodaysTempWidth, dIconSize);
		dWidth += qMax(dForecastTempWidth, dIconSize) * forecastDays();
	}
	else
	{
		if( forecastDays() > 0 )
		{
			if( forecastFormat().testFlag( Yawp::PanelIcon ) )
				dWidth += qRound(dHeight);
			if( forecastFormat().testFlag( Yawp::PanelTemperature ) )
				dWidth += getTemperatureWidth( (int)qRound(dHeight*0.45f) );
			dWidth = dWidth * ((float)(forecastDays()));
		}

		if( todaysFormat().testFlag( Yawp::PanelIcon ) )
			dWidth += dHeight;
		if( todaysFormat().testFlag( Yawp::PanelTemperature ) )
			dWidth += getTemperatureWidth( (int)qRound(dHeight*0.62f) );
	}
	dEndFunct() << qRound(dWidth) << "x" << qRound(dHeight);
	return QSizeF(qRound(dWidth), dHeight);
}

QRectF
HorizontalPanelLayout::getTodaysTempRect() const
{
	if( useCompactLayout() )
	{
		float dHeight( contentsRect().height() * 0.36f );
		float dIconSize( contentsRect().height() * 0.65f );
		float dWidth( qMax(m_dTodaysTempWidth, dIconSize) );
		return QRectF( 0.0f, qRound(contentsRect().height()-dHeight), qRound(dWidth), qRound(dHeight) );
	}
		
	float dHeight = contentsRect().height() * 0.7f;
	return QRectF( 0.0f, qRound((contentsRect().height() - dHeight) / 2.0f),
				   m_dTodaysTempWidth, qRound(dHeight) );
}

QRectF
HorizontalPanelLayout::getTodaysIconRect() const
{
	if( useCompactLayout() )
	{
		float dIconSize( contentsRect().height() * 0.65f );
		float dOffset( m_dTodaysTempWidth > dIconSize ? (m_dTodaysTempWidth-dIconSize)/2.0f : 0.0f );
		return QRectF( qRound(dOffset), 0.0f, qRound(dIconSize), qRound(dIconSize) );
	}

	float dOffset(0.0f);
	if( todaysFormat().testFlag( Yawp::PanelTemperature ) )
		dOffset = qRound(getTodaysTempRect().right());
	float dSize = qRound(contentsRect().height());
	return QRectF( dOffset, 0.0f, dSize, dSize );
}

QRectF
HorizontalPanelLayout::getForecastTempRect( const int iDay ) const
{
	if( useCompactLayout() )
	{
		const float dHeight( contentsRect().height() * 0.36f );
		const float dIconSize( contentsRect().height() * 0.65f );
		const float dTodayOffset( qMax(m_dTodaysTempWidth, dIconSize) );
		float const dForecastOffset( qMax(m_dForecastTempWidth, dIconSize) * iDay );

		return QRectF( qRound(dTodayOffset+dForecastOffset), qRound(contentsRect().height()-dHeight),
					   qRound(qMax(m_dForecastTempWidth,dIconSize)), qRound(dHeight) );
	}
	
	float dOffset(0.0f);
	if( iDay > 0 )
	{
		if( forecastFormat().testFlag( Yawp::PanelIcon ) )
			dOffset += contentsRect().height();
		dOffset+= m_dForecastTempWidth;
		dOffset = dOffset * (float)iDay;
	}
	dOffset += calculateTodaysOffset();
	return QRectF( qRound(dOffset), 0.0f, m_dForecastTempWidth, qRound(contentsRect().height()) );
}

QRectF
HorizontalPanelLayout::getForecastIconRect( const int iDay ) const
{
	if( useCompactLayout() )
	{
		const float dIconSize( contentsRect().height() * 0.65f );
		const float dTodayOffset( qMax(m_dTodaysTempWidth, dIconSize) );
		float const dForecastOffset( qMax(m_dForecastTempWidth, dIconSize) * iDay );
		const float dOffset( m_dForecastTempWidth > dIconSize ? (m_dForecastTempWidth-dIconSize)/2.0f : 0.0f );
		
		return QRectF( qRound(dTodayOffset + dForecastOffset + dOffset), 0.0f, 
					   qRound(dIconSize), qRound(dIconSize) );
		return QRectF();
	}

	float dOffset = 0.0f;
	if( iDay > 0 )
	{
		if( forecastFormat().testFlag( Yawp::PanelTemperature ) )
			dOffset += m_dForecastTempWidth;
		dOffset+= contentsRect().height();
		dOffset = dOffset * (float)iDay;
	}
	if( forecastFormat().testFlag( Yawp::PanelTemperature ) )
		dOffset += m_dForecastTempWidth;
	dOffset = dOffset + calculateTodaysOffset();
	return QRectF( qRound(dOffset), 0.0f, qRound(contentsRect().height()), qRound(contentsRect().height()) );
}

float
HorizontalPanelLayout::calculateTodaysOffset() const
{
	if( todaysFormat().testFlag( Yawp::PanelIcon ) )
		return qRound(getTodaysIconRect().right());
	else if( todaysFormat().testFlag( Yawp::PanelTemperature ) )
		return qRound(getTodaysTempRect().right());
	else
		return 0.0f;
}

float
HorizontalPanelLayout::getTemperatureWidth( int iPixelSize, const QString & str ) const
{
	dDebug() << str;
	QFont font( KGlobalSettings::generalFont() );
	font.setBold(false);
	font.setPixelSize( iPixelSize );
	QFontMetrics fm(font);
	return (float)fm.width( str );
}


/**********************************************************************\
*                                                                      *
*            V E R T I C A L   P A N E L   L A Y O U T                 *
*                                                                      *
\**********************************************************************/

VerticalPanelLayout::VerticalPanelLayout()
{
}

VerticalPanelLayout::~VerticalPanelLayout()
{
}

qreal
VerticalPanelLayout::getScalingFactor() const
{
	return contentsRect().width() / 40.0;
}

QSizeF
VerticalPanelLayout::getSize( const QSizeF & size ) const
{
	float dHeight = 0.0f;
	const float dWidth = (size.width() <= 0.01 ? 40.0f : qRound(size.width()));

	
	if( useCompactLayout() )
	{
		dHeight = dWidth * PV_COMPACT_ICON_WIDTH * (float)(forecastDays()+1);
	}
	else
	{
		if( forecastDays() > 0 )
		{
			if( forecastFormat().testFlag( Yawp::PanelTemperature ) )
				dHeight += dWidth * PV_FORECAST_TEMP_HEIGHT;
			if( forecastFormat().testFlag( Yawp::PanelIcon ) )
				dHeight += dWidth;
			dHeight = dHeight * ((float)(forecastDays()));
		}

		if( todaysFormat().testFlag( Yawp::PanelTemperature ) )
			dHeight += dWidth * PV_TODAYS_TEMP_HEIGHT;
		if( todaysFormat().testFlag( Yawp::PanelIcon ) )
			dHeight += dWidth;
	}
	return QSizeF(dWidth, qRound(dHeight));
}

QRectF
VerticalPanelLayout::getTodaysTempRect() const
{
	if( useCompactLayout() )
		return getCompactTempRect(0);
	
	float dHeight = contentsRect().width() * PV_TODAYS_TEMP_HEIGHT;
	return QRectF( 0.0f, 0.0f, qRound(contentsRect().width()), qRound(dHeight) );
}

QRectF
VerticalPanelLayout::getTodaysIconRect() const
{
	if( useCompactLayout() )
		return getCompactIconRect(0);

	float dOffset = 0.0f;
	if( todaysFormat().testFlag( Yawp::PanelTemperature ) )
		qRound(dOffset = getTodaysTempRect().bottom());
	float dSize = qRound(contentsRect().width());
	return QRectF( 0.0f, dOffset, dSize, dSize );
}

QRectF
VerticalPanelLayout::getForecastTempRect( const int iDay ) const
{
	if( useCompactLayout() )
		return getCompactTempRect(iDay+1);
		
	float dOffset = 0.0f;
	if( iDay > 0 )
	{
		if( forecastFormat().testFlag( Yawp::PanelIcon ) )
			dOffset += contentsRect().width();
		dOffset+= contentsRect().width() * PV_FORECAST_TEMP_HEIGHT;
		dOffset = dOffset * (float)iDay;
	}
	dOffset += calculateTodaysOffset();

	float dHeight = contentsRect().width() * PV_FORECAST_TEMP_HEIGHT;
	return QRectF( 0.0f, qRound(dOffset), qRound(contentsRect().width()), qRound(dHeight) );
}

QRectF
VerticalPanelLayout::getForecastIconRect( const int iDay ) const
{
	if( useCompactLayout() )
		return getCompactIconRect(iDay+1);
		
	float dOffset = 0.0f;
	if( iDay > 0 )
	{
		if( forecastFormat().testFlag( Yawp::PanelTemperature ) )
			dOffset += contentsRect().width() * PV_FORECAST_TEMP_HEIGHT;
		dOffset+= contentsRect().width();
		dOffset = dOffset * (float)iDay;
	}
	if( forecastFormat().testFlag( Yawp::PanelTemperature ) )
		dOffset += contentsRect().width() * PV_FORECAST_TEMP_HEIGHT;
	dOffset = dOffset + calculateTodaysOffset();

	return QRectF( 0.0f, qRound(dOffset), qRound(contentsRect().width()), qRound(contentsRect().width()) );
}

float
VerticalPanelLayout::calculateTodaysOffset() const
{
	if( todaysFormat().testFlag( Yawp::PanelIcon ) )
		return getTodaysIconRect().bottom();
	else if( todaysFormat().testFlag( Yawp::PanelTemperature ) )
		return getTodaysTempRect().bottom();
	else
		return 0.0f;
}

QRectF
VerticalPanelLayout::getCompactIconRect(int index) const
{
	float dSize( contentsRect().width() * PV_COMPACT_ICON_WIDTH );
	return QRectF( 0.0f, qRound(dSize*index), qRound(dSize), qRound(dSize) );
}

QRectF
VerticalPanelLayout::getCompactTempRect(int index) const
{
	float dIconSize( contentsRect().width() * PV_COMPACT_ICON_WIDTH );
	return QRectF( qRound(dIconSize), qRound(dIconSize*index),
				   qRound(contentsRect().width()-dIconSize), qRound(dIconSize) );
}


/**********************************************************************\
*                                                                      *
*                     D E S K T O P   L A Y O U T                      *
*                                                                      *
\**********************************************************************/

DesktopLayout::DesktopLayout()
{
}

DesktopLayout::~DesktopLayout()
{
}

void
DesktopLayout::setContentsRect( const QRectF & rect )
{
	AbstractPanelLayout::setContentsRect( rect );
	m_dScale = rect.width() / YAWP_ORIG_SIZEX;
}

QSizeF
DesktopLayout::getSize( const QSizeF & size ) const
{
	Q_UNUSED( size );
	if( size.width() > 0 && size.height() > 0 )
		return size;
	return QSizeF( YAWP_ORIG_SIZEX, YAWP_ORIG_SIZEY );
}

QRectF
DesktopLayout::getPageRect() const
{
	return QRectF( qRound(contentsRect().left()+4.0f*m_dScale),
	               qRound(contentsRect().top()+4.0f*m_dScale),
	               qRound(contentsRect().width()-8.0f+m_dScale),
	               qRound(contentsRect().height()-8.0f+m_dScale) );
}

QRectF
DesktopLayout::getDetailsRect() const
{
	return QRectF( qRound(contentsRect().left()+4.0f*m_dScale),
	               qRound(contentsRect().top()+120.0f*m_dScale),
	               qRound(contentsRect().width()-8.0f*m_dScale),
	               qRound(129.0f*m_dScale) );
}

QRectF
DesktopLayout::getTodaysTempRect() const
{
	return QRectF( qRound(contentsRect().left() + 5.0f*m_dScale),
	               qRound(contentsRect().top() + 40.0f*m_dScale),
	               qRound(68.0f*m_dScale),
	               qRound(45.0*m_dScale) );
}

QRectF
DesktopLayout::getTodaysIconRect() const
{
	return QRectF( qRound(contentsRect().left() + 83.0f*m_dScale),
	               qRound(contentsRect().top() + 7.0f*m_dScale),
	               qRound(88.0f*m_dScale),
	               qRound(88.0f*m_dScale) );
}

QRectF
DesktopLayout::getCurrentTempRect() const
{
	return QRectF( qRound(contentsRect().left() + 170.0f*m_dScale),
	               qRound(contentsRect().top()  +   1.0f*m_dScale),
	               qRound(100.0f*m_dScale),
	               qRound( 45.0f*m_dScale) );
}

QRectF
DesktopLayout::getSateliteRect() const
{
	return QRectF( qRound(contentsRect().left()  +  4.0f * m_dScale),
	               qRound(contentsRect().top()   + 55.0f * m_dScale),
	               qRound(contentsRect().width() -  9.0f * m_dScale),
	               qRound(185.0f * m_dScale) );
}

QRectF
DesktopLayout::getForecastTempRect( const int day ) const
{
	if( day < 1 || day > 5 )
		return QRectF();

	if( forecastDays() == 1 && day == 1 )
	{
		return QRectF( qRound(m_detailsRect.left()),
		               qRound(m_detailsRect.top() + 40.0f*m_dScale),
		               qRound(75.0f*m_dScale),
		               qRound(45.0*m_dScale) );
	}
	const double dColumnWidth = m_detailsRect.width() / (float)forecastDays();
	return QRectF( qRound(m_detailsRect.left() + float(day-1)*dColumnWidth + 2.0*m_dScale),
	               qRound(m_detailsRect.top() + 87.0f*m_dScale),
	               qRound(dColumnWidth-4.0*m_dScale),
	               qRound(40.0*m_dScale) );
}

QRectF
DesktopLayout::getForecastIconRect( const int day ) const
{
	if( day < 1 || day > 5 )
		return QRectF();

	if( forecastDays() == 1 && day == 1 )
	{
		return QRectF( qRound(m_detailsRect.left() + 80.0f*m_dScale),
		               qRound(m_detailsRect.top() + 40.0f*m_dScale),
		               qRound(88.0f*m_dScale),
		               qRound(88.0f*m_dScale) );
	}
	const double dIconSize( 50.0f*m_dScale );
	const double dColumnWidth = m_detailsRect.width() / (float)forecastDays();
	return QRectF( qRound(m_detailsRect.left() + float(day-1)*dColumnWidth + (dColumnWidth-dIconSize)/2.0),
	               qRound(m_detailsRect.top() + 35.0f*m_dScale),
	               qRound(dIconSize),
	               qRound(dIconSize) );
}

QRectF
DesktopLayout::getForecastDayNamesRect() const
{
	return QRectF( m_detailsRect.left(),
	               m_detailsRect.top(),
	               m_detailsRect.width(),
	               qRound(30.0f*m_dScale) );
}

QRectF
DesktopLayout::getDetailsArrowRect( const bool bForward ) const
{
	const qreal dButtonSize = qRound(20.0f*m_dScale);
	qreal dXPos;
	if( bForward )
		dXPos = m_detailsRect.right()-(4.0f*m_dScale+dButtonSize);
	else
		dXPos = m_detailsRect.left()+(4.0*m_dScale);
	return QRectF( qRound(dXPos),
	               qRound(m_detailsRect.top() + 3.0f*m_dScale),
	               dButtonSize,
	               dButtonSize );
}
