/*
* Copyright (c) 2009 Stanford University, School of Medicine All rights reserved. 
* 
* STANFORD ACADEMIC SOFTWARE LICENSE AGREEMENT 
* FOR AngioLocalize SOURCE CODE: 
* 
* 1.  This is a legal agreement between you, RECIPIENT, and STANFORD UNIVERSITY.  
*       By accepting, receiving, and using AngioLocalize.including any accompanying information, materials or 
*       manuals (Program), you are agreeing to be bound by the terms of this Agreement.  
*       If you do not agree to the terms of this Agreement, promptly return the Program to the STANFORD.

* 2.  STANFORD grants to RECIPIENT a royalty-free, nonexclusive, and nontransferable license to use the Program 
*       and accompanying source code furnished hereunder, upon the terms and conditions set out below. 
*       documentation and/or other materials provided with the distribution. 
* 3.  RECIPIENT acknowledges that the Program is a research tool still in the development stage and that 
*       it is being supplied as is, without any accompanying services, support or improvements from STANFORD.
* 4.  RECIPIENT agrees to use the Program solely for internal non-commercial purposes. 
* 5.  RECIPIENT may create derivatives and further transfer the Program under the following terms and conditions: 
*        A) Recipient agrees to not commercially exploit the Program and agrees all uses will be for non-commercial purposes; and,
*        B) Recipient may not mark any derivatives with the title of Program and may not to use iPad mark for any derivatives; and,
*        C) Recipient agrees to mark and acknowledge all derivatives as follows: "This is a derivative work based on AngioLocalize:
*           Frameless AVM localization with 2D Digital Subtraction Angiography (DSA) and 3D Rotational Angiography (DRA) Images developed
*           by Dimitre Hristov, Lina Liu.
*        D) Recipient agrees to make all improvements, enhancements and derivatives available under 
*           similar terms and conditions to the research community. 
* 6.   RECIPIENT warrants that RECIPIENT will not remove or export any part of the software or Program from the United 
*       States except in full compliance with all United States and other applicable laws and regulations.
* 7.  RECIPIENT will use the Program in compliance with all applicable laws, policies and regulations including, but not 
*       limited to, any approvals, informed consent and patient confidentiality principles.
* 8.   RECIPIENT will indemnify, hold harmless, and defend Stanford against any claim of any kind arising out of or
*       related to the exercise of any rights granted under this Agreement or the breach of this Agreement by RECIPIENT.
* 9.  Title and copyright to the Program and any associated documentation shall at all times remain with STANFORD, 
*       and RECIPIENT agrees to preserve same.
*/
//----------------------------------------------------------------------------------
//! Macro module RTStructExportTool
/*!
// \file    RTStructExportTool.js
// \author  linal
// \date    2010-05-17
//
// export CSO to RTStructure and images to sliced images
*/
//----------------------------------------------------------------------------------

gEchoSCUexe  = MLABFileManager.getExecutable("echoscu");
gStoreSCUexe = MLABFileManager.getExecutable("storescu");

gStoreSCUProcess = null;
gEchoSCUProcess = null;

initModule();

function initModule() {
  // reset ImageSave parameters
  ctx.field("Saver.format").setStringValue("DICOM");
  ctx.field("Saver.filename").setStringValue("");

  //  resetGlobalDefaults();
  updateImageInformation();
  updateExportDirectory(0);
  updateSlicesAndTimepoints();
  updateSaveEnabled();
  

  ctx.field("dicomConsole").setStringValue("");

  autoLoadDICOMConfig();
  //ctx.log("gConfigFilename = "+gConfigFilename);
  //ctx.log("gEchoSCUexe = "+gEchoSCUexe);
  //ctx.log("gStoreSCUexe = "+gStoreSCUexe);
}

function resetGlobalDefaults() {
  ctx.field("exportBaseDir").setStringValue("");
  ctx.field("addPatNameDir").setValue(false);
  ctx.field("addStudyUIDDIR").setValue(false);
  ctx.field("addSeriesUIDDIR").setValue(false);

  ctx.field("allSlices").setValue(true);
  ctx.field("allTimepoints").setValue(true);

  ctx.field("minSlice").setMinMaxValue(1,ctx.field("Info.sizeZ").intValue());
  ctx.field("maxSlice").setMinMaxValue(1,ctx.field("Info.sizeZ").intValue());
  ctx.field("minSlice").setIntValue(1);
  ctx.field("maxSlice").setIntValue(ctx.field("Info.sizeZ").intValue());

  ctx.field("minTime").setMinMaxValue(1,ctx.field("Info.sizeT").intValue());
  ctx.field("maxTime").setMinMaxValue(1,ctx.field("Info.sizeT").intValue());
  ctx.field("minTime").setIntValue(1);
  ctx.field("maxTime").setIntValue(ctx.field("Info.sizeT").intValue());

  updateExportDirectory()
//  updateImageInformation();
}

function updateImageInformation() {
  //ctx.log("updateImageInformation()");
  // set min/max values for new image
  var minSlice = ctx.field("minSlice");
  var maxSlice = ctx.field("maxSlice");
  var minTime = ctx.field("minTime");
  var maxTime = ctx.field("maxTime");

  minSlice.setMinMaxValue(1,ctx.field("Info.sizeZ").intValue());
  maxSlice.setMinMaxValue(1,ctx.field("Info.sizeZ").intValue());
  maxSlice.setIntValue(ctx.field("Info.sizeZ").intValue());

  minTime.setMinMaxValue(1,ctx.field("Info.sizeT").intValue());
  maxTime.setMinMaxValue(1,ctx.field("Info.sizeT").intValue());
  maxTime.setIntValue(ctx.field("Info.sizeT").intValue());

  // check/init UIDs
  ctx.field("UIDModifier.getValues").touch();

  if (ctx.field("UIDModifier.tagValue0").stringValue() == "") {
    ctx.field("hasSeriesUID").setValue(false);
  }
  else {
    ctx.field("hasSeriesUID").setValue(true);
  }
  if (ctx.field("UIDModifier.tagValue1").stringValue() == "") {
    ctx.field("hasStudyUID").setValue(false);
  }
  else {
    ctx.field("hasStudyUID").setValue(true);
  }

  // create necessary UIDs
  createUIDs();
  
}

function updateSlicesAndTimepoints() {
  //ctx.log("updateSlicesAndTimepoints()");
  var minSlice = ctx.field("minSlice").intValue();
  var maxSlice = ctx.field("maxSlice").intValue();
  var minUsedSlice = ctx.field("minUsedSlice");
  var maxUsedSlice = ctx.field("maxUsedSlice");
  var minTime = ctx.field("minTime").intValue();
  var maxTime = ctx.field("maxTime").intValue();
  var minUsedTime = ctx.field("minUsedTime");
  var maxUsedTime = ctx.field("maxUsedTime");

  if (ctx.field("allSlices").boolValue()) {
    minUsedSlice.setIntValue(0);
    maxUsedSlice.setIntValue(ctx.field("Info.sizeZ").intValue());
  } 
  else {
    minUsedSlice.setIntValue(minSlice-1);
    maxUsedSlice.setIntValue(maxSlice);
  }

  if (ctx.field("allTimepoints").boolValue()) {
    minUsedTime.setIntValue(0);
    maxUsedTime.setIntValue(ctx.field("Info.sizeT").intValue());
  } 
  else {
    minUsedTime.setIntValue(minTime-1);
    maxUsedTime.setIntValue(maxTime);
  }

  //ctx.log("Now using "+minUsedSlice.intValue()+"<=z<"+maxUsedSlice.intValue());
  //ctx.log("          "+minUsedTime.intValue()+"<=t<"+maxUsedTime.intValue());
}

function updateSaveEnabled() {
  var restoreFrameSpecific = ctx.field("restoreFrameSpecific").value;
  var frameSpecificValid = ctx.field("subFrame.valid").value;
  ctx.field("saveEnabled").value = !restoreFrameSpecific || frameSpecificValid;
}

function updateExportDirectory(guiReady) {
  var baseDir = ctx.field("exportBaseDir").stringValue();
  var patName = ctx.field("DICOMInfo.tagValue0").stringValue();
  var studyUID = ctx.field("DICOMInfo.tagValue1").stringValue();
  var seriesUID = ctx.field("DICOMInfo.tagValue2").stringValue();
  // bk20030826: removed standardizing (is there something similar in QT?)
  // var exportDir = [baseDir stringByStandardizingPath:];
  var exportDir = baseDir;

  if (ctx.field("newSeriesUID").boolValue()) {
    seriesUID = ctx.field("UIDModifier.tagValue0").stringValue();
  }
  if (ctx.field("newStudyUID").boolValue()) {
    studyUID = ctx.field("UIDModifier.tagValue1").stringValue();
  }

  if (ctx.field("addPatNameDir").boolValue())
    exportDir = exportDir+"/"+patName;
  if (ctx.field("addStudyUIDDIR").boolValue())
    exportDir = exportDir+"/"+studyUID;
  if (ctx.field("addSeriesUIDDIR").boolValue())
    exportDir = exportDir+"/"+seriesUID;

  ctx.field("exportDir").setStringValue(exportDir);
  if (guiReady) {
    ctx.control("exportDirCtrl").setToolTip(exportDir);
  }
  ctx.field("fileHelper.path").setStringValue(exportDir);

  //ctx.log("set export directory to "+exportDir);
}

function createStudyUID() {
  ctx.field("studyUID.createButton").touch();
}

function createSeriesUID() {
  //ctx.log("create new series UID");
  ctx.field("seriesUID.createButton").touch();
}
function createUIDs()
{
  // get original UIDs
  ctx.field("UIDModifier.getValues").touch();

  if (ctx.field("UIDModifier.tagValue0").stringValue() == ""
      || ctx.field("newSeriesUID").boolValue()) {
    createSeriesUID();
  }
  if (ctx.field("UIDModifier.tagValue1").stringValue() == ""
      || ctx.field("newStudyUID").boolValue()) {
    createStudyUID();
  }
}

function saveDICOMSlices(exportDir) {
  var minUsedSlice = ctx.field("minUsedSlice").intValue();
  var maxUsedSlice = ctx.field("maxUsedSlice").intValue();
  var minUsedTime = ctx.field("minUsedTime").intValue();
  var maxUsedTime = ctx.field("maxUsedTime").intValue();
  var totalSlices = (maxUsedTime-minUsedTime) * (maxUsedSlice-minUsedSlice);
  var imNumber = 0;
  var prog = 0.0;
  var fillString = "0000";
  var nrString = "";
  var cancelled = 0;

//  ctx.log("Exporting z="+minUsedSlice+", "+maxUsedSlice+"t="+minUsedTime+","+maxUsedTime);

  // enable cancel button
  ctx.field("canCancel").setValue(true);

  if (exportDir && exportDir != "") {
    // the export dir was given as argument
    ctx.field("fileHelper.path").setStringValue(exportDir);
  }

  if (ctx.field("fileHelper.path").stringValue()=="") {
    MLAB.logWarning("Invalid directory");
    setStatus("Invalid directory");
    return;
  }

  // create the directory if it's not already there
  ctx.field("fileHelper.createDir").touch();
  // not sure if this is really needed, but probably the info
  // fields are not yet up to date right after creating the 
  // directory
  ctx.field("fileHelper.update").touch();
  
  if (!ctx.field("fileHelper.exists").boolValue() || (ctx.field("fileHelper.exists").boolValue() && !ctx.field("fileHelper.isDirectory").boolValue())) {
    MLAB.logError("Couldn't create directory");
    setStatus("Couldn't create directory");
    return;
  }

  // set up UIDs Tags
  createUIDs()

  for (var t=minUsedTime; t<maxUsedTime && cancelled == 0; t++) {
    ctx.field("Sub.t").setFloatValue(t);
    ctx.field("Sub.st").setFloatValue(1);

    for (var z=minUsedSlice; z<maxUsedSlice && cancelled == 0; z++) {
      if (MLAB.shouldStop()) {
        cancelled = 1;
      }

      imNumber++;

      ctx.field("UIDModifier.tagValue2").setStringValue(imNumber.toString());

      prog = 1.0*imNumber/totalSlices;

      nrString = fillString.substring(0,4-imNumber.toString().length);
      nrString += imNumber.toString();

      setProgress(prog);

      ctx.field("Sub.z").setFloatValue(z);
      ctx.field("Sub.sz").setFloatValue(1);

      ctx.field("filename.userStringT").setStringValue(nrString);
      
      ctx.field("Saver.filename").setStringValue(ctx.field("filename.outputName").stringValue());
      ctx.field("Saver.save").touch();

      setStatus("Saving ["+imNumber+"/"+totalSlices+"]");
    }
  }

  setProgress(0.0);
  // disable cancel button
  ctx.field("canCancel").setValue(false);

  var RTStructFile = "";
  RTStructFile = ctx.field("fileHelper.path").stringValue();
  RTStructFile += "//RTstruct";
  newString = ctx.field("fileHelper.createDate").stringValue();
  
  var formattedStr = newString.replace(/:/g, "-");
  ctx.log("newString:" + formattedStr);
  RTStructFile += formattedStr;
  
  RTStructFile += ".dcm";
  ctx.log("RTStructFile:" + RTStructFile);
  ctx.field("CSOToRTStructure.rtStructFile").setStringValue(RTStructFile);
  if (ctx.field("CSOToRTStructure.valid").boolValue() == true)
  {
    ctx.field("CSOToRTStructure.apply").touch();
  }
  if (cancelled == 0)
  {
    setStatus("Saved "+totalSlices+" DICOM images and 1 RTStructure to "+ctx.field("fileHelper.path").stringValue());
    ctx.log("Saved "+totalSlices+" DICOM images and 1 RTStructure to "+ctx.field("fileHelper.path").stringValue());

    return totalSlices;
  }
  else {
    setStatus("Cancelled Saving to "+ctx.field("fileHelper.path").stringValue());
  
    return -1;
  }
  
}

function echoSCU(aet, aec, peer, port, quiet) {
  var args = [];
  var status ="";
  var exe = gEchoSCUexe;
  var echoStatus = 0;

  if (!quiet) {
    quiet = 0;
  }

  if (quiet == 0) {
    // clear console if autoclear mode is set
    if (ctx.field("consoleAutoClear").boolValue()) {
      clearConsole();
    }
  }

  args.push(exe);

  if (ctx.field("echoVerbose").boolValue()) 
    args.push("-v");
  if (ctx.field("echoDebug").boolValue())  
    args.push("-d");

  if (!aet) {
    aet = ctx.field("dicomCallingAET").stringValue();
  }
  if (!aec) {
    aec = ctx.field("dicomCalledAET").stringValue();
  }
  if (!peer) {
    peer = ctx.field("dicomHostname").stringValue();
  }
  if (!port) {
    port = ctx.field("dicomPort").stringValue();
  }

  if (aet && aet != "") {
    args.push("-aet");
    args.push(aet);
  }

  if (aec && aec != "") {
    args.push("-aec");
    args.push(aec);
  }

  if (!peer || peer == "") {
    status = "DICOM Hostname not set! Check DICOM Settings";
  } 
  else {
    args.push(peer);
  }

  if (!port || port == 0) {
    status = "DICOM Port not set! Check DICOM Settings";
  } 
  else {
    args.push(port);
  }

  if (!status) {
    gEchoSCUProcess = MLAB.newProcess();
    if (quiet == 0) {
      gEchoSCUProcess.setStdOutHandler(ctx, "dicomOutput");
      gEchoSCUProcess.setStdErrHandler(ctx, "dicomError");
    }

    gEchoSCUProcess.addArguments(args);
    gEchoSCUProcess.run();
    gEchoSCUProcess.waitForExit();

    echoStatus = gEchoSCUProcess.exitStatus();
    if (echoStatus == 0) {
      if (quiet == 0) {
        MLAB.showInformation("DICOM C-ECHO request successful for \nHost:\t"+peer+"\nPort:\t"+port+"\nAET:\t"+aec);
      }
    }
    else {
      if (quiet == 0) {
        MLAB.showWarning("DICOM Server could not be contacted, please check DICOM settings:\nHost:\t"+peer+"\nPort:\t"+port+"\nAET:\t"+aec);
      }
    }
  }
  else {
    MLAB.logWarning("echoscu not started, reason: "+status);
  }

  return echoStatus;
}

function storeSCU(aet, aec, peer, port) {
  var args = [];
  var status ="";
  var exe = gStoreSCUexe;
  var processStatus = 0;
  var cancelled = 0;
  var totalSlices = -1;

  // clear console if autoclear mode is set
  if (ctx.field("consoleAutoClear").boolValue()) {
    clearConsole();
  }

  //gStoreSCUProcess.addArgument(exe);
  args.push(exe);

  if (ctx.field("storeVerbose").boolValue()) 
  {
    args.push("-v");
    //gStoreSCUProcess.addArgument("-v");
  }
  if (ctx.field("storeDebug").boolValue())  
  {
    args.push("-d");
    //gStoreSCUProcess.addArgument("-d");
  }

  if (!aet) {
    aet = ctx.field("dicomCallingAET").stringValue();
  }
  if (!aec) {
    aec = ctx.field("dicomCalledAET").stringValue();
  }
  if (!peer) {
    peer = ctx.field("dicomHostname").stringValue();
  }
  if (!port) {
    port = ctx.field("dicomPort").stringValue();
  }

  if (aet && aet != "") {
    args.push("-aet");
    args.push(aet);
    //gStoreSCUProcess.addArgument("-aet");
    //gStoreSCUProcess.addArgument(aet);
  }

  if (aec && aec != "") {
    args.push("-aec");
    args.push(aec);
    //gStoreSCUProcess.addArgument("-aec");
    //gStoreSCUProcess.addArgument(aec);
  }

  if (!peer || peer == "") {
    status = "DICOM Hostname not set! Check DICOM Settings";
  } 
  else {
    args.push(peer);
    //gStoreSCUProcess.addArgument(peer);
  }

  if (!port || port == 0) {
    status = "DICOM Port not set! Check DICOM Settings";
  } 
  else {
    args.push(port);
    //gStoreSCUProcess.addArgument(port);
  }

  processStatus = echoSCU(aet,aec,peer,port,1);

  if (processStatus == 1) {
    MLAB.showWarning("DICOM Server could not be contacted, please check DICOM settings:\nHost:\t"+peer+"\nPort:\t"+port+"\nAET:\t"+aec);

    // disable cancel button and cleanup
    ctx.field("canCancel").setValue(false);
    return;
  }

  if (!status) {
    var fileManager = MLABFileManager;
    var tempDir = fileManager.getTmpDir();
    var tempExportDir = tempDir+"/"+"MLabDICOMExport";
    var imNumber = 0;
    var prog = 0.0;
    var dirContent;
    //logVar("tempDir",tempDir);
    //logVar("tempExportDir",tempExportDir);

    totalSlices = saveDICOMSlices(tempExportDir);

    //logVar("totalSlice", totalSlices);

    var file = "";
    var fileArgs = [];
    
    dirContent = fileManager.contentOfDirectory(tempExportDir);

    if (totalSlices > 0) {
      for (var i = 0; i < totalSlices && cancelled == 0; i++)
      {
        var filename = tempExportDir+"/"+dirContent[i];
        
        // setup store process
        gStoreSCUProcess = MLAB.newProcess();
        gStoreSCUProcess.setWorkDir(tempExportDir);
        gStoreSCUProcess.setStdOutHandler(ctx, "dicomOutput");
        gStoreSCUProcess.setStdErrHandler(ctx, "dicomError");
        
        fileArgs = args.concat([filename]);
        imNumber++;
        prog = 1.0*imNumber/totalSlices;
        
        //MLAB.log("Sending ["+imNumber+"/"+totalSlices+"]");
        setStatus("Sending ["+imNumber+"/"+totalSlices+"]");
        setProgress(prog);
        
        gStoreSCUProcess.addArguments(fileArgs);
        
        
//      logVar("filename",filename);
//      logVar("exe",exe);
//      logVar("fileArgs",fileArgs);
        
//      ctx.log("commandline "+exe+" "+[fileArgs description:]);
        
        //MLAB.runCommand(exe, fileArgs);
        
        gStoreSCUProcess.run();

        /* This method makes sending *very* slow, so I 
           temporarily disabled the ability to cancel
           the sending...
        while (gStoreSCUProcess.isRunning()) {
          if (MLAB.shouldStop()) {
            cancelled = 1;
            gStoreSCUProcess.kill();
          }
        }
        */
        gStoreSCUProcess.waitForExit();
        
        fileManager.remove(filename);
        MLAB.deleteProcess(gStoreSCUProcess);
        
        //MLAB.usleep(1);
      }
    }
    setStatus("Cleaning Up");
    fileManager.recursiveRemoveDir(tempExportDir);
  }
  else {
    MLAB.logWarning("storescu not started, reason: "+status);
  }

  setProgress(0.0);

  if (cancelled == 1 || totalSlices == -1)
  {
    setStatus("Cancelled");
  }
  else 
  {
    setStatus("Finished");
    ctx.log("Sent "+totalSlices+" images to ("+peer+","+aec+","+port+")");
  }

  ctx.field("canCancel").setValue(false);
}

function dicomOutput(process) 
{
  var outString = "";

  outString = outString + process.readStdOut();
  ctx.field("dicomOutput").value = outString;
}
function dicomError(process) 
{
  var errorString = "<b>Error: </b>";
  var processError = process.readStdErr();

  MLAB.logError(processError);
  errorString = errorString + processError;

  ctx.field("dicomOutput").value = "<tt>"+errorString+"</tt>" + "<br/>";
}

function clearConsole()
{
  ctx.field("dicomConsole").value = "";
}

function appendDicomOutput() {
  var output = ctx.field("dicomOutput").value;
  
  ctx.control("consoleControl").appendText(output);
  ctx.field("dicomOutput").value = "";
}

/* Expanddirectory name macros */
function ExpandPath (path)
{
  path = ctx.expandFilename(path);
  return path;
}

function logVar(string, variable)
{
  MLAB.log("Variable "+string+"="+variable);
}

function unimplemented() {
  MLAB.log("Not yet implemented");
}

function setStatus(string) {
  ctx.field("status").setStringValue(string);
//  ctx.log("DICOMTool: "+string);
}
function setProgress(progress) {
  ctx.field("progress").setFloatValue(progress);
}

function setDisplayMode () {
  var displayMode1 = ctx.field("displayMode1").stringValue();
  var displayMode2 = ctx.field("displayMode2").stringValue();
  
  var content = "Panel {";

  switch (displayMode1)
  {
  case "Input":
    content = content + "module = DICOMInfo ";
    break;
  case "Output":
    content = content + "module = DICOMOutInfo ";
    break;
  }
  switch (displayMode2)
  {
  case "Selected":
    content = content + "panel = readTagsPanel";
    break;
  case "All":
    content = content + "panel = allTagsPanel";
    break;
  }

  content = content+"}";

  ctx.control("dynFrame").setContentString(content);
}
//# MeVis signature v1
//# key: MFowDQYJKoZIhvcNAQEBBQADSQAwRgJBANEfsmYse2e1dRhkQ9AQbreCq9uxwzWLoGom13MNYmyfwoJqQOEXljLFAgw2eEjaT12G4CdqKWhRxh9ANP6n7GMCARE=:VI/mB8bT4u+mRtf/ru8yUQi8BzpaS3UeL2x62YxsUYnVqCWuLrVNLiukIIjnJMKQXlc8ezmgOIcVAV7pgvgKpQ==
//# owner: MeVis
//# date: 2009-05-09T05:37:19
//# hash: x0fIzhmyGZBbTRF3fVyqf1wXu50KjikY2K8qAuOdcY2BJccqyDQRYMEuiB52qj1XAwh5slf5GovSBoinpqETeQ==
//# MeVis end

