#include <qbitmap.h>
#include "qwt3d_label.h"
#include "qwt3d_plot.h"
#include "../3rdparty/gl2ps/gl2ps.h"

using namespace Qwt3D;

bool Label::devicefonts_ = false;

Label::Label()
{
	init();
}

Label::Label(const QString & family, int pointSize, int weight, bool italic)
{
	init(family, pointSize, weight, italic);
}


void Label::init(const QString & family, int pointSize, int weight, bool italic)
{
	init();
	font_ = QFont(family, pointSize, weight, italic );
}

void Label::init()
{
	beg_ = Triple(0.0, 0.0, 0.0);
	end_ = beg_;
	pos_ = beg_;
	setColor(0,0,0);
	font_ = QFont();
	anchor_ = BottomLeft;
	gap_ = 0;
	width_ = 0.0;
	height_ = 0.0;
}

void Label::useDeviceFonts(bool val)
{
	devicefonts_ = val;
}

void Label::setFont(const QFont& f)
{
    if ( font_ == f ) {
        return;
    }
    font_ = f;
}

void Label::setFont(const QString & family, int pointSize, int weight, bool italic)
{
    setFont( QFont(family, pointSize, weight, italic ) );
}

void Label::setString(QString const& s)
{
  text_ = s;
}

const QString& Label::string() const
{
   return text_;
}

void Label::setColor(double r, double g, double b, double a)
{
  Drawable::setColor(r,g,b,a);
  flagforupdate_ = true;
}	

void Label::setColor(Qwt3D::RGBA rgba)
{
  Drawable::setColor(rgba);
  flagforupdate_ = true;
}

/**
example:

\verbatim

   Anchor TopCenter (*)  resp. BottomRight(X) 

   +----*----+
   |  Pixmap |
   +---------X

\endverbatim
*/
void Label::setPosition(Triple pos, ANCHOR a)
{
    use_relpos_ = false;
	anchor_ = a;
	pos_ = pos;
}

void Label::setRelPosition(Tuple rpos, ANCHOR a)
{
	double ot = 0.99;
    relpos_ = Triple(rpos.x, rpos.y, ot);
    anchor_ = a;
    use_relpos_ = true;
}

QImage Label::createImage(double angle)
{
	QRect r = QRect(QPoint(0, 0), QFontMetrics(font_).size(Qwt3D::SingleLine, text_));
	int textWidth = r.width();
	int textHeight = r.height();

	double aux_a = angle;
	if (aux_a > 270)
		aux_a -= 270;
	if (aux_a >= 180)
		aux_a -= 180;
	if (aux_a > 90)
		aux_a -= 90;

	double rad = aux_a*M_PI/180.0;

	int w = 0, h = 0;
	if ((angle >= 0 && angle <= 90) || (angle >= 180 && angle <= 270)){
		w = qRound(fabs(textWidth*cos(rad) + textHeight*sin(rad)));
		h = qRound(fabs(textWidth*sin(rad) + textHeight*cos(rad)));
	} else {
		w = qRound(fabs(textWidth*sin(rad) + textHeight*cos(rad)));
		h = qRound(fabs(textWidth*cos(rad) + textHeight*sin(rad)));
	}

	width_ = w;
	height_ = h;

	QPixmap pm_ = QPixmap(w, h);

	if (plot() && plot()->isExportingVector() && plot()->vectorExportFormat() != GL2PS_PDF){
		Qwt3D::RGBA rgba = plot()->backgroundRGBAColor();
		pm_.fill(GL2Qt(rgba.r, rgba.g, rgba.b));
	} else
		pm_.fill(Qt::transparent);

	QPainter p(&pm_);

	if (angle >= 270)
		p.translate(textHeight*cos(rad), 0.0);
	else if (angle >= 180)
		p.translate(w, textHeight*cos(rad));
	else if (angle > 90)
		p.translate(textWidth*sin(rad), h);
	else
		p.translate(0.0, textWidth*sin(rad));

	p.rotate(-angle);
	p.translate(0.0, textHeight - QFontMetrics(font_).descent());

	p.setFont( font_ );
	p.setPen(Qt::SolidLine);
	p.setPen(GL2Qt(color.r, color.g, color.b));
	p.drawText(0, 0, text_);
	p.end();

	return QGLWidget::convertToGLFormat(pm_.toImage());
}

/**
Adds an additional shift to the anchor point. This happens in a more or less intelligent manner
depending on the nature of the anchor:
\verbatim
anchor type         shift

left aligned         -->
right aligned        <--
top aligned          top-down            
bottom aligned       bottom-up
\endverbatim
The unit is user space dependend (one pixel on screen - play around to get satisfying results)
*/
void Label::adjust(int gap)
{
	gap_ = gap;
}

void Label::convert2screen()
{
	Triple start = World2ViewPort(pos_);
	
	switch (anchor_)
	{
		case BottomLeft :
			beg_ = pos_;
			break;
		case BottomRight:
			beg_ = ViewPort2World(start - Triple(width() + gap_, 0, 0));
			break;
		case BottomCenter:
			beg_ = ViewPort2World(start - Triple(width() / 2, -gap_, 0));
			break;
		case TopRight:
			beg_ = ViewPort2World(start - Triple(width() + gap_, height(), 0));
			break;
		case TopLeft:
			beg_ = ViewPort2World(start - Triple(-gap_, height(), 0));
			break;
		case TopCenter:
			beg_ = ViewPort2World(start - Triple(width() / 2, height() + gap_, 0));
			break;
		case CenterLeft:
			beg_ = ViewPort2World(start - Triple(-gap_, height() / 2, 0));
			break;
		case CenterRight:
			beg_ = ViewPort2World(start - Triple(width() + gap_, height() / 2, 0));
			break;
		case Center:
			beg_ = ViewPort2World(start - Triple(width() / 2, height() / 2, 0));
			break;
		default:
			break;
	}
	start = World2ViewPort(beg_);
	end_ = ViewPort2World(start + Triple(width(), height(), 0));	
}

const char * Label::fontname()
{
	const char *name = "Helvetica";
	if (font_.family() == "Times New Roman"){
		name = "Times";
		if (font_.bold() && font_.italic ())
			name = "Times-BoldItalic";
		else if (font_.italic())
			name = "Times-Italic";
		else if (font_.bold())
			name = "Times-Bold";
	} else if (font_.family() == "Courier" || font_.family() == "Courier New"){
		name = "Courier";
		if (font_.bold() && font_.italic ())
			name = "Courier-BoldOblique";
		else if (font_.italic())
			name = "Courier-Oblique";
		else if (font_.bold())
			name = "Courier-Bold";
	} else {
		if (font_.bold() && font_.italic ())
			name = "Helvetica-BoldOblique";
		else if (font_.italic())
			name = "Helvetica-Oblique";
		else if (font_.bold())
			name = "Helvetica-Bold";
	}

	return (const char*) name;
}

void Label::draw(double angle)
{
	if (!plot() || !plot()->isVisible())
		return;

	if (text_.isEmpty())
		return;

	if ( use_relpos_ ) {
		getMatrices(modelMatrix, projMatrix, viewport);
		beg_ = relativePosition(relpos_);
		setPosition(beg_, anchor_);
		use_relpos_ = true;// reset the flag
	}

	GLboolean b;
	GLint func;
	GLdouble v;
	glGetBooleanv(GL_ALPHA_TEST, &b);
	glGetIntegerv(GL_ALPHA_TEST_FUNC, &func);
	glGetDoublev(GL_ALPHA_TEST_REF, &v);

	glEnable (GL_ALPHA_TEST);
	glAlphaFunc (GL_NOTEQUAL, 0.0);

	convert2screen();
	glRasterPos3d(beg_.x, beg_.y, beg_.z);

	if (plot()->isExportingVector()){
		if (devicefonts_)
			drawDeviceText(QWT3DLOCAL8BIT(text_), fontname(), font_.pointSize(), pos_, color, anchor_, gap_, angle);
		else {
			QImage tex_ = createImage(angle);
			drawDevicePixels(tex_.width(), tex_.height(), GL_RGBA, GL_UNSIGNED_BYTE, tex_.bits());
		}
	} else {
		if (!angle){
			Triple start = World2ViewPort(beg_);
			start = ViewPort2World(start + Triple(0, QFontMetrics(font_).descent(), 0));
			plot()->qglColor(GL2Qt(color.r, color.g, color.b));
			plot()->renderText(start.x, start.y, start.z, text_, font_);
		} else {
			QImage tex_ = createImage(angle);
			drawDevicePixels(tex_.width(), tex_.height(), GL_RGBA, GL_UNSIGNED_BYTE, tex_.bits());
		}
	}

	glAlphaFunc(func,v);
	Enable(GL_ALPHA_TEST, b);
}

double Label::width() const
{
	if (width_ > 0.0 && height_ > 0.0)
		return width_;

	return QRect(QPoint(0, 0), QFontMetrics(font_).size(Qwt3D::SingleLine, text_)).width();
}

double Label::height() const
{
	if (width_ > 0.0 && height_ > 0.0)
		return height_;

	return QRect(QPoint(0, 0), QFontMetrics(font_).size(Qwt3D::SingleLine, text_)).height();
}

double Label::textHeight() const
{
	return QRect(QPoint(0, 0), QFontMetrics(font_).size(Qwt3D::SingleLine, text_)).height();
}
