/*****
 * drawfill.cc
 * Andy Hammerlindl 2002/06/06
 *
 * Stores a cyclic path that will outline a filled shape in a picture.
 *****/

#include "drawfill.h"

namespace camp {

using settings::ps2tex;
using settings::tex2ps;

void drawAxialShade::palette(psfile *out)
{
  pentype.convert();
  penb.convert();

  colorspace=(ColorSpace) max(pentype.colorspace(),penb.colorspace());

  switch(colorspace) {
    case RGB:
    {
      if (pentype.grayscale()) pentype.greytorgb();
      else if (penb.grayscale()) penb.greytorgb();
      break;
    }

    case CMYK:
    {
      if (pentype.grayscale()) pentype.greytocmyk();
      else if (penb.grayscale()) penb.greytocmyk();

      if (pentype.rgb()) pentype.rgbtocmyk();
      else if (penb.rgb()) penb.rgbtocmyk();
      break;
    }
    default:
      break;
  }

  out->gsave();
}

bool drawFill::draw(psfile *out)
{
  if(pentype.invisible() || empty()) return true;

  palette(out);
  writepath(out);
  fill(out);
  return true;
}

drawElement *drawFill::transformed(const transform& t)
{
  return new drawFill(transpath(t),stroke,transpen(t),KEY);
}

drawElement *drawLatticeShade::transformed(const transform& t)
{
  return new drawLatticeShade(transpath(t),stroke,pentype,pens,t*T,KEY);
}

drawElement *drawAxialShade::transformed(const transform& t)
{
  pair A=t*a, B=t*b;
  return new drawAxialShade(transpath(t),stroke,pentype,A,extenda,penb,B,
                            extendb,KEY);
}

drawElement *drawRadialShade::transformed(const transform& t)
{
  pair A=t*a, B=t*b;
  double RA=length(t*(a+ra)-A);
  double RB=length(t*(b+rb)-B);
  return new drawRadialShade(transpath(t),stroke,pentype,A,RA,extenda,penb,B,
                             RB,extendb,KEY);
}

drawElement *drawGouraudShade::transformed(const transform& t)
{
  size_t size=vertices.size();
  vm::array *Vertices=new vm::array(size);
  for(size_t i=0; i < size; i++)
    (*Vertices)[i]=t*vm::read<pair>(vertices,i);

  return new drawGouraudShade(transpath(t),stroke,pentype,pens,*Vertices,
                              edges,KEY);
}

drawElement *drawTensorShade::transformed(const transform& t)
{
  size_t size=boundaries.size();
  size_t zsize=z.size();
  vm::array *Boundaries=new vm::array(size);
  vm::array *Z=new vm::array(zsize);

  for(size_t i=0; i < size; i++)
    (*Boundaries)[i]=vm::read<path>(boundaries,i).transformed(t);

  for(size_t i=0; i < zsize; i++) {
    vm::array *zi=vm::read<vm::array *>(z,i);
    size_t zisize=checkArray(zi);
    vm::array *Zi=new vm::array(zisize);
    (*Z)[i]=Zi;
    for(size_t j=0; j < zisize; j++)
      (*Zi)[j]=t*vm::read<pair>(zi,j);
  }

  return new drawTensorShade(transpath(t),stroke,pentype,pens,*Boundaries,*Z,
                             KEY);
}

bool drawFunctionShade::write(texfile *out, const bbox& box)
{
  if(empty()) return true;

  ColorSpace colorspace=pentype.colorspace();
  size_t ncomponents=ColorComponents[colorspace];

  out->verbatim("\\pdfobj stream attr {/FunctionType 4");
  out->verbatim("/Domain [0 1 0 1]");
  out->verbatim("/Range [");
  for(size_t i=0; i < ncomponents; ++i)
    out->verbatim("0 1 ");
  out->verbatim("]}{{");
  out->verbatimline(shader);
  out->verbatimline("}}%");
  out->verbatimline("\\edef\\lastobj{\\the\\pdflastobj}\\pdfrefobj\\lastobj");

  out->verbatim("\\setbox\\ASYbox=\\hbox to ");
  double Hoffset=out->hoffset();
  double hoffset=(bpath.Max().getx()-Hoffset)*ps2tex;
  out->write(hoffset);
  out->verbatim("pt {");
  out->verbatim("\\vbox to ");
  out->write((box.top-box.bottom)*ps2tex);
  out->verbatimline("pt {\\vfil%");
  out->gsave();
  out->beginspecial();
  out->beginraw();
  writeshiftedpath(out);
  if(stroke) strokepath(out);
  out->endclip(pentype);
  out->verbatimline("/Sh sh");
  out->endraw();
  out->endspecial();
  out->grestore();
  out->verbatimline("}\\hfil}%");

  out->verbatimline("\\pdfxform resources {");
  out->verbatimline("/Shading << /Sh << /ShadingType 1");
  out->verbatim("/Matrix [");

  out->write(shift(pair(-Hoffset,-box.bottom))*matrix(bpath.Min(),bpath.Max()));
  out->verbatimline("]");
  out->verbatim("/Domain [0 1 0 1]");
  out->verbatim("/ColorSpace /Device");
  out->verbatimline(ColorDeviceSuffix[colorspace]);
  out->verbatimline("/Function \\lastobj\\space 0 R >> >>}\\ASYbox");

  out->verbatimline("\\pdfrefxform\\the\\pdflastxform");
  out->verbatim("\\kern");
  out->write(-hoffset);
  out->verbatimline("pt%");
  return true;
}

drawElement *drawFunctionShade::transformed(const transform& t)
{
  return new drawFunctionShade(transpath(t),stroke,pentype,shader,KEY);
}

} // namespace camp
