#usage "<qt><b>Copy Wire (Polygon Wire) to any layer</b><p>"
       "This ULP copies copper wire and/or polygon from layer (1 or 16) of selected signals into "
       "the solder stop layers or any layer in order to keep it free from solder stop layer.<p>"
       "Use:<br><nobr>"
       "run copy-wire-to-solder-mask.ulp [signalname] [signalname] <br>"
       "run copy-wire-to-solder-mask.ulp $nameoff$<br>"
       "run copy-wire-to-solder-mask.ulp -p [signalname] [signalname]<br>"
       "run copy-wire-to-solder-mask.ulp +p [signalname] [signalname]<br>"
       "run copy-wire-to-solder-mask.ulp -p -f [signalname] [signalname]<br>"
       "run copy-wire-to-solder-mask.ulp +p +f [signalname] [signalname]<br>"
       "$nameoff$ switches off the checking of net names<p>"
       "Options are case sensitive.<br>"
       "<b>$nameoff$</b> copy all signals.<br>"
       "<b>-p</b> copies also polygons.<br>"
       "<b>+p</b> copies only polygons.<br>"
       "<b>-f</b> copies only polygon contour as polygon.<br>"
       "<b>-f</b> copies polygon contour and filling as wire.<br>"
       "</nobr>"
       "<author>Author: support@cadsoft.de</author></qt>"

//     THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED.

string Version = "ULP-Version: 1.5"; //  2008-04-23 check is a polygon placed
                                     //  changed menu to copy to any layer
                                     //  2009-01-28 check polygon filling on orphan alf@cadsoft.de
                                     //  2009-04-23 check menu parameter
									 //  2009-06-30 correct polygon export


int    NameOff     = 0;    // 0 = copy by signal name
                           // 1 = copy without signal name (all)
int    PolygonOn   = 0;    // copy also polygon
int    onlyPolygon = 0;
int    fillPolygon = 0;    // copy only polygon contour or copy polygon filling as wire 2006.01.20 alf
int    Player[];
string poly[];
int    cntp        = 0;
string isRatsnest;
string isLayer     = "Top/Bottom";  // default layer
int    isLayerNb   = 0;
string toLayer     = "t/bStop";     // default do Stop-Layer
int    Lused[];                     // 2009-04-23

string signals[]   = { "" };
string chsignals[] = { "" };
int    chngsig     = 0;
int    lastSigCh   = -1;
int    decs;

int    index[];
int    x1[], y1[], x2[], y2[], layer[];
int    Wwidth[];
int    n = 1;

string cmd;
string c;

int    nbIslayer;
int    nbTolayer;

int    test = 0;  // 2009-06-30 for test menu


// *************************************
string check(void) { // 2009-04-23 alf@cadsoft.de
  int isLfound = 0;
  int toLfound = 0;
  nbIslayer = strtol(isLayer);
  nbTolayer = strtol(toLayer);

  if (isLayer == "Top/Bottom") isLfound = -1;
  else {
    board(B) B.layers(L) {
      if (nbIslayer == L.number || isLayer == L.name) {
        isLfound = L.number;
        nbIslayer  = L.number;
        break;
      }
    }
  }
  if (toLayer == "t/bStop") toLfound = -1;
  else {
    board(B) B.layers(L) {
      if (nbTolayer == L.number || toLayer == L.name) {
        toLfound = L.number;
        nbTolayer = L.number;
        break;
      }
    }
  }
  if (isLfound == -1);
  else if (!isLfound) return "!Select a available layer number or name for <i>Copy layer</i>.";
  else if (!Lused[isLfound]) return "!Not used layer <i>Copy layer</i> " + isLayer + ".";

  if (toLfound == -1);
  else if (!toLfound) return "!Select a available layer number or name for <i>to layer</i>.";
  else if (!Lused[toLfound]) return "!Not used layer <i>to layer</i> " + toLayer + ".";

  if (!NameOff && lastSigCh < 0 ) {
    return "!No signal selected";
  }
  return "";
}


int found(string fnam) {
  int fnd = 0;
  do {
    if (chsignals[fnd] == fnam) {
      return 1;
      break;
    }
    ++fnd;
  } while (chsignals[fnd]);
  return 0;
}


void changeLayer(int l) {
  if (toLayer == "t/bStop") {
    if (l == 1) sprintf(c, "CHANGE LAYER 29;\n");
    if (l == 16) sprintf(c, "CHANGE LAYER 30;\n");
    cmd+= c;
  }
  if (isLayer == "Top/Bottom") { // 2009-06-30
    if (l == 1) {
      sprintf(c, "CHANGE LAYER 29;\n");
      cmd+= c;
    }
    if (l == 16) {
      sprintf(c, "CHANGE LAYER 30;\n");
      cmd+= c;
    }
  }
  else if (l == isLayerNb) {
    sprintf(c, "CHANGE LAYER %s;\n", toLayer); // 2009-04-23
    cmd+= c;
  }
  return;
}


int delfromList(int selct) {
  if (lastSigCh >= 0) {
    lastSigCh--;
    for (int r = selct; r <= lastSigCh; r++) {
      chsignals[r] = chsignals[r + 1];
    }
    chsignals[lastSigCh + 1] = "";
  }
  return selct;
}


void  AddList(string SigName) {
  int nofound = 1;
  for (int r = 0; r <= lastSigCh; r++) {
    if (chsignals[r] == SigName) {
      nofound = 0;
      break;
    }
  }
  if (nofound) {
    lastSigCh++;
    if (lastSigCh > 0) {
      for (int x = lastSigCh; x > 0; x--) {
        chsignals[x] = chsignals[x - 1];
      }
    }
    chsignals[0] = SigName;
  }
  return;
}


void AddArgument(int n) {
  do {
    AddList(strupr(argv[n]));
    n++;
  } while(argv[n]);
  return;
}


void menue() {
  if (argc > 1) {
    if (argv[1] == "-p" || argv[1] == "+p" || argv[1] == "$nameoff$") {
      if (argv[1] == "-p") PolygonOn = 1;
      if (argv[1] == "+p") onlyPolygon = 1;
      if (argv[2] == "-f") fillPolygon = 0;   // 2006.01.20 alf
      if (argv[2] == "+f") fillPolygon = 1;
      if (argv[1] == "$nameoff$") { NameOff = 1; AddArgument(2); }
      else if (argv[2] == "$nameoff$") { NameOff = 1; AddArgument(3); }
      else  AddArgument(2);
      if (argv[2] == "$nameoff$") { NameOff = 1; AddArgument(3); }
      else if (argv[3] == "$nameoff$") { NameOff = 1; AddArgument(4); }
      else  AddArgument(3);
    }
    else AddArgument(1);
  }
  else {
    string slist[];
    int Result = dlgDialog("Copy wire to layer") {
      dlgLabel(Version);
      dlgHBoxLayout dlgSpacing(250);
      dlgCheckBox("Copy &all (without signal name)", NameOff);
      dlgSpacing(10);
      dlgStretch(0);
      dlgLabel("Add &signal to list");
      dlgComboBox(signals, chngsig) { AddList(signals[chngsig]); dlgRedisplay();}
      dlgSpacing(30);
      dlgLabel("&Delete signal from list");
      dlgComboBox(chsignals, decs) decs = delfromList(decs);
      dlgGroup("Polygon") {
        dlgCheckBox("Copy &polygon with signal name", PolygonOn);
        dlgCheckBox("Copy &only polygons", onlyPolygon);
        dlgHBoxLayout {
          dlgRadioButton("Copy only &contour", fillPolygon);
          dlgRadioButton("Copy with &filling", fillPolygon);
        }
      }
      dlgHBoxLayout {
        dlgLabel("Copy &layer ");
        dlgStringEdit(isLayer);
        dlgLabel(" &to layer ");
        dlgStringEdit(toLayer);
        dlgStretch(1);
      }
      dlgHBoxLayout {
        dlgPushButton("+OK") {
          string error = check();          // 2009-04-23 alf@cadsoft.de
          if(error) dlgMessageBox(error);
          else dlgAccept();
        }
        dlgPushButton("-Cancel") dlgReject();
        dlgStretch(1);
        dlgPushButton("&Help") dlgMessageBox(usage, "OK");
      }
      dlgStretch(0);
    };
    if (Result == 0) exit (0);
  }
  isLayerNb = nbIslayer;   // 2009-04-23
  return;
}


// main
if (board) board(B) {
  B.layers(L) Lused[L.number] = L.used;
  isRatsnest = "! Start RATSNEST first!";
  int cntPoly = 0;
  B.signals(S) {
    S.polygons(P) {
      cntPoly++;
      P.fillings(F) {  // check if run RATSNEST
        isRatsnest = "";
        break;
      }
      if (isRatsnest) { // check a orphan 2009-01-28 alf@cadsoft.de
        P.wires(W) {
          sprintf(isRatsnest, "Start RATSNEST and check polygon on (%.4f %.4f) mm!", u2mm(W.x1), u2mm(W.y1) );
          dlgMessageBox(isRatsnest, "OK");
          sprintf(isRatsnest, "GRID MM;\nWIN (%.4f %.4f);\nGRID LAST;\n", u2mm(W.x1), u2mm(W.y1) );
          exit(isRatsnest);
        }
      }
    }
  }
  if (cntPoly) {
    if (isRatsnest) {
      dlgMessageBox(isRatsnest, "OK");
      exit(0);
    }
  }
  int s = 0;
  B.signals(S) {
    signals[s] = S.name;
    s++;
  }
  menue();

  sprintf(c, "GRID MM;\nSET WIRE_BEND 2;\nSET UNDO OFF;\n");
  cmd+= c;
  B.signals(S) {
    if (found(S.name) || NameOff || onlyPolygon) {
      if (!onlyPolygon) {
        S.wires(W) {
          if ((isLayer == "Top/Bottom" && (W.layer == 1 || W.layer == 16)) || isLayerNb == W.layer) { // 2009-04-23 alf
            x1[n] = W.x1;
            y1[n] = W.y1;
            x2[n] = W.x2;
            y2[n] = W.y2;
            Wwidth[n] = W.width;
            layer[n] = W.layer;
            ++n;
          }
        }
      }
      if ( (PolygonOn && NameOff) || (onlyPolygon && !NameOff && found(S.name)) || (PolygonOn &&  !NameOff && found(S.name)) ) {
        S.polygons(POL) {
          if (isLayer && (POL.layer == 1 || POL.layer == 16) || isLayerNb == POL.layer) { // 2009-06-30 alf
            string p;
            int startx, starty;
			int first = 1;
            Player[cntp] = POL.layer;
            POL.contours(W) {
              if (first) {
                first = 0;
                startx = W.x1;
                starty = W.y1;
                sprintf(poly[cntp], "WIRE %.4f (%.4f %.4f) (%.4f %.4f)",  // 2009-06-30
                                             u2mm(W.width),
                                             u2mm(W.x1), u2mm(W.y1),
                                             u2mm(W.x2), u2mm(W.y2)
                       );
              }
              else {
                sprintf(p, " (%.4f %.4f)", u2mm(W.x2), u2mm(W.y2) );
                poly[cntp] += p;
                if (startx == W.x2 && starty == W.y2) {
                 sprintf(p, " (%.4f %.4f);\n", u2mm(startx), u2mm(starty) );
                 poly[cntp] += p;
                 cntp++;
                 break;
                }
              }
            }
            if (fillPolygon) {   // Polygon filling with wire 2009-06-30
              POL.fillings(W) {
                x1[n] = W.x1;
                y1[n] = W.y1;
                x2[n] = W.x2;
                y2[n] = W.y2;
                Wwidth[n] = W.width;
                layer[n] = W.layer;
                ++n;
              }
            }
          }
        }
      }
    }
  }
  sort(n, index, layer);
  int dl = 0;
  for (int i = 1; i < n; i++) {
    if(dl != layer[index[i]]) {
      dl = layer[index[i]];
      changeLayer(dl);
    }
    sprintf(c, "WIRE %.4f (%.4f %.4f) (%.4f %.4f);\n", u2mm(Wwidth[index[i]]),
                u2mm(x1[index[i]]), u2mm(y1[index[i]]), u2mm(x2[index[i]]), u2mm(y2[index[i]])  );
    cmd+= c;
  }
  sort(cntp, index, Player);
  for ( i = 0; i < cntp; ++i) {
    if(dl != Player[index[i]]) {
      dl = Player[index[i]];
      changeLayer(dl);
    }
    sprintf(c, "WIRE %.4f (%.4f %.4f) (%.4f %.4f);\n", u2mm(Wwidth[index[i]]),
                u2mm(x1[index[i]]), u2mm(y1[index[i]]), u2mm(x2[index[i]]), u2mm(y2[index[i]])  );
    cmd+= poly[index[i]];
  }
  sprintf(c, "SET UNDO ON;\nGRID LAST;\n");
  cmd+= c;
  if (test) { // 2009-06-30
    dlgDialog("test") {
      dlgTextEdit(cmd);
	  dlgHBoxLayout {
	    dlgPushButton("OK") dlgAccept();
	    dlgPushButton("Cancel") { dlgReject(); exit(-9); }
	  }
    };
  }
  exit (cmd);
}

else dlgMessageBox("! Start this ULP in a Board", "OK");