/***************************************************************************
 *   Copyright (C) 2011 by Jeremy Burton   *
 *   jburton@39net-w04   *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <math.h>
#include <QFont>
#include <QPainter>

#include <stdio.h>

#include "dom.h"
#include "textitem.h"
#include "textitem2.h"

#define realtodev(n,r) ((n)/25.4*(r))
#define devtoreal(n,r) ((n)/(r)*25.4)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

textitem2::textitem2(const QString &s) : textitem(s)
{
/*
  fontfamily = "Arial";
  fontweight = QFont::Normal;
  fontstretch = 100.0;
  spacing = 1.0;
  fontheight = 10.0;
  angle =0.0;
  str = s;
  refchar = 'X';
  forward = true;
  smallcaps = false;
*/
  radius1 = 60.0;
  radius2 = 40.0;
  circular = false;
  justify = JustifyLeft;
}

////////////////////////////////////////////////////////////////////////////////

baseitem *textitem2::dup()
{
  textitem2 *item = new textitem2;
  *item = *this;
  return item;
}

////////////////////////////////////////////////////////////////////////////////

QString textitem2::describe()
{
  return QString("Text2: %1").arg(str);
}

/*
int textitem2::reftext_height(QPainter &painter,QFont &font)
{
  QFontMetrics *fontmetrics;
  QRect rect;
  int y1,y2,ymin=0,ymax=0;

  fontmetrics = new QFontMetrics(font,painter.device());

  for (int i=0;i<refchar.size();i++)
  {
    rect = fontmetrics->boundingRect(refchar.at(i));
    y1 = rect.y();
    y2 = y1+rect.height();
    if (i==0)
    {
      ymin = y1;
      ymax = y2;
    }
    else
    {
      if (y1<ymin) ymin=y1;
      if (y2>ymax) ymax=y2;
    }
  }

  delete fontmetrics;

  if (ymax==ymin)
    return 1;
  else
    return ymax-ymin;
}
*/

void textitem2::paint_handles(QPainter &painter, double zoom)
{
/*  double
    ang1 = DegToRad(angle),
    ang2 = DegToRad(anchorangle);*/
  int
    rx1 = radius1*zoom,
    ry1 = radius2*zoom,
    rx2 = (radius1+fontheight)*zoom,
    ry2 = (radius2+fontheight)*zoom,
    router = ry2+ANGLE_HANDLE_EXTEND;
  QPoint
    ctr(0,0),
    ctr1(centre.x()*zoom,-centre.y()*zoom);
  QPen
    pen1(Qt::DashLine);

  //Using NON-rotated,non-item centred canvas
  if (!centrelock) move_handle = ctr1;
  if (!anglelock)
  {
    angle_handle.setPolar(ctr1,router,angle);
    anchorangle_handle.setPolar(ctr1,rx1-ANGLE_HANDLE_SIZE*2,ry1-ANGLE_HANDLE_SIZE*2,anchorangle);
    anchorangle_handle.rotate(ctr1,angle);
  }
  if (!sizelock)
  {
    if (circular)
    {
      radius1_handle.setPolar(ctr1,rx1,ry1,45.0);
      radius1_handle.rotate(ctr1,angle);
      //paint_handle_size(painter,ctr1,rx1,ry1,45.0);
      fontheight_handle.setPolar(ctr1,rx2,ry2,45.0);
      fontheight_handle.rotate(ctr1,angle);
      //paint_handle_size(painter,ctr1,rx2,ry2,45.0);
    }
    else
    {
      radius1_handle.setPolar(ctr1,rx1,ry1,90.0);
      radius1_handle.rotate(ctr1,angle);
      radius2_handle.setPolar(ctr1,rx1,ry1,0.0);
      radius2_handle.rotate(ctr1,angle);
      //paint_handle_size(painter,ctr1,rx1,ry1,90.0);
      //paint_handle_size(painter,ctr1,rx1,ry1,0.0);
      fontheight_handle.setPolar(ctr1,rx2,ry2,0.0);
      fontheight_handle.rotate(ctr1,angle);
      //paint_handle_size(painter,ctr1,rx2,ry2,0.0);
    }
  }

//painter.setPen(Qt::black);
//painter.setBrush(Qt::NoBrush);
//painter.drawEllipse(anchorangle_handle,5,5);

//painter.save();
  painter.translate(centre.x()*zoom,-centre.y()*zoom);
  painter.rotate(angle);

  //Ellipses...
  pen1.setColor(Qt::blue);
  painter.setPen(pen1);
  painter.setBrush(Qt::NoBrush);
  painter.drawEllipse(ctr,rx1,ry1);
  painter.drawEllipse(ctr,rx2,ry2);

  //cross axes...
  pen1.setColor(Qt::gray);
  painter.setPen(pen1);
  painter.drawLine(ctr.x(),-ry2,ctr.x(),ry2);
  painter.drawLine(-rx2,ctr.y(),rx2,ctr.y());

  paint_handle_move(painter,ctr);
  if (circular)
  {
    paint_handle_size(painter,ctr,rx1,ry1,45.0);
    paint_handle_size(painter,ctr,rx2,ry2,45.0);
  }
  else
  {
    paint_handle_size(painter,ctr,rx1,ry1,90.0);
    paint_handle_size(painter,ctr,rx1,ry1,0.0);
    paint_handle_size(painter,ctr,rx2,ry2,0.0);
  }
  paint_handle_angle2(painter,ctr,ry2);
  paint_handle_anchorangle(painter,ctr,rx1,ry1);
//painter.restore();
//  paint_handle_angle(painter,ctr,std::max(rx2,ry2));
}

//Work out tangent angle on ellipse - empirical method - go .01 rad either side and calculate the angle of the line
double ellipse_tan_angle(double ang,double r1,double r2)
{
  double
    small_angle = 0.01,
    p1x = r1*sin(ang-small_angle),
    p1y = -r2*cos(ang-small_angle),
    p2x = r1*sin(ang+small_angle),
    p2y = -r2*cos(ang+small_angle);
  return atan2(p2x-p1x,p2y-p1y); //Tangent angle = char angle
}

void textitem2::paint(QPainter &painter, bool selected, double zoom)
{
  struct chinfo_s
  {
    double
      width, width2,
      //angleinc,
      //angle,
      tht;
    int
      p0x, p0y;
  };

  double
    ang1 = DegToRad(anchorangle),
    r1 = radius1*zoom,
    r2 = radius2*zoom,
    inc1 = (forward ? 1.0:-1.0)/std::max(r1,r2);  //2.0*pi / (std::min(r1,r2)*2.0*pi); //radians/pixel;
  int
    dpix = painter.device()->logicalDpiX(),
    dpiy = painter.device()->logicalDpiY(),
    h = fontheight*zoom;
  QPen
    pen1(Qt::SolidLine);
  QColor
    scolor(strokecolor),
    fcolor(fillcolor);
  QFont
    font;
  QRectF
    rect;
  QPolygon
    poly1,poly2,poly3;
  struct chinfo_s
    chinfos[str.size()], *chinfo;

  font = QFont(fontfamily, 72);
  font.setWeight(fontweight);
  font.setStretch(fontstretch);
//font.setStyle(QFont::StyleItalic);
  if (smallcaps)
    font.setCapitalization(QFont::SmallCaps);

  painter.setPen(Qt::SolidLine);
  double n = /*72.0/72.0**/(double)dpiy/(double)reftext_height(painter,font);
  font.setPixelSize(fontheight*n*zoom+0.5); //***** 'zoom' pix per mm scale, round up *****//
  painter.setFont(font);

  // Find the widths of each character
  for (int i=0;i<str.size();i++)
  {
    chinfo = &chinfos[i];

//#ifdef DRAW_TEXT_AS_PATH
//QPainterPath path;
//    path.addText(0,0,font,str.at(i));
//    rect = path.boundingRect();
//#else
    rect = painter.boundingRect(painter.window(),Qt::TextSingleLine,str.at(i));
//#endif
    chinfo->width = rect.width()*spacing;
    chinfo->width2 = chinfo->width/2.0;
  }

  // Set up stroke & fill colors etc.
  if (!selected)
  {
    scolor.setAlpha(127);
    fcolor.setAlpha(127);
  }

  if (stroke)
  {
    pen1.setWidth(strokewidth*zoom);
    pen1.setJoinStyle(Qt::MiterJoin);
    pen1.setColor(scolor);
    painter.setPen(pen1);
  }
  else
    painter.setPen(Qt::NoPen);

  if (fill)
    painter.setBrush(fcolor);
  else
    painter.setBrush(Qt::NoBrush);

  painter.translate(centre.x()*zoom,-centre.y()*zoom);
  painter.rotate(angle);

//TODO: how to centre text??
//printf("inc=%f\n",inc2);
  for (int i=0;i<str.size();i++)
  {
    chinfo = &chinfos[i];

    //v3
    //P0 is the centre point for the char
    for (int j=0;j<1000;j++)
    {
      //chinfo->angle = ang2;
      chinfo->p0x = r1*sin(ang1);
      chinfo->p0y = r2*cos(ang1);
      chinfo->tht = ellipse_tan_angle(ang1,r1,r2);
      double
	s = sin(chinfo->tht),
	c = cos(chinfo->tht),
	p1x = chinfo->width2*s,		// P1 is the offset from p0 for 1/2 char width
	p1y = -chinfo->width2*c,
	p2x = h*c,			// P2 is the offset from p0 for char height
	p2y = h*s;
      poly2.setPoints(4,
	(int)(chinfo->p0x-p1x), -(int)(chinfo->p0y-p1y),
	(int)(chinfo->p0x+p1x), -(int)(chinfo->p0y+p1y),
	(int)(chinfo->p0x+p2x+p1x), -(int)(chinfo->p0y+p2y+p1y),
	(int)(chinfo->p0x+p2x-p1x), -(int)(chinfo->p0y+p2y-p1y)
      );

      if (i==0)
	break;

      poly3 = poly2.intersected(poly1);
      if (poly3.size() == 0) break;
      ang1 += inc1;
    }
/*
printf("poly2: (%d,%d) (%d,%d) (%d,%d) (%d,%d)\n",
	(int)(chinfo->p0x-p1x), (int)(chinfo->p0y-p1y),
	(int)(chinfo->p0x+p1x), (int)(chinfo->p0y+p1y),
	(int)(chinfo->p0x+p2x+p1x), (int)(chinfo->p0y+p2y+p1y),
	(int)(chinfo->p0x+p2x-p1x), (int)(chinfo->p0y+p2y-p1y)
);
*/
//painter.drawPolygon(poly2);
//painter.setBrush(Qt::green);
//painter.drawEllipse(QPoint(p0x,-p0y),4,4);	// show P0
//painter.drawLine(p0x,p0y,0,0);	//Show radial to p0

    painter.save();
    painter.translate(chinfo->p0x,-chinfo->p0y);
    painter.rotate((forward?90.0:270.0)-RadToDeg(chinfo->tht));
    if (drawpath)
//#ifdef DRAW_TEXT_AS_PATH
    {
      QPainterPath path;
      path.addText(-chinfo->width2,0,font,str.at(i));
      painter.drawPath(path);
//#else
    }
    else
      painter.drawText(QPoint(-chinfo->width2,forward?0:h),str.at(i));
//#endif
//painter.drawRect(-xi,0,chinfo->width,forward?-h:h);	//Show char box
    painter.restore();

    //Initial increment guess: 80% of angular step on major radius (for all but last char)
    // (chinfo->width/2.0+chinfos[i+1].width/2.0) / (2.0*pi*std::max(r1,r2)) * 2.0*pi * (forward ? 0.8 : -0.8);
    if ((i+1)<str.size())
      ang1 += (chinfo->width+chinfos[i+1].width) / (2.0*std::max(r1,r2)) * (forward ? 0.8 : -0.8);
//(chinfo->width+chinfos[i+1].width) / std::max(r1,r2) * 2.0 * (forward ? 0.8 : -0.8);

    poly1 = poly2;
  }
}

void textitem2::output(QPainter &painter)
{
  int
    dpix = painter.device()->logicalDpiX(),
    dpiy = painter.device()->logicalDpiY();
  double
    ang1 = DegToRad(anchorangle),
    r1 = realtodev(radius1,dpix),
    r2 = realtodev(radius2,dpiy),
    inc1 = (forward ? 1.0:-1.0)/std::max(r1,r2),  //2.0*pi / (std::min(r1,r2)*2.0*pi); //radians/pixel;
    h = realtodev(fontheight,dpiy);
  QFont
    font;
  QPen
    pen1(strokecolor);

//printf("DPI=%d,%d\n",dpix,dpiy);

  painter.translate(realtodev(centre.x(),dpix),-realtodev(centre.y(),dpiy));
  painter.rotate(angle);

  QRectF rect;
  struct chinfo_s
  {
    double
      width, width2,
      //angleinc,
      //angle,
      tht;
    double p0x,p0y;
  } chinfos[str.size()], *chinfo;

  font = QFont(fontfamily, 72);
  font.setWeight(fontweight);
  font.setStretch(fontstretch);
  if (smallcaps)
    font.setCapitalization(QFont::SmallCaps);

/*v2*/
  double n = /*72.0/72.0**/(double)dpiy/(double)reftext_height(painter,font);

//printf("Font fontheight=%fmm, rect.height=%fmm\n",fontheight,devtoreal(rect.height(),dpiy));
//printf("Font n=%f, dpiy=%d\n",n,dpiy);
  //font = QFont("Arial", fontheight/devtoreal(rect.height(),dpiy)*fontheight/25.4*72.0);
  font.setPointSizeF(mmtopt(fontheight)*n);
  //fontmetrics = new QFontMetrics(font,painter.device());
  painter.setFont(font);

  if (drawpath)
{
    font.setPixelSize(realtodev(fontheight,dpiy)*n);
//printf("Font pixelSize=%d\n",font.pixelSize());
}

//TODO: how to centre this??
  QPolygon poly1,poly2,poly3;

  for (int i=0;i<str.size();i++)
  {
    chinfo = &chinfos[i];

    rect = painter.boundingRect(painter.window(),Qt::TextSingleLine,str.at(i));
    chinfo->width = rect.width()*spacing;
    chinfo->width2 = chinfo->width/2.0;
  }

  //Set line & fill colours
  if (stroke)
  {
    pen1.setWidth(realtodev(strokewidth,dpix));
    pen1.setJoinStyle(Qt::MiterJoin);
    painter.setPen(pen1);
  }
  else
    painter.setPen(Qt::NoPen);

  if (fill)
    painter.setBrush(fillcolor);
  else
    painter.setBrush(Qt::NoBrush);

  //Draw each character
  for (int i=0;i<str.size();i++)
  {
    chinfo = &chinfos[i];

    //v3
    //P0 is the centre point for the char
    for (int j=0;j<1000;j++)
    {
      //chinfo->angle = ang2;
      chinfo->p0x = r1*sin(ang1);
      chinfo->p0y = r2*cos(ang1);
      chinfo->tht = ellipse_tan_angle(ang1,r1,r2);
      double
	s = sin(chinfo->tht),
	c = cos(chinfo->tht),
	p1x = chinfo->width2*s,		// P1 is the offset from p0 for 1/2 char width
	p1y = -chinfo->width2*c,
	p2x = h*c,			// P2 is the offset from p0 for char height
	p2y = h*s;
      poly2.setPoints(4,
	(int)(chinfo->p0x-p1x), -(int)(chinfo->p0y-p1y),
	(int)(chinfo->p0x+p1x), -(int)(chinfo->p0y+p1y),
	(int)(chinfo->p0x+p2x+p1x), -(int)(chinfo->p0y+p2y+p1y),
	(int)(chinfo->p0x+p2x-p1x), -(int)(chinfo->p0y+p2y-p1y)
      );

      if (i==0)
	break;

      poly3 = poly2.intersected(poly1);
      if (poly3.size() == 0) break;
      ang1 += inc1;
    }
//painter.drawPolygon(poly2);

    painter.save();
    painter.translate(chinfo->p0x,-chinfo->p0y);
    painter.rotate((forward?90.0:270.0)-RadToDeg(chinfo->tht));
    if (drawpath)
//#ifdef DRAW_TEXT_AS_PATH
    {
      QPainterPath path;
      path.addText(-chinfo->width2,0,font,str.at(i));
      painter.drawPath(path);
//#else
    }
    else
      painter.drawText(QPoint(-chinfo->width2,forward?0:h),str.at(i));
//#endif
//painter.drawRect(-chinfo->width2,0,chinfo->width,forward?-h:h);	//Show char box
    painter.restore();

    //Initial increment guess: 80% of angular step on major radius (for all but last char)
    // (chinfo->width/2.0+chinfos[i+1].width/2.0) / (2.0*pi*std::max(r1,r2)) * 2.0*pi * (forward ? 0.8 : -0.8);
    if ((i+1)<str.size())
      ang1 += (chinfo->width+chinfos[i+1].width) / (2.0*std::max(r1,r2)) * (forward ? 0.8 : -0.8);

    poly1 = poly2;
  }
}

void textitem2::toDom(QDomDocument &doc,QDomElement &parent)
{
  QDomElement aw = doc.createElement( "textitem2" );

  //aw.setAttribute(QString("forward"),forward);

  textitem::toDom_content(doc,aw);

  //toDom_Text(doc,aw,"radius2",radius2);

  parent.appendChild(aw);
}

void textitem2::fromDom(QDomDocument &doc,QDomElement &element)
{
  textitem::fromDom(doc,element);

  //forward = element.attribute("forward", "1").toInt() != 0;

/*
  QDomNode n = element.firstChild();
  while(!n.isNull()) 
  {
    QDomElement e = n.toElement(); // try to convert the node to an element.
    if(!e.isNull())
    {
      if (e.tagName() == "radius2")
	radius2 = e.text().toDouble();
    }
    n = n.nextSibling();
  }
*/
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
