/***************************************************************************
 *   Copyright (C) 2005 by David Saxton                                    *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/

#include "dpline.h"
#include "libraryitem.h"
#include "resizeoverlay.h"
#include "variant.h"

#include <cmath>
#include <kiconloader.h>
#include <klocale.h>
#include <qpainter.h>


//BEGIN class DPLine
Item* DPLine::construct( ItemDocument *itemDocument, bool newItem, const char *id )
{
	return new DPLine( itemDocument, newItem, id );
}

LibraryItem* DPLine::libraryItem()
{
	return new LibraryItem(
		QString("dp/line"),
		i18n("Line"),
		i18n("Other"),
		KGlobal::iconLoader()->loadIcon( "text", KIcon::Small ),
		LibraryItem::lit_drawpart,
		DPLine::construct );
}

DPLine::DPLine( ItemDocument *itemDocument, bool newItem, const char *id )
	: DrawPart( itemDocument, newItem, id ? id : "line" )
{
	m_pLineOverlay = new LineOverlay(this);
	m_name = i18n("Line");
	m_desc = i18n("Select the line to position the end points");
	
	createProperty( "line-color", Variant::Type::Color );
	property("line-color")->setCaption( i18n("Line Color") );
	property("line-color")->setValue(Qt::black);
	
	createProperty( "line-width", Variant::Type::Int );
	property("line-width")->setCaption( i18n("Line Width") );
	property("line-width")->setMinValue(1);
	property("line-width")->setMaxValue(1000);
	property("line-width")->setValue(1);
	
	createProperty( "line-style", Variant::Type::PenStyle );
	property("line-style")->setCaption( i18n("Line Style") );
	property("line-style")->setAdvanced(true);
	setDataPenStyle( "line-style", Qt::SolidLine );
	
	createProperty( "cap-style", Variant::Type::PenCapStyle );
	property("cap-style")->setCaption( i18n("Cap Style") );
	property("cap-style")->setAdvanced(true);
	setDataPenCapStyle( "cap-style", Qt::FlatCap );
}

DPLine::~DPLine()
{
}

void DPLine::setSelected( bool yes )
{
	if ( yes == isSelected() )
		return;
	
	DrawPart::setSelected(yes);
	m_pLineOverlay->showResizeHandles(yes);
}


void DPLine::dataChanged()
{
	setPen( QPen( dataColor("line-color"),
			unsigned( dataInt("line-width") ),
			getDataPenStyle("line-style"),
			getDataPenCapStyle("cap-style"),
			Qt::MiterJoin ) );
	
	postResize(); // in case the pen width has changed
	update();
}


void DPLine::postResize()
{
	int x1 = offsetX();
	int y1 = offsetY();
	int x2 = x1+width();
	int y2 = y1+height();
	
	QPointArray p(4);
	int pw = pen().width();
	int dx = QABS(x1-x2);
	int dy = QABS(y1-y2);
	pw = pw*4/3+2; // approx pw*sqrt(2)
	int px = x1<x2 ? -pw : pw ;
	int py = y1<y2 ? -pw : pw ;
	if ( dx && dy && (dx > dy ? (dx*2/dy <= 2) : (dy*2/dx <= 2)) ) {
	// steep
		if ( px == py ) {
			p[0] = QPoint(x1   ,y1+py);
			p[1] = QPoint(x2-px,y2   );
			p[2] = QPoint(x2   ,y2-py);
			p[3] = QPoint(x1+px,y1   );
		} else {
			p[0] = QPoint(x1+px,y1   );
			p[1] = QPoint(x2   ,y2-py);
			p[2] = QPoint(x2-px,y2   );
			p[3] = QPoint(x1   ,y1+py);
		}
	} else if ( dx > dy ) {
	// horizontal
		p[0] = QPoint(x1+px,y1+py);
		p[1] = QPoint(x2-px,y2+py);
		p[2] = QPoint(x2-px,y2-py);
		p[3] = QPoint(x1+px,y1-py);
	} else {
	// vertical
		p[0] = QPoint(x1+px,y1+py);
		p[1] = QPoint(x2+px,y2-py);
		p[2] = QPoint(x2-px,y2-py);
		p[3] = QPoint(x1-px,y1+py);
	}
	setItemPoints( p, false );
}


void DPLine::drawShape( QPainter & p )
{
	int x1 = int(x()+offsetX());
	int y1 = int(y()+offsetY());
	int x2 = x1+width();
	int y2 = y1+height();
	
	p.drawLine( x1, y1, x2, y2 );
}
//END class DPLine


//BEGIN class DPArrow
Item* DPArrow::construct( ItemDocument *itemDocument, bool newItem, const char *id )
{
	return new DPArrow( itemDocument, newItem, id );
}

LibraryItem* DPArrow::libraryItem()
{
	return new LibraryItem(
		QString("dp/arrow"),
		i18n("Arrow"),
		i18n("Other"),
		KGlobal::iconLoader()->loadIcon( "text", KIcon::Small ),
		LibraryItem::lit_drawpart,
		DPArrow::construct );
}

DPArrow::DPArrow( ItemDocument *itemDocument, bool newItem, const char *id )
	: DPLine( itemDocument, newItem, id ? id : "arrow" )
{
	m_name = i18n("Arrow");
	
	// We don't want to use the square cap style as it screws up drawing our arrow head
	QStringList allowed = property("cap-style")->allowed();
	allowed.remove( DrawPart::penCapStyleToName( Qt::SquareCap ) );
	property("cap-style")->setAllowed(allowed);
}

DPArrow::~DPArrow()
{
}


void DPArrow::drawShape( QPainter & p )
{
	int x1 = int(x()+offsetX());
	int y1 = int(y()+offsetY());
	int x2 = x1+width();
	int y2 = y1+height();
	
	p.drawLine( x1, y1, x2, y2 );
	
	double dx = x2-x1;
	double dy = y2-y1;
	
	if ( dx == 0. && dy == 0. )
		return;
	
	double pi = 3.14159265358979323846264;
	double arrow_angle = ( dx == 0 ? (dy>0?(pi/2.):(-pi/2.)) : std::atan(dy/dx) );
	if ( dx < 0 )
		arrow_angle += pi;
	
	double head_angle = 0.6; // Angle of arrowhead
	double head_length = 10.;
	
	// Position of arrowhead
	int x3 = int( x2 + head_length*std::cos( pi + arrow_angle - head_angle ) );
	int y3 = int( y2 + head_length*std::sin( pi + arrow_angle - head_angle ) );
	int x4 = int( x2 + head_length*std::cos( pi + arrow_angle + head_angle ) );
	int y4 = int( y2 + head_length*std::sin( pi + arrow_angle + head_angle ) );
	
	// Draw arrowhead
	QPen pen = p.pen();
	pen.setCapStyle( Qt::RoundCap );
	p.setPen(pen);
	p.setBrush(pen.color());
	QPointArray pa(3);
	pa[0] = QPoint( x2, y2 );
	pa[1] = QPoint( x3, y3 );
	pa[2] = QPoint( x4, y4 );
	p.drawPolygon(pa);
	p.drawPolyline(pa);
// 	p.drawLine( x2, y2, x3, y3 );
// 	p.drawLine( x2, y2, x4, y4 );
}
//END class DPLine

