#usage "Mirror board (with all Layers)<p>"
       "<author>Author: support@cadsoft.de</author>"

#require 5.0600

// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
// Version 1.01 -- 2006-09-15 alf@cadsoft.de
//                 2008-04-10 changed GROUP ... (>x y); alf@cadsoft.de
//
// Version 1.02 -- 2009-12-01 unlock and lock emlements, swap layer colors and fill  alf@cadsoft.de
//                            check via stack for blind or micro vias

string Version = "1.02";
int test = 0;

string cmd;
int    lVisible[];
int    useLayer[];
int    lcolor[];
int    lfill[];
string lNames[] = { " " };

string lockName[];
int    cntlock = 0;

int    maxX = INT_MIN;
int    minX = INT_MAX;
int    maxY = INT_MIN;
int    minY = INT_MAX;
int    bminx, bmaxx, bminy, bmaxy;

int uval = 1;

if (board) board(B) uval = B.grid.unit;
string unit[] = { "Micron", "mm", "Mil", "Inch" };
int    unitPrec[] = { 0, 1, 1, 3 }, RoundFactor = pow(10, unitPrec[uval]);

real u2u(int v) {
  switch (uval) {
    case GRID_UNIT_MIC  : return u2mic(v);
                          break;

    case GRID_UNIT_MM	  : return u2mm(v);
                          break;

    case GRID_UNIT_MIL  : return u2mil(v);
                          break;

    case GRID_UNIT_INCH : return u2inch(v);
                          break;
  }
}


void checkmaxmin(int x1, int x2, int y1, int y2) {
  if (x1 > maxX) maxX = x1;
  if (x2 > maxX) maxX = x2;
  if (y1 > maxY) maxY = y1;
  if (y2 > maxY) maxY = y2;
  if (x1 < minX) minX = x1;
  if (x2 < minX) minX = x2;
  if (y1 < minY) minY = y1;
  if (y2 < minY) minY = y2;
  return;
}

void checkarc( int x1, int x2, int y1, int y2, int xc, int yc, real angle1, real angle2, real radius) {
  checkmaxmin( x1, x2, y1, y2 );
  if ( angle2 > angle1 + 270.0) {
    if     ( angle1 < 90  ) checkmaxmin( x1         , xc - radius, yc + radius, yc - radius );
    else if( angle1 < 180 ) checkmaxmin( xc - radius, xc + radius, y1         , yc - radius );
    else if( angle1 < 270 ) checkmaxmin( x1         , xc + radius, yc - radius, yc + radius );
    else if( angle1 < 360 ) checkmaxmin( xc + radius, xc - radius, y1         , yc + radius );
  }
  else if( angle2 > angle1 + 180.0) {
    if     ( angle1 < 90  ) checkmaxmin( x1         , xc - radius, yc + radius, y2          );
    else if( angle1 < 180 ) checkmaxmin( x1         , xc - radius, yc - radius, y2          );
    else if( angle1 < 270 ) checkmaxmin( x1         , xc + radius, yc - radius, y2          );
    else if( angle1 < 360 ) checkmaxmin( x1         , xc + radius, yc + radius, y2          );
  }
  else if( angle2 > angle1 + 90.0 ) {
    if     ( angle1 < 90  ) checkmaxmin( x1         , x2         , yc + radius, y2          );
    else if( angle1 < 180 ) checkmaxmin( x1         , xc - radius, y1         , y2          );
    else if( angle1 < 270 ) checkmaxmin( x1         , x2         , yc - radius, y2          );
    else if( angle1 < 360 ) checkmaxmin( x1         , xc + radius, y1         , y2          );
  }
  return;
}


real WireLength(int x1, int x2, int y1, int y2) {
  return sqrt( pow(u2u(x2) - u2u(x1), 2) + pow( u2u(y2) - u2u(y1), 2));
}


void lock_elements(void) {
  for (int lc = 0; lc < cntlock; lc++) {
    cmd += "LOCK " + lockName[lc] + ";\n";
  }
  return;
}

void setcolor(void) {
  string s;
  sprintf(s, "SET COLOR_LAYER  1 %d;\n", lcolor[16]);  // 2009-12-01 shwap layer color and fill
  cmd += s;
  sprintf(s, "SET FILL_LAYER   1 %d;\n", lfill[16]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 16 %d;\n", lcolor[1]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  16 %d;\n", lfill[1]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 21 %d;\n", lcolor[22]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  21 %d;\n", lfill[22]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 22 %d;\n", lcolor[21]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  22 %d;\n", lfill[21]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 23 %d;\n", lcolor[24]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  23 %d;\n", lfill[24]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 24 %d;\n", lcolor[23]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  24 %d;\n", lfill[23]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 25 %d;\n", lcolor[26]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  25 %d;\n", lfill[26]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 26 %d;\n", lcolor[25]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  26 %d;\n", lfill[25]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 27 %d;\n", lcolor[28]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  27 %d;\n", lfill[28]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 28 %d;\n", lcolor[27]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  28 %d;\n", lfill[27]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 29 %d;\n", lcolor[30]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  29 %d;\n", lfill[30]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 30 %d;\n", lcolor[29]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  30 %d;\n", lfill[29]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 31 %d;\n", lcolor[32]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  31 %d;\n", lfill[32]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 32 %d;\n", lcolor[31]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  32 %d;\n", lfill[31]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 51 %d;\n", lcolor[52]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  51 %d;\n", lfill[52]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 52 %d;\n", lcolor[51]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  52 %d;\n", lfill[51]);
  cmd += s;
  return;
}

int checkVia(UL_VIA V) {
  if (V.start != 1 || V.end != 16) return 1;
  return 0;
}

// main
if (board) {
  board(B) {
    int verror = 0;
    B.signals(S) S.vias(V) verror += checkVia(V);
    if (verror) {
      dlgMessageBox("!Do not use this ULP if used blind or micro via(s)!", "OK");
      exit(-1);
    }
    bminx = B.area.x1;
    bmaxx = B.area.x2;
    bminy = B.area.y1;
    bmaxy = B.area.y2;
    B.layers(L) {
      lNames[L.number] = L.name;
      lVisible[L.number] = L.visible;
      useLayer[L.number] = L.used;
      lcolor[L.number] = L.color;
      lfill[L.number] = L.fill;
    }
    B.wires(W) {
      if (W.layer == 20) {
        if (W.arc) {
          checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius);
        }
        else {
          checkmaxmin( W.x1, W.x2, W.y1, W.y2 );
        }
      }
    }
    B.circles(C) {
      if (C.layer == 20) {
        checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius );
      }
    }
    B.elements(E) {
      E.package.wires(W) {
        if (W.layer == 20) {
          // *** Dimension in Packages ***
          if (W.arc) {
            checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius);
          }
          else {
            checkmaxmin( W.x1, W.x2, W.y1, W.y2 );
          }
        }
      }
      E.package.circles(C) {
        if (C.layer == 20) {
          checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius );
        }
      }
    }
    string s;
    sprintf(s, "DISPLAY ALL;\n");
    cmd += s;
    sprintf(s, "GROUP ALL;\n");
    cmd += s;
    cmd += "LOCK (>S 0 0);\n";  // unlock all  2009-11-01

    sprintf(s, "GRID FINEST;\nMIRROR (>%.4f %.4f);\nGRID LAST;\n",
                  (u2u(maxX) + u2u(minX)) / 2, u2u(minY) );
    cmd += s;
    cmd += "DISPLAY NONE ";
    for(int l = 1; l < 256; l++) {
      if (lNames[l]) {  // Layer defined
        if (lVisible[l]) {
          if (l == 1 || l == 16 || l == 21 || l == 22 || l == 23 || l == 24 || l == 25 || l == 26 || l == 27 || l == 28 || l == 29 || l == 30 || l == 31 || l == 32 || l == 51 || l == 52 ) {
            if      (l ==  1) sprintf(s, " %d", 16);  // 2009-12-01 shwap visible layers
            else if (l == 16) sprintf(s, " %d",  1);
            else if (l == 21) sprintf(s, " %d", 22);
            else if (l == 22) sprintf(s, " %d", 21);
            else if (l == 23) sprintf(s, " %d", 24);
            else if (l == 24) sprintf(s, " %d", 23);
            else if (l == 25) sprintf(s, " %d", 26);
            else if (l == 26) sprintf(s, " %d", 25);
            else if (l == 27) sprintf(s, " %d", 28);
            else if (l == 28) sprintf(s, " %d", 27);
            else if (l == 29) sprintf(s, " %d", 30);
            else if (l == 30) sprintf(s, " %d", 29);
            else if (l == 31) sprintf(s, " %d", 32);
            else if (l == 32) sprintf(s, " %d", 31);
            else if (l == 51) sprintf(s, " %d", 52);
            else if (l == 52) sprintf(s, " %d", 51);
          }
          else sprintf(s, " %d", l);
          cmd += s;
        }
      }
    }
    cmd += ";\n";
    B.elements(E) if (E.locked) cmd += "LOCK " + E.name + ";\n";   // 2009-12-01
    setcolor();
  }
}

if (test) dlgDialog("Test") {
  dlgTextEdit(cmd);
  dlgHBoxLayout  {
    dlgPushButton("ok") dlgAccept();
    dlgPushButton("esc") { dlgReject(); exit(-1); }
  }
};
exit(cmd);