#usage "<b>PIC Converter</b><p>\n"
       "Converts a board or schematic into a PIC file.<p>\n"
       "The resulting file is a PIC drawing which can be used with GROFF or LaTeX.<p>\n"
       "<author>Author: jeff@uClinux.org adapted from dxf.ulp by support@cadsoft.de</author>"

//
// The following switches allow us to customize the generated PIC file:
//

enum { NO, YES };

int PadColor = 0, ViaColor = 0;

//
// Some tools we need later:
//

real PicUnit(int n)
{
  return u2inch(n);
}

int LayerActive[] = {1};

real max_x1 = 0.0;
real max_y1 = 0.0;
real max_x2 = 0.0;
real max_y2 = 0.0;

void PicStart()
{
  printf(".PS\n");
}

void PicEnd()
{
  printf(".PE\n");
}

void PicLine(int layer, int width, int x1, int y1, int x2, int y2)
{
  if (width <= 0) width = -1;

  printf("linethick = %f; line at ( %f, %f) to ( %f, %f);\n",
    PicUnit(width) * 72.0,
    PicUnit(x1),
    PicUnit(y1),
    PicUnit(x2),
    PicUnit(y2));
}

void PicBox(int layer, int x1, int y1, int x2, int y2)
{
  printf("box at ( %f, %f) fill 1.0 height %f width %f;\n",
    PicUnit(x1) + (PicUnit(x2) - PicUnit(x1))/2.0,
    PicUnit(y1) + (PicUnit(y2) - PicUnit(y1))/2.0,
    abs(PicUnit(x2) - PicUnit(x1)),
    abs(PicUnit(y2) - PicUnit(y1)));
}

void PicCircle(int layer, int width, int x, int y, int r)
{
  if (width <= 0) width = -1;

  printf("linethick = %f; circle at ( %f, %f) rad %f;\n",
    PicUnit(width) * 72.0,
    PicUnit(x),
    PicUnit(y),
    PicUnit(r));
}

void PicArc(int layer, int width, int xc, int yc, int x1, int y1, int x2, int y2)
{
  printf("linethick = %f; arc at (%f, %f) from (%f, %f) to (%f, %f)\n",
    PicUnit(width) * 72.0,
    PicUnit(xc),
    PicUnit(yc),
    PicUnit(x1),
    PicUnit(y1),
    PicUnit(x2),
    PicUnit(y2));
}

//
// Low level EAGLE to PIC conversion functions:
//

void Layer(UL_LAYER L)
{
  if (L.visible)
     printf("# Layer %d colour %d\n",L.number, L.color);
  LayerActive[L.number] = L.visible;
  switch (L.number) {
    case LAYER_PADS: PadColor = L.color; break;
    case LAYER_VIAS: ViaColor = L.color; break;
    }
}

void Area(UL_AREA A)
{
  max_x1 = PicUnit(A.x1);
  max_y1 = PicUnit(A.y1);
  max_x2 = PicUnit(A.x2);
  max_y2 = PicUnit(A.y2);

  printf("# This pic is %f by %f inches\n",max_x2 - max_x1, max_y2 - max_y1);
}

void Line(UL_WIRE W)
{
  PicLine(W.layer, W.width, W.x1, W.y1, W.x2, W.y2);
}

void Wire(UL_WIRE W)
{
  if (LayerActive[W.layer]) {
     if (W.style != WIRE_STYLE_CONTINUOUS)
        W.pieces(P) Line(P);
     else
        Line(W);
     }
}

void Circle(UL_CIRCLE C)
{
  if (LayerActive[C.layer]) {
     PicCircle(C.layer, C.width, C.x, C.y, C.radius);
     }
}

void Arc(UL_ARC A)
{
  if (LayerActive[A.layer]) {
        PicArc(A.layer, A.width,
               A.xc, A.yc,
               A.x1, A.y1,
               A.x2, A.y2);
     }
}

void Rectangle(UL_RECTANGLE R)
{
  PicBox(R.layer, R.x1, R.y1, R.x2, R.y2);
}

void Hole(UL_HOLE H)
{
  PicCircle(LAYER_DIMENSION, H.drill / 2, H.x, H.y, H.drill / 2);
}

void Via(UL_VIA V)
{
  string Shape[] = { "SQUAREV", "ROUNDV", "OCTAGONV" };
  int Count = 0;
  int Extended = 0;

  for (int l = LAYER_TOP; l; ) {
      if (LayerActive[l] || l == Extended) {
         Count++;
//         PicInsert(ViaColor ? LAYER_VIAS : l, Shape[V.shape[l]], PicUnit(V.x), PicUnit(V.y), PicUnit(V.diameter[l]), PicUnit(V.diameter[l]));
         }
      if (l < LAYER_BOTTOM) {
         if (Extended)
            l = Extended = LAYER_BOTTOM;
         else
            ++l;
         }
      else
         switch (l) {
           case LAYER_BOTTOM: if (!Extended && !Count && ViaColor && LayerActive[LAYER_VIAS])
                                 l = Extended = LAYER_TOP;
                              else
                                 l = LAYER_TSTOP;
                              break;
           case LAYER_TSTOP:  l = LAYER_BSTOP; break;
           default:           l = 0;
           }
      }
  if (Count)
     PicCircle(LAYER_DRILLS, (V.diameter[LAYER_BOTTOM] - V.drill)/2, V.x, V.y, V.diameter[LAYER_BOTTOM] - (V.diameter[LAYER_BOTTOM] - V.drill) / 2);
}

void Pad(UL_PAD P)
{
  string Shape[] = { "SQUAREP", "ROUNDP", "OCTAGONP", "XLONGOCT", "YLONGOCT" };
  int Count = 0;
  int Extended = 0;

  for (int l = LAYER_TOP; l; ) {
      if (LayerActive[l] || l == Extended) {
         Count++;
//         PicInsert(PadColor ? LAYER_PADS : l, Shape[P.shape[l]], PicUnit(P.x), PicUnit(P.y), PicUnit(P.diameter[l]), PicUnit(P.diameter[l]));
         }
      if (l < LAYER_BOTTOM) {
         if (Extended)
            l = Extended = LAYER_BOTTOM;
         else
            ++l;
         }
      else
         switch (l) {
           case LAYER_BOTTOM: if (!Extended && !Count && PadColor && LayerActive[LAYER_PADS])
                                 l = Extended = LAYER_TOP;
                              else
                                 l = LAYER_TSTOP;
                              break;
           case LAYER_TSTOP:  l = LAYER_BSTOP; break;
           default:           l = 0;
           }
      }
  if (Count)
     PicCircle(LAYER_DRILLS, (P.diameter[LAYER_BOTTOM] - P.drill)/2, P.x, P.y, P.diameter[LAYER_BOTTOM] - (P.diameter[LAYER_BOTTOM] - P.drill) / 2);
}

void Smd(UL_SMD S)
{
}

void Junction(UL_JUNCTION J)
{
   PicCircle(LAYER_NETS, J.diameter / 2, J.x, J.y, J.diameter / 4);
}

void Polygon(UL_POLYGON P)
{
  P.contours(W) Wire(W);
  if (P.width > 0)
     P.fillings(W) Wire(W);
  else if (dlgMessageBox("Can't fill polygon with Width = 0", "+Ok", "-Cancel") != 0)
     exit(1);
}

void Text(UL_TEXT T)
{
  if (LayerActive[T.layer]) {
    T.wires(W) Line(W);
  }
}

//
// Level 3: High level EAGLE decomposing functions:
//

void Package(UL_PACKAGE P)
{
  P.polygons(P) Polygon(P);
  P.wires(W) Wire(W);
  P.texts(T) Text(T);
  P.arcs(A) Arc(A);
  P.circles(C) Circle(C);
  P.rectangles(R) Rectangle(R);
  P.holes(H) Hole(H);
  P.contacts(C) {
    if (C.pad) Pad(C.pad);
    else       Smd(C.smd);
    }
}

void Element(UL_ELEMENT E)
{
  int layer;

  switch (E.mirror) {
    case 0: layer = LAYER_TORIGINS; break; // not mirrored
    case 1: layer = LAYER_BORIGINS; break; // mirrored
    }
//  PicPoint(layer, PicUnit(E.x), PicUnit(E.y));
  Package(E.package);
  E.texts(T) Text(T);
}

void Signal(UL_SIGNAL S)
{
  S.polygons(P) Polygon(P);
  S.wires(W) Wire(W);
  S.vias(V) Via(V);
}

void Board(UL_BOARD B)
{
  B.polygons(P) Polygon(P);
  B.wires(W) Wire(W);
  B.texts(T) Text(T);
  B.arcs(A) Arc(A);
  B.circles(C) Circle(C);
  B.rectangles(R) Rectangle(R);
  B.holes(H) Hole(H);
  B.elements(E) Element(E);
  B.signals(S) Signal(S);
}

void Pin(UL_PIN P)
{
  P.wires(W) Wire(W);
  P.circles(C) Circle(C);
  P.texts(T) Text(T);
}

void Symbol(UL_SYMBOL S)
{
  S.polygons(P) Polygon(P);
  S.wires(W) Wire(W);
  S.texts(T) Text(T);
  S.pins(P) Pin(P);
  S.arcs(A) Arc(A);
  S.circles(C) Circle(C);
  S.rectangles(R) Rectangle(R);
}

void Instance(UL_INSTANCE I)
{
  Symbol(I.gate.symbol);
  I.texts(T) Text(T);
}

void Part(UL_PART P)
{
  P.instances(I) Instance(I);
}

void Segment(UL_SEGMENT S)
{
  S.wires(W) Wire(W);
  S.junctions(J) Junction(J);
  S.texts(T) Text(T);
}

void Bus(UL_BUS B)
{
  B.segments(S) Segment(S);
}

void Net(UL_NET N)
{
  N.segments(S) Segment(S);
}

void Sheet(UL_SHEET S)
{
  S.polygons(P) Polygon(P);
  S.wires(W) Wire(W);
  S.texts(T) Text(T);
  S.arcs(A) Arc(A);
  S.circles(C) Circle(C);
  S.rectangles(R) Rectangle(R);
  S.parts(P) Part(P);
  S.busses(B) Bus(B);
  S.nets(N) Net(N);
}

//
// Main program:
//

string OutputFileName;

if (board)
   board(B) OutputFileName = B.name;
else if (schematic)
   schematic(SCH) OutputFileName = SCH.name;
else {
   dlgMessageBox(usage + "<hr><b>ERROR: No board or schematic!</b><p>\nThis program can only work in the board or schematic editor.");
   exit(1);
   }

OutputFileName = filesetext(OutputFileName, ".pic");

dlgDialog("PIC Converter") {
  dlgHBoxLayout {
    dlgLabel("&Output file");
    dlgStringEdit(OutputFileName);
    dlgPushButton("&Browse") {
      string FileName = dlgFileSave("Save PIC file", OutputFileName, "PIC files (*.pic)");
      if (FileName)
         OutputFileName = FileName;
      }
    }
  dlgStretch(1);
  dlgHBoxLayout {
    dlgStretch(1);
    dlgPushButton("+Ok") {
      string a[];
      if (!fileglob(a, OutputFileName) || dlgMessageBox("File '" + OutputFileName + "' exists\n\nOverwrite?", "+&Yes", "-&No") == 0)
      dlgAccept();
      }
    dlgPushButton("-Cancel") { dlgReject(); exit(1); }
    dlgPushButton("About") dlgMessageBox(usage);
    }
  };

output(OutputFileName) {
  PicStart();
    if (board) board(B) Area(B.area);
    else sheet(S) Area(S.area);
    if (board) board(B) B.layers(L) Layer(L);
    else schematic(SCH) SCH.layers(L) Layer(L);
    if (board) board(B) Board(B);
    else sheet(S) Sheet(S);
  PicEnd();
  }
