// Copyright (C) 1999-2014
// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
// For conditions of distribution and use, see copyright notice in "copyright"

#include "contour.h"
#include "base.h"
#include "context.h"

Contour::Contour(Base* p, const char* c, int w, int d) 
  : parent(p), lineWidth(w), dash(d)
{
  colorName = dupstr(c);
  color = parent->getColor(colorName);

  previous_ = NULL;
  next_ = NULL;
}

Contour::Contour(Base* p, const char* c, int w, int d,
		 const List<Vertex>& cont) 
  : parent(p), lineWidth(w), dash(d)
{
  contours_ = cont;
  colorName = dupstr(c);
  color = parent->getColor(colorName);

  previous_ = NULL;
  next_ = NULL;
}

Contour::~Contour()
{
  if (colorName)
    delete [] colorName;
}

void Contour::render(Pixmap pmap, Coord::InternalSystem sys, int width, int height)
{
  if (contours_.head()) {
    XSetForeground(parent->display, parent->contourGC, color);
    int ww = lineWidth>=1 ? lineWidth : 1;

    if (!dash)
      XSetLineAttributes(parent->display, parent->contourGC, 
			 ww, LineSolid, CapButt, JoinMiter);
    else {
      char dl[2];
#ifdef _GWIN32
      dl[0] = parent->dlist[0]/2;
      dl[1] = parent->dlist[1]/2;
#else
      dl[0] = parent->dlist[0];
      dl[1] = parent->dlist[1];
#endif
      XSetDashes(parent->display, parent->contourGC, 0, dl, 2);
      XSetLineAttributes(parent->display, parent->contourGC, 
			 ww, LineOnOffDash, CapButt, JoinMiter);
    }

    BBox bb = BBox(0, 0, width, height);

    Vector u1 = contours_.current()->vector;
    while (contours_.next()) {
      Vector u2 = contours_.current()->vector;
      if (u1[0] != DBL_MAX && u2[0] != DBL_MAX) {
	Vector v1 = parent->mapFromRef(u1,sys);
	Vector v2 = parent->mapFromRef(u2,sys);

 	if (bb.isIn(v1) || bb.isIn(v2))
 	  XDrawLine(parent->display, pmap, parent->contourGC, 
 		    (int)v1[0], (int)v1[1], (int)v2[0], (int)v2[1]);
      }

      u1 = u2;
    }
  }
}

void Contour::ps(int mode)
{
  if (contours_.head()) {
    {
      ostringstream str;
      switch ((Widget::PSColorSpace)mode) {
      case Widget::BW:
      case Widget::GRAY:
	psColorGray(parent->getXColor(colorName), str);
	str << " setgray";
	break;
      case Widget::RGB:
	psColorRGB(parent->getXColor(colorName), str);
	str << " setrgbcolor";
	break;
      case Widget::CMYK:
	psColorCMYK(parent->getXColor(colorName), str);
	str << " setcmykcolor";
	break;
      }
      str << endl << ends;
      Tcl_AppendResult(parent->interp, str.str().c_str(), NULL);
    }  
  
    {
      ostringstream str;
      if (!dash) {
	str << lineWidth << " setlinewidth" << endl << "[] 0 setdash";
      }
      else {
	str << lineWidth << " setlinewidth" << endl
	    << '[' << parent->dlist[0] << ' ' << parent->dlist[1] 
	    << "] 0 setdash";
      }
      str << endl << ends;
      Tcl_AppendResult(parent->interp, str.str().c_str(), NULL);
    }

    // output stroke paths
    do {
      Vector u = contours_.current()->vector;
      if (u[0] != DBL_MAX) {
	ostringstream str;
	Vector v = parent->mapFromRef(u,Coord::CANVAS);
	str << "newpath " << endl
	    << v.TkCanvasPs(parent->canvas) << " moveto" << endl << ends;
	Tcl_AppendResult(parent->interp, str.str().c_str(), NULL);

	while (contours_.next()) {
	  Vector uu = contours_.current()->vector;
	  if (uu[0] != DBL_MAX) {
	    ostringstream str;
	    Vector vv = parent->mapFromRef(uu,Coord::CANVAS);
	    str << vv.TkCanvasPs(parent->canvas) << " lineto" 
		<< endl << ends;
	    Tcl_AppendResult(parent->interp, str.str().c_str(), NULL);
	  }
	  else
	    break;
	} 

	Tcl_AppendResult(parent->interp, "stroke\n", NULL);
      }
    } while (contours_.next());
  }
}

#ifdef _MACOSX
void Contour::macosx()
{
  if (contours_.head()) {
    // color, width, and dash
    macosxColor(parent->getXColor(colorName));
    macosxWidth(lineWidth);
    if (dash)
      macosxDash(parent->dlist,2);
    else
      macosxDash(NULL,0);

    Vector u1 = contours_.current()->vector;
    while (contours_.next()) {
      Vector u2 = contours_.current()->vector;
      if (u1[0] != DBL_MAX && u2[0] != DBL_MAX) {
	Vector v1 = parent->mapFromRef(u1,Coord::CANVAS);
	Vector v2 = parent->mapFromRef(u2,Coord::CANVAS);
	
	macosxDrawLine(v1,v2);
      }

      u1 = u2;
    }
  }
}
#endif

#ifdef _GWIN32
void Contour::win32()
{
  if (contours_.head()) {
    // color and width
    win32Color(parent->getXColor(colorName));
    win32Width(lineWidth);
    if (dash)
      win32Dash(parent->dlist,2);
    else
      win32Dash(NULL,0);

    Vector u1 = contours_.current()->vector;
    while (contours_.next()) {
      Vector u2 = contours_.current()->vector;
      if (u1[0] != DBL_MAX && u2[0] != DBL_MAX) {
	Vector v1 = parent->mapFromRef(u1,Coord::CANVAS);
	Vector v2 = parent->mapFromRef(u2,Coord::CANVAS);
	
	win32DrawLine(v1,v2);
      }

      u1 = u2;
    }
  }
}
#endif

void Contour::updateCoords(const Matrix& mx)
{
  if (contours_.head())
    do {
      Vector& v = contours_.current()->vector;
      if (v[0] != DBL_MAX)
	v *= mx;
    } while (contours_.next());
}

void Contour::setLineWidth(int w)
{
  lineWidth = w;
}

void Contour::setDash(int d)
{
  dash = d;
}

void Contour::setColor(const char* clr)
{
  if (colorName)
    delete [] colorName;

  colorName = dupstr(clr);
  color = parent->getColor(colorName);
}

