#include <qbitmap.h>
#include "qwt3d_label.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);
	pm_ = QPixmap(0, 0);
	font_ = QFont();
	anchor_ = BottomLeft;
	gap_ = 0;
	flagforupdate_ = true;
}

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

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

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

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)
{
	anchor_ = a;
	pos_ = pos;
}

void Label::setRelPosition(Tuple rpos, ANCHOR a)
{
	double ot = 0.99;

	getMatrices(modelMatrix, projMatrix, viewport);
	beg_ = relativePosition(Triple(rpos.x, rpos.y, ot));
	setPosition(beg_, a);	
}

void Label::update()
{
	QPainter p;
	QFontMetrics fm(font_);

  QFontInfo info(font_);

  QRect r = 	QRect(QPoint(0,0),fm.size(Qwt3D::SingleLine, text_));//fm.boundingRect(text_)  misbehaviour under linux;
  
#if QT_VERSION < 0x040000
 		r.moveBy(0, -r.top());
#else
 		r.translate(0, -r.top());
#endif
	
	pm_ = QPixmap(r.width(), r.bottom());

	if (pm_.isNull()) // else crash under linux
	{
		r = 	QRect(QPoint(0,0),fm.size(Qwt3D::SingleLine, QString(" "))); // draw empty space else //todo
#if QT_VERSION < 0x040000
 		r.moveBy(0, -r.top());
#else
 		r.translate(0, -r.top());
#endif
		pm_ = QPixmap(r.width(), r.bottom());		
	}
	
	QBitmap bm(pm_.width(),pm_.height());
#if QT_VERSION >= 0x040000 && defined(Q_WS_X11)
  bm.fill(Qt::white);
  p.begin( &bm );
    p.setPen(Qt::black);
    p.setFont(font_);
    p.drawText(0,r.height() - fm.descent() -1 , text_);
  p.end();

  pm_.setMask(bm);
  
  // avoids uninitialized areas in some cases
  pm_.fill(Qt::white);
  p.begin( &pm_ );
    p.setFont( font_ );
    p.setPen( Qt::SolidLine );
    p.setPen( GL2Qt(color.r, color.g, color.b) );

    p.drawText(0,r.height() - fm.descent() -1 , text_);
  p.end();

  buf_ = pm_.toImage();
#else
  bm.fill(Qt::color0);
	p.begin( &bm );
		p.setPen(Qt::color1);
		p.setFont(font_);
		p.drawText(0,r.height() - fm.descent() -1 , text_);
	p.end();

	pm_.setMask(bm);
  
  // avoids uninitialized areas in some cases
#if QT_VERSION < 0x040000
	pm_.fill();
#endif
	p.begin( &pm_ );
	  p.setFont( font_ );
	  p.setPen( Qt::SolidLine );
	  p.setPen( GL2Qt(color.r, color.g, color.b) );

	  p.drawText(0,r.height() - fm.descent() -1 , text_);
	p.end();     
#endif	       

#if QT_VERSION < 0x040000
  buf_ = pm_.convertToImage();
#else
  buf_ = pm_.toImage();
#endif
	
	tex_ = QGLWidget::convertToGLFormat( buf_ );	  // flipped 32bit RGBA ?		
}

/**
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));	
}

void Label::draw()
{
	if (flagforupdate_)
	{
		update();
		flagforupdate_ = false;
	}

	if (buf_.isNull())
		return;
		
	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);
 
	
	int w = tex_.width();
	int h = tex_.height();
 
	if (devicefonts_)
	{		
		drawDeviceText(QWT3DLOCAL8BIT(text_), "Courier", font_.pointSize(), pos_, color, anchor_, gap_);
	}
	else
	{
		drawDevicePixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, tex_.bits());
//    glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, tex_.bits());	
	}


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


double Label::width() const 
{ 
	return pm_.width(); 
}

double Label::height() const 
{ 
	return pm_.height(); 
}	
