/**
   * Check that the user has properly selected a target node for this tool
   *
   * <p>
   *
   * @return The phase progress message or <CODE>null</CODE> to abort early.
   * @throws PipelineException If unable to validate the given user input.
   */
  public synchronized String collectPhaseInput() throws PipelineException {
    if ((pPrimary == null) || (pSelected.size() != 1))
      throw new PipelineException("Please selected one node only.");

    // folder = nPath.getParent();
    // assetName = nPath.getName();
    Path nPath = new Path(pPrimary);
    nPath = nPath.getParentPath().getParentPath();

    if (!nPath.toString().matches(assetPattern))
      throw new PipelineException(
          "This tool only works on assets." + nPath.toString() + " " + nPath.toOsString());

    // if(!pPrimary.matches(matPattern))
    // throw new PipelineException("This tool will only work on a lgt node!");

    File errFile;
    try {
      errFile = File.createTempFile("MaterialsCheckOut", ".err", PackageInfo.sTempPath.toFile());
      err = new PrintWriter(errFile);
      FileCleaner.add(errFile);
    } catch (IOException e) {
      e.printStackTrace();
    }

    NodeStatus status = pSelected.get(pPrimary);
    NodeID nodeID = status.getNodeID();
    pUser = nodeID.getAuthor();
    pView = nodeID.getView();

    OverallNodeState state = status.getHeavyDetails().getOverallNodeState();
    JToolDialog tool = new JToolDialog("MaterialsCheckOut", new JPanel(), "Continue");
    if (!state.equals(OverallNodeState.Identical)) {
      JConfirmDialog dialog =
          new JConfirmDialog(
              tool,
              "This node is different from the checked in node. Do you want to continue with this check out?");
      dialog.setVisible(true);
      if (!dialog.wasConfirmed()) {
        return null;
      } // end if
    } // end if

    return "...Sing Hallelujah!";
  }
  /**
   * Construct a {@link SubProcessHeavy SubProcessHeavy} instance which when executed will fulfill
   * the given action agenda.
   *
   * <p>
   *
   * @param agenda The agenda to be accomplished by the action.
   * @param outFile The file to which all STDOUT output is redirected.
   * @param errFile The file to which all STDERR output is redirected.
   * @return The SubProcess which will fulfill the agenda.
   * @throws PipelineException If unable to prepare a SubProcess due to illegal, missing or
   *     imcompatable information in the action agenda or a general failure of the prep method code.
   */
  public SubProcessHeavy prep(ActionAgenda agenda, File outFile, File errFile)
      throws PipelineException {
    /* model filenames */
    TreeMap<String, Path> modelPaths = new TreeMap<String, Path>();
    TreeMap<String, Path> animPaths = new TreeMap<String, Path>();

    TreeMap<String, String> nameSpaces = new TreeMap<String, String>();
    TreeMap<String, String> reverseNameSpaces = new TreeMap<String, String>();
    TreeMap<String, Boolean> usesNameSpace = new TreeMap<String, Boolean>();
    TreeMap<String, String> buildTypes = new TreeMap<String, String>();

    for (String sname : agenda.getSourceNames()) {
      if (hasSourceParams(sname)) {
        FileSeq fseq = agenda.getPrimarySource(sname);
        String suffix = fseq.getFilePattern().getSuffix();
        if (fseq.isSingle() && (suffix != null)) {
          if (suffix.equals("ma") || suffix.equals("mb")) {
            Path npath = new Path(sname);
            String type = getSourceStringParamValue(sname, aSceneType);
            String nspace = getSourceStringParamValue(sname, aPrefixName);
            if (nspace == null) {
              nspace = npath.getName();
            }
            if (type.equals(aModel))
              modelPaths.put(sname, new Path(npath.getParentPath(), fseq.getPath(0)));
            else {
              animPaths.put(sname, new Path(npath.getParentPath(), fseq.getPath(0)));
              nspace += "_a";
            }

            boolean useNSpace = false;
            {
              Boolean tf = (Boolean) getSourceParamValue(sname, aNameSpace);
              useNSpace = ((tf != null) && tf);
            }

            String buildType = getSourceStringParamValue(sname, aBuildType);
            if (buildType == null)
              throw new PipelineException(
                  "The value of the "
                      + aBuildType
                      + " source parameter for node "
                      + "("
                      + sname
                      + ") was not set!");

            buildTypes.put(sname, buildType);
            nameSpaces.put(sname, nspace);
            reverseNameSpaces.put(nspace, sname);
            usesNameSpace.put(sname, useNSpace);
          }
        }
      }
    }

    /* the target Maya scene */
    Path targetScene = getMayaSceneTargetPath(agenda);
    String sceneType = getMayaSceneType(agenda);

    /* create a temporary MEL script file */
    File script = createTemp(agenda, "mel");
    try {
      FileWriter out = new FileWriter(script);

      /* provide parameters as MEL variables */
      out.write(genFrameRangeVarsMEL());

      /* rename the current scene as the output scene */
      out.write(
          "// SCENE SETUP\n"
              + "file -rename \""
              + targetScene
              + "\";\n"
              + "file -type \""
              + sceneType
              + "\";\n\n");

      out.write(genUnitsMEL());

      writeInitialMEL(agenda, out);

      /* the model file reference imports */
      TreeMap<String, Path> all = new TreeMap<String, Path>(modelPaths);
      all.putAll(animPaths);
      for (String sname : all.keySet()) {
        Path mpath = all.get(sname);

        String buildType = buildTypes.get(sname);

        out.write(
            "// MODEL: "
                + sname
                + "\n"
                + "print \""
                + buildType
                + " Model: "
                + mpath
                + "\\n\";\n"
                + "file\n");

        String nspace = nameSpaces.get(sname);

        boolean useNSpace = usesNameSpace.get(sname);

        if (buildType.equals(aImport)) {
          out.write("  -import\n");

          if (useNSpace) out.write("  -namespace \"" + nspace + "\"\n");
        } else if (buildType.equals(aReference)) {
          out.write("  -reference\n");

          if (useNSpace) out.write("  -namespace \"" + nspace + "\"\n");
          else out.write("  -renamingPrefix \"" + nspace + "\"\n");
        } else {
          throw new PipelineException(
              "Unknown value for the "
                  + aBuildType
                  + " source parameter for node "
                  + "("
                  + sname
                  + ") encountered!");
        }

        {
          String fname = mpath.getName();
          if (fname.endsWith("ma")) out.write("  -type \"mayaAscii\"\n");
          else if (fname.endsWith("mb")) out.write("  -type \"mayaBinary\"\n");
          else
            throw new PipelineException(
                "Unknown Maya scene format for source file (" + mpath + ")!");
        }

        out.write("  -options \"v=0\"\n" + "  \"$WORKING" + mpath + "\";\n\n");
      }

      writeModelMEL(agenda, out);

      out.write(
          "global proc string removePrefix(string $name)\n"
              + "{\n"
              + "  string $toReturn;\n"
              + "  string $buffer[];\n"
              + "  tokenize($name, \"|\", $buffer);\n"
              + "  string $part;\n"
              + "  for ($part in $buffer) {\n"
              + "    string $buffer2[];\n"
              + "    tokenize($part, \":\", $buffer2);\n"
              + "    if ($toReturn == \"\")\n"
              + "      $toReturn += $buffer2[(size($buffer2) -1)];\n"
              + "    else\n"
              + "      $toReturn += \"|\" + $buffer2[(size($buffer2) -1)];\n"
              + "  }\n"
              + "  return $toReturn;    \n"
              + "}\n");

      out.write(
          "global proc string addPrefix(string $name, string $prefix)\n"
              + "{\n"
              + "  string $toReturn;\n"
              + "  string $buffer[];\n"
              + "  tokenize($name, \"|\", $buffer);\n"
              + "  string $part;\n"
              + "  for ($part in $buffer) {\n"
              + "    if ($toReturn == \"\")\n"
              + "      $toReturn += $prefix + $buffer[(size($buffer) -1)];\n"
              + "    else\n"
              + "      $toReturn += \"|\" + $prefix + $buffer[(size($buffer) -1)];\n"
              + "  }\n"
              + "  return $toReturn;\n"
              + "}\n");

      for (String sname : animPaths.keySet()) {
        String nspace = nameSpaces.get(sname);
        String otherNspace = nspace.substring(0, nspace.length() - 2);

        String modelName = reverseNameSpaces.get(otherNspace);

        if (modelName != null) {
          boolean useNSpace = usesNameSpace.get(sname);
          boolean otherUseNSpace = usesNameSpace.get(modelName);

          String buildType = buildTypes.get(sname);
          String otherBuildType = buildTypes.get(modelName);
          String prefix = generatePrefix(nspace, useNSpace, buildType);
          String otherPrefix = generatePrefix(otherNspace, otherUseNSpace, otherBuildType);

          out.write(
              "{\n"
                  + "  string $crvPrefix = \""
                  + prefix
                  + "\";\n"
                  + "  string $objPrefix = \""
                  + otherPrefix
                  + "\";\n"
                  + "  string $obj = $crvPrefix + \"curveInfo\";\n"
                  + "  if (`objExists $obj`) {\n"
                  + "    int $size = `getAttr -s ($obj + \".cn\")`;\n"
                  + "    int $i = 0;\n"
                  + "    for ($i = 0; $i < $size; $i++) {\n"
                  + "      string $curve = `getAttr  ($obj + \".cn[\" + $i + \"]\")`;\n"
                  + "      string $attr = `getAttr  ($obj + \".an[\" + $i + \"]\")`;\n"
                  + "      $curve =  addPrefixToName($crvPrefix, $curve);\n"
                  + "      $attr  =  addPrefixToName($objPrefix, $attr);\n"
                  + "      print(\"connectAttr -f \" + $curve + \" \" + $attr + \"\\n\");\n"
                  + "      connectAttr -f $curve $attr;   \n"
                  + "    }\n"
                  + "  }\n"
                  + "  else {\n"
                  + "    string $curves[] = `ls -type animCurve ($crvPrefix + \"*\")`;\n"
                  + "    string $curve;\n"
                  + "    for ($curve in $curves) {\n"
                  + "      string $shortName = removePrefix($curve);\n"
                  + "      string $buffer[];\n"
                  + "      tokenize($shortName, \"_\", $buffer);\n"
                  + "      string $attr = $buffer[(size($buffer) -1)];\n"
                  + "      string $name = \"\";\n"
                  + "      int $length = (size($buffer) -1);\n"
                  + "      int $i;\n"
                  + "      for ($i = 0; $i < $length; $i++) {\n"
                  + "        $name += $buffer[$i];\n"
                  + "        if ($i != ($length - 1) )\n"
                  + "          $name += \"_\";\n"
                  + "      }\n"
                  + "      string $channel = addPrefix($name, $objPrefix) + \".\" + $attr;\n"
                  + "      print ($curve + \"\\t\" + $channel + \"\\n\");\n"
                  + "      if (!`getAttr -l $channel`)\n"
                  + "        connectAttr -f ($curve + \".output\") $channel;\n"
                  + "    }\n"
                  + "  }\n"
                  + "}\n");
        }
      }

      /* set the time options */
      out.write(genPlaybackOptionsMEL());

      writeAnimMEL(agenda, out);

      /* save the file */
      out.write(
          "// SAVE\n"
              + "print \"Saving Generated Scene: "
              + targetScene
              + "\\n\";\n"
              + "file -save;\n\n");

      writeFinalMEL(agenda, out);

      out.close();
    } catch (IOException ex) {
      throw new PipelineException(
          "Unable to write temporary MEL script file ("
              + script
              + ") for Job "
              + "("
              + agenda.getJobID()
              + ")!\n"
              + ex.getMessage());
    }

    /* create the process to run the action */
    return createMayaSubProcess(null, script, true, agenda, outFile, errFile);
  }
  private boolean dylanate(
      MasterMgrClient mclient,
      String switchName,
      DoubleMap<String, String, TreeSet<VersionID>> plugs)
      throws PipelineException {
    err.println("\nProcessing: " + switchName);
    String animName = null;

    {
      NodeMod switchMod = null;
      try {
        switchMod = mclient.getWorkingVersion(pUser, pView, switchName);
      } catch (PipelineException e) {
        mclient.checkOut(pUser, pView, switchName, null, keep, pFroz);
        switchMod = mclient.getWorkingVersion(pUser, pView, switchName);
      }

      TreeSet<String> switchSrcs = new TreeSet<String>(switchMod.getSourceNames());

      for (String src : switchSrcs) {
        if (src.matches(animPattern)) {
          animName = src;
          err.println("Found anim node: " + src);
          mclient.checkOut(pUser, pView, src, null, over, frozU);
          continue;
        } // end if

        mclient.checkOut(pUser, pView, src, null, over, frozU);

        LinkMod lMod = switchMod.getSource(src);
        LinkPolicy rel = lMod.getPolicy();
        System.err.println(src + ": " + rel);
        if (!rel.equals(REF)) {
          System.err.println("umm");
          lMod.setPolicy(REF);
          switchMod.setSource(lMod);
          mclient.modifyProperties(pUser, pView, switchMod);
        }
      } // end for

      err.println("anim node: " + animName);

      mclient.modifyProperties(pUser, pView, switchMod);

      if (animName == null)
        throw new PipelineException("This switch node does not have an associated anim node");
    }
    err.println("Checked out the anim and switch nodes");

    String actionName = null;
    VersionID ttVer = null;
    boolean toCache = false;

    /*change the action setting on the Switch node*/
    {
      NodeMod switchMod = mclient.getWorkingVersion(pUser, pView, switchName);

      Path p = new Path(switchName);
      Path syfRoot = new Path(p.getParentPath().getParentPath(), "syf");
      System.err.println("Going to look for caches in: " + syfRoot);
      ArrayList<String> syfDirs = getChildrenDirs(mclient, syfRoot.toString());

      for (String dir : syfDirs) {
        System.err.println(dir);
        Path dPath = new Path(syfRoot, dir);
        ArrayList<String> simDir = getChildrenNodes(mclient, dPath.toString());
        for (String pCache : simDir) {
          Path cPath = new Path(dPath, pCache);
          if (cPath.toString().matches(cltPattern)) {
            System.err.println("\t" + cPath.toString());
            try {
              mclient.checkOut(pUser, pView, cPath.toString(), null, over, froz);
              mclient.lock(pUser, pView, cPath.toString(), null);
              mclient.link(pUser, pView, switchMod.getName(), cPath.toString(), DEP, LINKALL, null);
            } catch (PipelineException e) {
              e.printStackTrace();
            }
            toCache = true;
          }
        }
      }

      {
        BaseAction action = switchMod.getAction();
        if (!switchMod.getToolset().equals(pToolset)) {
          switchMod.setToolset(pToolset);
          mclient.modifyProperties(pUser, pView, switchMod);
        }

        if (!toCache) {
          actionName = modRep;
        } else {
          actionName = modRep + "Syflex";
        }
        ttVer = plugs.get("SCEA", actionName).last();

        if ((action == null)
            || (!action.getName().equals(actionName))
            || (!action.getVersionID().equals(ttVer))) {
          System.err.println(
              "Action name is incorrect - the switch node "
                  + switchName
                  + " doesn't have a "
                  + actionName
                  + "Action");

          action = plug.newAction(actionName, ttVer, "SCEA");
          action.setSingleParamValue("Source", animName);
          action.setSingleParamValue("Response", "Ignore");
          if (toCache) action.setSingleParamValue(aApplyCache, true);
          switchMod.setAction(action);
          mclient.modifyProperties(pUser, pView, switchMod);
        } else {
          if (!action.getSingleParamValue("Response").equals("Ignore")) {
            //						action = plug.newAction(actionName, ttVer, "SCEA");
            //						action.setSingleParamValue("Source", animName);
            action.setSingleParamValue("Response", "Ignore");
            //						if(toCache)
            //						action.setSingleParamValue(aApplyCache, true);
            switchMod.setAction(action);
            mclient.modifyProperties(pUser, pView, switchMod);
          } // end if
        } // end else
      }
    }

    {
      /*-check out and lock the animation sources-*/
      NodeMod animMod = mclient.getWorkingVersion(pUser, pView, animName);
      Set<String> animSrcs = animMod.getSourceNames();
      for (String src : animSrcs) {
        if (src.matches(loresPattern)) {
          pLoresSrcs.add(src);
          err.println("Adding lores src " + src);
        }
        mclient.checkOut(pUser, pView, src, null, keep, pFroz);
      } // end for
      err.println("lores:" + pLoresSrcs);
    }

    /*-sync the animation assets with the switch assets.*/
    // also remove unnecessary hires models
    {
      NodeMod switchMod = mclient.getWorkingVersion(pUser, pView, switchName);
      for (String src : switchMod.getSourceNames()) {
        if (src.matches(hiresPattern)) {
          err.println("Found hires source " + src);
          if (pLoresSrcs.contains(src + "_lr")) {
            pHiresSrcs.add(src);
            err.println("The hires source matched the anim node.");
          } else {
            err.println("Gotta remove " + src);
          } // end else
        } // end if
      } // end for
    }

    // add necessary hires models
    for (String lores : pLoresSrcs) {
      String hr = lores.replace("_lr", "");
      err.println("Looking at lores source " + lores + " which matches " + hr);
      if (!pHiresSrcs.contains(hr)) {
        err.println("Gotta add " + hr + " to " + switchName);
        pHiresSrcs.add(hr);
      }
    }

    {
      NodeMod switchMod = mclient.getWorkingVersion(pUser, pView, switchName);
      TreeSet<String> switchSrcs = new TreeSet<String>(switchMod.getSourceNames());
      err.println("Final hiRes list:" + pHiresSrcs + "\n");
      err.println("switch now has:\n\t" + switchSrcs + "\n");
      err.println("Looking for things to add.");
      for (String src : pHiresSrcs) {
        if ((src.matches(hiresPattern) && (!switchSrcs.contains(src)))) {
          err.print("Linking ");
          mclient.checkOut(pUser, pView, src, null, over, frozU);
          mclient.link(pUser, pView, pPrimary, src, REF, LINKALL, null);
          switchSrcs.add(src);
        }
        err.println("src from hiRes list: " + src);
      }
    }

    {
      NodeMod switchMod = mclient.getWorkingVersion(pUser, pView, switchName);
      TreeSet<String> switchSrcs = new TreeSet<String>(switchMod.getSourceNames());
      err.println("switch now has:\n\t" + switchSrcs + "\n");
      for (String src : switchSrcs) {
        if ((src.matches(hiresPattern) && (!pHiresSrcs.contains(src)))) {
          err.print("Unlinking ");
          mclient.unlink(pUser, pView, pPrimary, src);
        }
        err.println("src from switch node list: " + src);
      }
    }

    /*queue the switch node*/
    mclient.submitJobs(pUser, pView, switchName, null);

    return false;
  }