context: using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Globalization;
  using System.IO;
  using System.Linq;
  using System.Text;
  
  using Epanet.Enums;
  using Epanet.Hydraulic;
  using Epanet.Hydraulic.IO;
  using Epanet.Network;
  using Epanet.Network.IO.Input;
  using Epanet.Network.Structures;
  using Epanet.Quality;
  using Epanet.Util;
  
  using EpanetNetwork = Epanet.Network.Network;
  
  namespace Epanet {
  
      public class Program {
          public static void Main(string[] args) {
              TraceSource log = new TraceSource(typeof(Program).FullName ?? nameof(Program), SourceLevels.All);
  
              string hydFile = null;
              string qualFile = null;
  
              List<NodeVariableType> nodesVariables = new List<NodeVariableType>();
              List<LinkVariableType> linksVariables = new List<LinkVariableType>();
  
              string inFile = "";
              List<TimeSpan> targetTimes = new List<TimeSpan>();
              List<string> targetNodes = new List<string>();
              List<string> targetLinks = new List<string>();
  
              int parseMode = 0;
              foreach (string arg in args) {
                  if (arg.EndsWith(".inp", StringComparison.OrdinalIgnoreCase)) {
                      parseMode = 0;
                      inFile = arg;
                      if (!File.Exists(inFile)) {
                          ConsoleLog("END_RUN_ERR");
                          Console.Error.WriteLine("File not found !");
                          return;
                      }
  
                      continue;
                  }
  
                  switch (arg) {
                      case "-T":
                      case "-t":
                          parseMode = 1;
                          continue;
                      case "-N":
                      case "-n":
                          parseMode = 2;
                          continue;
                      case "-L":
                      case "-l":
                          parseMode = 3;
                          continue;
                  }
  
                  switch (parseMode) {
                      case 1:
                          targetTimes.Add(Utilities.ToTimeSpan(arg));
                          break;
                      case 2:
                          targetNodes.Add(arg);
                          break;
                      case 3:
                          targetLinks.Add(arg);
                          break;
                  }
              }
  
              try {
                  InputParser parserInp = InputParser.Create(FileType.INP_FILE);
                  EpanetNetwork net = parserInp.Parse(new EpanetNetwork(), inFile);
  
                  if (targetTimes.Count > 0)
                      foreach (var time in targetTimes) {
                          string epanetTime = time.GetClockTime();
                          if (time < net.RStart)
                              throw new Exception("Target time \"" + epanetTime + "\" smaller than simulation start time");
  
                          if (time > net.Duration)
                              throw new Exception("Target time \"" + epanetTime + "\" bigger than simulation duration");
  
                          // FIXME: precision 
                          if ((time - net.RStart).Ticks % net.RStep.Ticks != 0)
                              throw new Exception("Target time \"" + epanetTime + "\" not found");
                      }
  
                  foreach (string nodeName in targetNodes)
                      if (net.GetNode(nodeName) == null)
                          throw new Exception("Node \"" + nodeName + "\" not found");
  
                  foreach (string linkName in targetLinks)
                      if (net.GetLink(linkName) == null)
                          throw new Exception("Link \"" + linkName + "\" not found");
  
                  nodesVariables.Add(NodeVariableType.ELEVATION);
                  nodesVariables.Add(NodeVariableType.BASEDEMAND);
  
                  if (net.QualFlag != QualType.NONE)
                      nodesVariables.Add(NodeVariableType.INITQUALITY);
  
                  nodesVariables.Add(NodeVariableType.PRESSURE);
                  nodesVariables.Add(NodeVariableType.HEAD);
                  nodesVariables.Add(NodeVariableType.DEMAND);
  
                  if (net.QualFlag != QualType.NONE)
                      nodesVariables.Add(NodeVariableType.QUALITY);
  
                  linksVariables.Add(LinkVariableType.LENGHT);
                  linksVariables.Add(LinkVariableType.DIAMETER);
                  linksVariables.Add(LinkVariableType.ROUGHNESS);
                  linksVariables.Add(LinkVariableType.FLOW);
                  linksVariables.Add(LinkVariableType.VELOCITY);
                  linksVariables.Add(LinkVariableType.UNITHEADLOSS);
                  linksVariables.Add(LinkVariableType.FRICTIONFACTOR);
  
                  if (net.QualFlag != QualType.NONE)
                      linksVariables.Add(LinkVariableType.QUALITY);
  
                  hydFile = Path.GetTempFileName(); // "hydSim.bin"
  
                  ConsoleLog("START_RUNNING");
  
                  HydraulicSim hydSim = new HydraulicSim(net, log);
                  hydSim.Simulate(hydFile);
  
                  if (net.QualFlag != QualType.NONE) {
                      qualFile = Path.GetTempFileName(); // "qualSim.bin"
  
                      QualitySim q = new QualitySim(net, log);
                      q.Simulate(hydFile, qualFile);
                  }
  
                  HydraulicReader hydReader = new HydraulicReader(new BinaryReader(File.OpenRead(hydFile)));
  
                  StreamWriter nodesTextWriter = null;
                  StreamWriter linksTextWriter = null;
                  string nodesOutputFile = null;
  
                  if (targetNodes.Count == 0 && targetLinks.Count == 0 || targetNodes.Count > 0) {
                      nodesOutputFile = Path.GetFullPath(inFile) + ".nodes.out";
                      nodesTextWriter = new StreamWriter(nodesOutputFile, false, Encoding.UTF8);
  
                      nodesTextWriter.Write('\t');
                      foreach (NodeVariableType nodeVar in nodesVariables) {
                          nodesTextWriter.Write('\t');
                          nodesTextWriter.Write(nodeVar.ToString());
                      }
  
                      nodesTextWriter.Write("\n\t");
  
                      foreach (NodeVariableType nodeVar in nodesVariables) {
                          nodesTextWriter.Write('\t');
                          nodesTextWriter.Write(net.FieldsMap.GetField(ToFieldType(nodeVar)).Units);
                      }
  
                      nodesTextWriter.Write('\n');
                  }
  
                  if (targetNodes.Count == 0 && targetLinks.Count == 0 || targetLinks.Count > 0) {
                      string linksOutputFile = Path.GetFullPath(inFile) + ".links.out";
                      linksTextWriter = new StreamWriter(linksOutputFile, false, Encoding.UTF8);
  
                      linksTextWriter.Write('\t');
                      foreach (LinkVariableType linkVar in linksVariables) {
                          linksTextWriter.Write('\t');
                          linksTextWriter.Write(linkVar.ToString());
                      }
  
                      linksTextWriter.Write("\n\t");
  
                      foreach (LinkVariableType linkVar in linksVariables) {
                          linksTextWriter.Write('\t');
                          if (linkVar < 0) continue;
  
                          linksTextWriter.Write(net.FieldsMap.GetField((FieldType)linkVar).Units);
                      }
  
                      linksTextWriter.Write('\n');
                  }
  
                  for (TimeSpan time = net.RStart; time <= net.Duration; time += net.RStep) {
                      AwareStep step = hydReader.GetStep(time);
  
                      int i = 0;
  
                      if (targetTimes.Count > 0 && !targetTimes.Contains(time))
                          continue;
  
                      if (nodesTextWriter != null)
                          foreach (Node node in net.Nodes) {
                              if (targetNodes.Count > 0 && !targetNodes.Contains(node.Name))
                                  continue;
  
                              nodesTextWriter.Write(node.Name);
  
                              nodesTextWriter.Write('\t');
                              nodesTextWriter.Write(time.GetClockTime());
  
                              foreach (NodeVariableType nodeVar in nodesVariables) {
                                  nodesTextWriter.Write('\t');
                                  double val = GetNodeValue(nodeVar, net.FieldsMap, step, node, i);
                                  nodesTextWriter.Write(ConvertToScientifcNotation(val, 1000, 0.01, 2));
                              }
  
                              nodesTextWriter.Write('\n');
  
                              i++;
                          }
  
                      i = 0;
  
                      if (linksTextWriter != null)
                          foreach (Link link in net.Links) {
                              if (targetLinks.Count > 0 && !targetLinks.Contains(link.Name))
                                  continue;
  
                              linksTextWriter.Write(link.Name);
  
                              linksTextWriter.Write('\t');
                              linksTextWriter.Write(time.GetClockTime());
  
                              foreach (LinkVariableType linkVar in linksVariables) {
                                  linksTextWriter.Write('\t');
                                  double val = GetLinkValue(
                                      linkVar,
                                      net.FormFlag,
                                      net.FieldsMap,
                                      step,
                                      link,
                                      i);
                                  linksTextWriter.Write(ConvertToScientifcNotation(val, 1000, 0.01, 2));
                              }
  
                              linksTextWriter.Write('\n');
  
                              i++;
                          }
                  }
  
                  if (nodesTextWriter != null) {
                      nodesTextWriter.Close();
                      ConsoleLog("NODES FILE \"" + nodesOutputFile + "\"");
                  }
  
                  if (linksTextWriter != null) {
                      linksTextWriter.Close();
                      ConsoleLog("LINKS FILES \"" + nodesOutputFile + "\"");
                  }
  
                  ConsoleLog("END_RUN_OK");
              }
  
gt:             catch (EnException e) {