#include <QDebug>
#include <QRegExp>
#include <QGraphicsScene>

#include "headingobj.h"

extern bool debug;

/////////////////////////////////////////////////////////////////
// HeadingObj
/////////////////////////////////////////////////////////////////
HeadingObj::HeadingObj(QGraphicsItem *parent) :MapObj(parent)
{
    //qDebug() << "Const HeadingObj (s) ";
    init ();
}

HeadingObj::~HeadingObj()
{
//  qDebug() << "Destr. HeadingObj "<<heading;
    while (!textline.isEmpty())
	delete textline.takeFirst();
}

void HeadingObj::init()
{
    textwidth=40;
    color=QColor ("black");
    font=QFont();
    heading="";
    angle=0;	
}

void HeadingObj::copy(HeadingObj *other)
{
    MapObj::copy (other);
    textwidth=other->textwidth;
    color=other->color;
    font=other->font;
    setText (other->text() );
}

void HeadingObj::move(double x, double y)
{
    MapObj::move(x,y);

    qreal h;	// height of a textline
    qreal ho;	// offset of height while drawing all lines

    if (!textline.isEmpty() )
	h=textline.first()->boundingRect().height();
    else
	h=2;
    ho=0;
    for (int i=0; i<textline.size(); ++i)
    {
	textline.at(i)->setPos(x,y+ho);
	ho=ho+h;
    }	
}


void HeadingObj::moveBy(double x, double y)
{
    move (x+absPos.x(),y+absPos.y() );
}

void HeadingObj::positionBBox()
{
    bbox.setX (absPos.x());
    bbox.setY (absPos.y());
}

void HeadingObj::calcBBoxSize()
{   
    qreal w=0;
    qreal h=0;
    // Using Backspace an empty heading might easily be created, then there
    // would be textline.first()==NULL This can be worked around by the following, but
    // then no selection would be visible, thus we prevent it in ::setText()
    if (!textline.isEmpty() )
    {
	for (int i=0; i<textline.size(); i++)
	{
	    h+=textline.at(i)->boundingRect().height();
	    if (w<textline.at(i)->boundingRect().width() )
		w=textline.at(i)->boundingRect().width();
	}   
    } 
    bbox.setSize (QSizeF(w,h));
}

QGraphicsTextItem* HeadingObj::newLine(QString s)  
{
    QGraphicsTextItem *t=new QGraphicsTextItem (s,parentItem());
    t->setFont (font);
    t->setZValue(dZ_TEXT);
    t->setDefaultTextColor(color);
    t->setRotation (angle);
    return t;
}

void HeadingObj::setTransformOriginPoint (const QPointF & p)
{
    for (int i=0; i<textline.size(); i++)
    {
	textline.at(i)->setTransformOriginPoint (p);
    }
}

void HeadingObj::setRotation (const qreal &a)
{
    angle=a;
    for (int i=0; i<textline.size(); i++)
	textline.at(i)->setRotation (angle);
}

qreal HeadingObj::getRotation()
{
    return angle;
}

void HeadingObj::setText (QString s)  
{
    heading=s;

    // remove old textlines and prepare generating new ones
    while (!textline.isEmpty())
	delete textline.takeFirst();

    if (s.startsWith("<html>")||
	s.startsWith("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">")
    )
    {
	QGraphicsTextItem *t=new QGraphicsTextItem ();
	t->setFont (font);
	t->setZValue(dZ_TEXT);
	t->setHtml (s);
	t->setDefaultTextColor(color);
	t->setRotation (angle);
	scene()->addItem (t);
	textline.append (t);
    } else
    {
	// prevent empty textline, so at least a small selection stays
	// visible for this heading
	if (s.length()==0) s="  ";

	int i=0;	// index for actual search for ws
	int j=0;	// index of last ws
	int k=0;	// index of "<br>" or similar linebreak
	int br=0;	// width of found break, e.g. for <br> it is 4
	QRegExp re("<br.*/>");
	re.setMinimal (true);

	// set the text and wrap lines
	while (s.length()>0)
	{
	    // ok, some people wanted manual linebreaks, here we go
	    k=re.indexIn (s,i);
	    if (k>=0)
	    {
		br=re.cap(0).length();
		i=k;
	    } else
		i=s.indexOf (" ",i);
	    if (i<0 && j==0)
	    {   // no ws found at all in s
		// append whole s
		textline.append (newLine(s));
		s="";
	    } else
	    {
		if (i<0 && j>0)
		{	// no ws found in actual search
		    if (s.length()<=textwidth)
		    {
			textline.append (newLine(s));
			s="";
		    } else
		    {
			textline.append (newLine(s.left(j)));
			s=s.mid(j+1,s.length());
			j=0;
		    }	    
		} else
		{
		    if (i>= 0 && i<=static_cast <int> (textwidth))
		    {   // there is a ws in textwidth
			if (br>0)
			{
			    // here is a linebreak
			    textline.append (newLine(s.left(i)));
			    s=s.mid(i+br,s.length());
			    i=0;
			    j=0;
			    br=0;
			} else
			{
			    j=i;
			    i++;
			}
		    } else
		    {
			if (i>static_cast <int> (textwidth)  )
			{	
			    if (j>0)
			    {   // a ws out of textwidth, but we have also one in
				textline.append (newLine(s.left(j)));
				s=s.mid(j+1,s.length());
				i=0;
				j=0;
			    } else
			    {   // a ws out of text, but none in
				textline.append (newLine(s.left(i)));
				s=s.mid(i+1,s.length());
				i=0;
			    }
			}
		    } 
		}	  
	    }	    
	}
    } // ASCII heading with multiple lines
    setVisibility (visible);
    move (absPos.x(),absPos.y());
    calcBBoxSize();
}

QString HeadingObj::text ()
{
    return heading;
}

void HeadingObj::setFont (QFont f)
{
    if (font!=f) 
    {
	font=f;
	setText (text());
    }
}

QFont HeadingObj::getFont()
{
    return font;
}    
    
    
void HeadingObj::setColor (QColor c)
{
    if (color!=c)
    {
	color=c;
	for (int i=0; i<textline.size(); ++i)
	    // TextItem
	    textline.at(i)->setDefaultTextColor(c);
	    // SimpleTextItem
	    //textline.at(i)->setBrush(c);
    }	    
}

QColor HeadingObj::getColor()
{
    return color;
}    

void HeadingObj::setZValue (double z)
{
    for (int i=0; i<textline.size(); ++i)
	textline.at(i)->setZValue (z);
}

void HeadingObj::setVisibility (bool v)
{
    MapObj::setVisibility(v);
    for (int i=0; i<textline.size(); ++i)
	if (v)
	    textline.at(i)->show();
	else
	    textline.at(i)->hide();
}

qreal HeadingObj::getHeight ()
{
    return bbox.height();
}

qreal HeadingObj::getWidth()
{
    return bbox.width();
}

