//var scoresGrouped = scores.GroupBy(a => new Tuple<string, bool>(a.StructureFilename, a.StructureFolder.Contains("Reversed")));

        //foreach (var scoreGrouped in scoresGrouped)
        //{

        //var output = scoreGrouped.ToList().Select(a=>a.ToString()).ToList();// .SelectMany(a => a.SubstitutionDescription == "Native (No change)" ? new[] {"", a.ToString()} : new[] {a.ToString()}).ToList();
        //var output = scores.ToList().Select(a => a.ToString()).ToList();// .SelectMany(a => a.SubstitutionDescription == "Native (No change)" ? new[] {"", a.ToString()} : new[] {a.ToString()}).ToList();

        //output.Insert(0, EnergyScore.Header());
        //scores[1].ToString()
        //File.WriteAllLines(logResultsFolder + Environment.MachineName + "_energy.csv", output);

        //Environment.MachineName
        //File.WriteAllLines(saveFile, output);
        //}
        //}

        /*
         *  var pisaLogFiles = Directory.GetFiles(logResultsFolder, "pisa_monomer.log", SearchOption.AllDirectories);
         *  //var pdbtoolsLogFiles = Directory.GetFiles(logResultsFolder, "pdbtools_monomer.log", SearchOption.AllDirectories);
         *  var infoLogFiles = Directory.GetFiles(logResultsFolder, "substitution.log", SearchOption.AllDirectories);
         *
         *  var folders = new List<string>();
         *
         *  folders.AddRange(modellerLogFiles.Select(Path.GetDirectoryName).ToList());
         *  folders.AddRange(pisaLogFiles.Select(Path.GetDirectoryName).ToList());
         *  //folders.AddRange(pdbtoolsLogFiles.Select(Path.GetDirectoryName).ToList());
         *  folders.AddRange(infoLogFiles.Select(Path.GetDirectoryName).ToList());
         *  folders = folders.Distinct().ToList();
         *
         *  var scores = new List<EnergyScore>();
         *
         *  for (int folderIndex = 0; folderIndex < folders.Count; folderIndex++)
         *  {
         *      var folder = folders[folderIndex];
         *      var modellerMonomerLogFile = folder + @"\modeller_monomer_assessment.log";
         *      var modellerDimerLogFile = folder + @"\modeller_dimer_assessment.log";
         *      var pisaMonomerLogFile = folder + @"\pisa_monomer.log";
         *      var pisaDimerLogFile = folder + @"\pisa_dimer.log";
         *      //var pdbtoolsLogFile = folder + @"\pdbtools_monomer.log";
         *      var infoLogFile = folder + @"\substitution.log";
         *
         *      var pisaMonomerLogFileLines = new string[0];
         *      var pisaDimerLogFileLines = new string[0];
         *      var pdbtoolsLogFileLines = new string[0];
         *      var modellerMonomerLogFileLines = new string[0];
         *      var modellerDimerLogFileLines = new string[0];
         *      var infoLogFileLines = new string[0];
         *
         *      if (File.Exists(modellerMonomerLogFile)) modellerMonomerLogFileLines = File.ReadAllLines(modellerMonomerLogFile);
         *      if (File.Exists(modellerDimerLogFile)) modellerMonomerLogFileLines = File.ReadAllLines(modellerMonomerLogFile);
         *      if (File.Exists(pisaMonomerLogFile)) pisaMonomerLogFileLines = File.ReadAllLines(pisaMonomerLogFile);
         *      if (File.Exists(pisaDimerLogFile)) pisaDimerLogFileLines = File.ReadAllLines(pisaDimerLogFile);
         *
         *      if (File.Exists(infoLogFile)) infoLogFileLines = File.ReadAllLines(infoLogFile);
         *
         *      if (pisaMonomerLogFileLines.Length == 0 && pdbtoolsLogFileLines.Length == 0 && modellerMonomerLogFileLines.Length == 0 &&
         *          infoLogFileLines.Length == 0) continue;
         *
         *      var folderNameSplit = folder.Replace(logResultsFolder, @"").Replace('\\', ',').Split(',');
         *
         *      var infoScore = new EnergyScore();
         *
         *      infoScore.StructureFolder = folder;
         *
         *      infoScore.StructuralTruncation = folderNameSplit[0];
         *
         *      var line = -1;
         *
         *
         *
         *      infoScore.Input1QprReceptorCluster = infoLogFileLines[++line] + "-" + infoLogFileLines[++line];
         *      infoScore.Input1QprLigandCluster = infoLogFileLines[++line] + "-" + infoLogFileLines[++line];
         *
         *      infoScore.Input2QplReceptorCluster = infoLogFileLines[++line] + "-" + infoLogFileLines[++line];
         *      infoScore.Input2QplLigandCluster = infoLogFileLines[++line] + "-" + infoLogFileLines[++line];
         *
         *      infoScore.Input1QprReceptorPdbId = infoLogFileLines[++line] + "-" + infoLogFileLines[++line];
         *      infoScore.Input1QprLigandPdbId = infoLogFileLines[++line] + "-" + infoLogFileLines[++line];
         *
         *      infoScore.Input2QplReceptorPdbId = infoLogFileLines[++line] + "-" + infoLogFileLines[++line];
         *      infoScore.Input2QplLigandPdbId = infoLogFileLines[++line] + "-" + infoLogFileLines[++line];
         *
         *      infoScore.SubstitutionDescription = infoLogFileLines[++line].Replace("_", " ").Replace("Reversed", "(Reversed)");
         *
         *      infoScore.Input1QprLigandInterface = infoLogFileLines[++line];
         *
         ++line;
         *
         *      infoScore.Input2QplLigandInterface = infoLogFileLines[++line];
         *
         *
         *
         *      //var monomerStructFiles = new List<string> { "model_monomer.pdb", "model_locked_monomer.pdb", "model_fragment_monomer.pdb" };
         *      //var dimerStructFiles = new List<string>   {"model_dimer.pdb", "model_locked_dimer.pdb", "model_fragment_dimer.pdb"};
         *
         *      //crystal structure
         *      //if (infoScore.Input2QplLigandCluster == infoScore.Input1QprLigandCluster && infoScore.SubstitutionDescription.Replace("_", " ").ToUpperInvariant() == "Query Interface".ToUpperInvariant()) { structFiles.Add("template_ligand_all.pdb"); }
         *
         *      foreach (var p in pdbFileNames)
         *      {
         *          var modellerMonomerLogResult = ParseModellerLog(modellerMonomerLogFileLines, infoScore, new List<string>() { p });
         *          //var modellerDimerLogResult = ParseModellerLog(modellerDimerLogFileLines, infoScore, new List<string>() {p});
         *          var pisaMonomerLogResult = ParsePisaLog(pisaMonomerLogFileLines, infoScore, new List<string>() { p });
         *          //var pisaDimerLogResult = ParsePisaLog(pisaDimerLogFileLines, infoScore, dimerStructFiles);
         *          //var pdbtoolsLogResult = ParsePdbtoolsLog(pdbtoolsLogFileLines, infoScore, structFiles);
         *
         *
         *
         *          //var monomerStructFile = monomerStructFiles[index];
         *          //var dimerStructFile = dimerStructFiles[index];
         *
         *                var score = new EnergyScore();
         *
         *              var modellerMonomerScore = modellerMonomerLogResult.FirstOrDefault(a => a.StructureFilename == p);
         *              //var modellerDimerScoreA = modellerDimerLogResult.FirstOrDefault(a => a.StructureFilename == dimerStructFile);
         *              //var modellerDimerScoreB = modellerDimerLogResult.Skip(1).FirstOrDefault(a => a.StructureFilename == dimerStructFile);
         *
         *              var pisaMonomerScore = pisaMonomerLogResult.FirstOrDefault(a => a.StructureFilename == p);
         *              //var pisaDimerScoreA = pisaDimerLogResult.FirstOrDefault(a => a.StructureFilename == dimerStructFile);
         *              //var pisaDimerScoreB = pisaDimerLogResult.Skip(1).FirstOrDefault(a => a.StructureFilename == dimerStructFile);
         *
         *              //var pdbtoolsScore = pdbtoolsLogResult.FirstOrDefault(a => a.StructureFilename == structFile);
         *
         *              //score.ResultGroupNumber = infoScore.ResultGroupNumber;
         *              score.StructureFilename = p;
         *              score.StructureFolder = infoScore.StructureFolder;
         *              score.StructuralTruncation = infoScore.StructuralTruncation;
         *
         *              score.Input1QprReceptorCluster = infoScore.Input1QprReceptorCluster;
         *              score.Input1QprLigandCluster = infoScore.Input1QprLigandCluster;
         *              score.Input2QplReceptorCluster = infoScore.Input2QplReceptorCluster;
         *              score.Input2QplLigandCluster = infoScore.Input2QplLigandCluster;
         *              score.Input1QprReceptorPdbId = infoScore.Input1QprReceptorPdbId;
         *              score.Input1QprLigandPdbId = infoScore.Input1QprLigandPdbId;
         *              score.Input2QplReceptorPdbId = infoScore.Input2QplReceptorPdbId;
         *              score.Input2QplLigandPdbId = infoScore.Input2QplLigandPdbId;
         *              score.SubstitutionDescription = infoScore.SubstitutionDescription;
         *              score.Input1QprLigandInterface = infoScore.Input1QprLigandInterface;
         *              score.Input2QplLigandInterface = infoScore.Input2QplLigandInterface;
         *
         *              if (modellerMonomerScore != null)
         *              {
         *                  score.ModellerModelChainName = modellerMonomerScore.ModellerModelChainName;
         *
         *                  score.ModellerGa341 = modellerMonomerScore.ModellerGa341;
         *                  score.ModellerGa341Comptactness = modellerMonomerScore.ModellerGa341Comptactness;
         *                  score.ModellerGa341NativeEnergyCombined = modellerMonomerScore.ModellerGa341NativeEnergyCombined;
         *                  score.ModellerGa341NativeEnergyPair = modellerMonomerScore.ModellerGa341NativeEnergyPair;
         *                  score.ModellerGa341NativeEnergySurface = modellerMonomerScore.ModellerGa341NativeEnergySurface;
         *                  score.ModellerGa341ZScoreCombined = modellerMonomerScore.ModellerGa341ZScoreCombined;
         *                  score.ModellerGa341ZScorePair = modellerMonomerScore.ModellerGa341ZScorePair;
         *                  score.ModellerGa341ZScoreSurface = modellerMonomerScore.ModellerGa341ZScoreSurface;
         *
         *                  score.ModellerMolPdf = modellerMonomerScore.ModellerMolPdf;
         *                  score.ModellerDope = modellerMonomerScore.ModellerDope;
         *                  score.ModellerDopeHr = modellerMonomerScore.ModellerDopeHr;
         *                  score.ModellerDopeNormalized = modellerMonomerScore.ModellerDopeNormalized;
         *                  score.ModellerSoap = modellerMonomerScore.ModellerSoap;
         *              }
         *
         *              if (pisaMonomerScore != null)
         *              {
         *                  score.PisaMonomerSerial1 = pisaMonomerScore.PisaMonomerSerial1;
         *                  score.PisaMonomerId1 = pisaMonomerScore.PisaMonomerId1;
         *                  score.PisaMonomerName1 = pisaMonomerScore.PisaMonomerName1;
         *                  score.PisaMonomerClass1 = pisaMonomerScore.PisaMonomerClass1;
         *                  score.PisaMonomerTotalAtoms1 = pisaMonomerScore.PisaMonomerTotalAtoms1;
         *                  score.PisaMonomerTotalResidues1 = pisaMonomerScore.PisaMonomerTotalResidues1;
         *                  score.PisaMonomerSurfaceAtoms1 = pisaMonomerScore.PisaMonomerSurfaceAtoms1;
         *                  score.PisaMonomerSurfaceResidues1 = pisaMonomerScore.PisaMonomerSurfaceResidues1;
         *                  score.PisaMonomerArea1 = pisaMonomerScore.PisaMonomerArea1;
         *                  score.PisaMonomerDeltaG1 = pisaMonomerScore.PisaMonomerDeltaG1;
         *              }
         *
         *
         *              //if (pdbtoolsScore != null)
         *              //{
         *              //    score.PdbToolsCoulombEp1 = pdbtoolsScore.PdbToolsCoulombEp1;
         *              //    score.PdbToolsCoulombIonStr1 = pdbtoolsScore.PdbToolsCoulombIonStr1;
         *              //    score.PdbToolsCoulombPh1 = pdbtoolsScore.PdbToolsCoulombPh1;
         *              //    score.PdbToolsCoulombT1 = pdbtoolsScore.PdbToolsCoulombT1;
         *              //    score.PdbToolsCoulombDeltaG1 = pdbtoolsScore.PdbToolsCoulombDeltaG1;
         *              //}
         *
         *              if (score.StructureFilename == "template_ligand_all.pdb" && score.SubstitutionDescription.Replace("_", " ").ToUpperInvariant() == "Query Interface".ToUpperInvariant()) { score.SubstitutionDescription = "Native (No change)"; }
         *              else if (score.Input2QplLigandCluster == score.Input1QprLigandCluster && score.SubstitutionDescription.Replace("_", " ").ToUpperInvariant() == "Query Interface".ToUpperInvariant()) { score.SubstitutionDescription = "Native Theoretical Model"; }
         *              else if (score.Input2QplLigandCluster == score.Input1QprLigandCluster && score.SubstitutionDescription.Replace("_", " ").ToUpperInvariant() == "Query Interface (Reversed)".ToUpperInvariant()) { score.SubstitutionDescription = "Native Theoretical Model (Reversed)"; }
         *
         *              scores.Add(score);
         *          //}
         *      }
         *      var subDesc = new List<string>
         *      {
         *      "Native (No change)",
         *      "Native Theoretical Model",
         *      "Query Interface",
         *      "Similar Physiochemical",
         *      "Similar Propensity",
         *      "Similar Blosum62",
         *      "Dissimilar Physiochemical",
         *      "Dissimilar Propensity",
         *      "Dissimilar Blosum62",
         *      };
         *
         *      subDesc.AddRange(subDesc.Select(s => s + " (Reversed)").ToList());
         *      subDesc = subDesc.Select(a => a.Replace("_", " ").ToUpperInvariant()).ToList();
         *
         *      var scoresDistinct = scores.Select(a => new
         *      {
         *          Input1QPR_ReceptorCluster = a.Input1QprReceptorCluster,
         *          Input1QPR_LigandCluster = a.Input1QprLigandCluster,
         *          Input2QPL_ReceptorCluster = a.Input2QplReceptorCluster,
         *      }).Distinct().ToList();
         *
         *      scores =
         *                          scores.OrderBy(a => a.StructuralTruncation.Trim())
         *                              .ThenBy(a => a.StructureFolder.Substring(0, a.StructureFolder.LastIndexOfAny(new char[] { '/', '\\' })).Trim())
         *
         *                          .ThenBy(a => subDesc.IndexOf(a.SubstitutionDescription.Replace("_", " ").ToUpperInvariant()))
         *                          .ToList();
         *      var scoresGrouped = scores.GroupBy(a => new Tuple<string,bool>(a.StructureFilename,a.SubstitutionDescription.Contains("(Reversed)")));
         *      foreach (var scoreGrouped in scoresGrouped)
         *      {
         *
         *          var output = scoreGrouped.ToList().SelectMany(a => a.SubstitutionDescription == "Native (No change)" ? new[] {"", a.ToString()} : new[] {a.ToString()}).ToList();
         *          output.Insert(0, EnergyScore.Header());
         *          File.WriteAllLines(logResultsFolder + "energy_" + scoreGrouped.Key.Item1 + (scoreGrouped.Key.Item2?" reversed":"") +  ".csv", output);
         *      }
         *
         *
         *  }
         */
        //}

        //public static List<EnergyScore> ParsePdbtoolsLog(string[] pdbtoolsLogFileLines, EnergyScore paramEnergyScore, List<string> structFiles)
        //{
        //    var monomerMarker = "                                     pdb        ep   ion_str        pH         T        dG";

        //    var result = new List<EnergyScore>();
        //    var score = new EnergyScore();

        //    for (int index = 0; index < pdbtoolsLogFileLines.Length; index++)
        //    {
        //        var line = pdbtoolsLogFileLines[index];
        //        var lineSplit = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

        //        if (line.StartsWith("; pdb_coulomb.py")) score.StructureFilename = lineSplit[2];

        //        if (line == monomerMarker)
        //        {
        //            var line2 = pdbtoolsLogFileLines[index + 1];
        //            var lineSplit2 = line2.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Where(a => a != "|").ToList();

        //            if (structFiles.Contains(score.StructureFilename))
        //            {
        //                score.PdbToolsCoulombEp1 = lineSplit2[2];
        //                score.PdbToolsCoulombIonStr1 = lineSplit2[3];
        //                score.PdbToolsCoulombPh1 = lineSplit2[4];
        //                score.PdbToolsCoulombT1 = lineSplit2[5];
        //                score.PdbToolsCoulombDeltaG1 = lineSplit2[6];

        //                result.Add(score);
        //                score = new EnergyScore();
        //            }
        //        }

        //    }

        //    return result;
        //}

        public static List <EnergyScore> ParsePisaLog(string[] pisaLogFileLines, /*EnergyScore paramEnergyScore,*/ List <string> structFiles = null)
        {
            var monomerMarker = "  ## Id |   Monomer   |  Class    Nat Nres   Sat Sres     Area   DeltaG";
            //var interfaceMarker = "  ## Id |   Monomer1  |   Monomer2    Symmetry operation Sym.Id |   Area  DeltaG Nhb Nsb Nds";


            var result = new List <EnergyScore>();
            var score  = new EnergyScore();

            for (int index = 0; index < pisaLogFileLines.Length; index++)
            {
                var line      = pisaLogFileLines[index];
                var lineSplit = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();

                if (line.StartsWith("; pisa"))
                {
                    score.StructureFilename = lineSplit[2];
                }

                if (line == monomerMarker)
                {
                    var line2      = pisaLogFileLines[index + 2];
                    var lineSplit2 = line2.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Where(a => a != "|").ToList();

                    if (structFiles == null || structFiles.Count == 0 || structFiles.Contains(score.StructureFilename))
                    {
                        score.PisaMonomerSerial1          = lineSplit2[0];
                        score.PisaMonomerId1              = lineSplit2[1];
                        score.PisaMonomerName1            = lineSplit2[2];
                        score.PisaMonomerClass1           = lineSplit2[3];
                        score.PisaMonomerTotalAtoms1      = lineSplit2[4];
                        score.PisaMonomerTotalResidues1   = lineSplit2[5];
                        score.PisaMonomerSurfaceAtoms1    = lineSplit2[6];
                        score.PisaMonomerSurfaceResidues1 = lineSplit2[7];
                        score.PisaMonomerArea1            = lineSplit2[8];
                        score.PisaMonomerDeltaG1          = lineSplit2[9];


                        result.Add(score);
                        score = new EnergyScore();
                    }
                }
            }

            return(result);
        }
        public static List <EnergyScore> ParseModellerLog(string modellerLogFilename, /*EnergyScore paramEnergyScore,*/ List <string> structFiles = null)
        {
            var folder = Path.GetDirectoryName(modellerLogFilename);
            var file   = Path.GetFileName(modellerLogFilename);

            var modellerLogFileLines = File.ReadAllLines(modellerLogFilename);

            var modellerLogFileMarkers = new string[] { "; ENERGY ", "; FILE ", "; CHAIN ", "; FINISHED " };

            modellerLogFileLines = modellerLogFileLines.Where(a => modellerLogFileMarkers.Any(a.StartsWith)).ToArray();

            var result = new List <EnergyScore>();
            var score  = new EnergyScore();

            score.StructureFolder         = folder;
            score.StructureFilename       = file;
            score.SubstitutionDescription = "";
            score.StructuralTruncation    = "";

            foreach (var line in modellerLogFileLines)
            {
                var lineSplit = line.Split(' ').ToList();
                lineSplit.RemoveAt(0);

                if (lineSplit[0] == "FILE")
                {
                    score.StructureFilename = lineSplit[1];
                    continue;
                }

                if (lineSplit[0] == "CHAIN")
                {
                    //if (structFiles==null|| structFiles.Count == 0 || structFiles.Contains(score.StructureFilename))
                    {
                        score.ModellerModelChainName = lineSplit[1];
                    }
                    continue;
                }

                if (lineSplit[0] == "ENERGY")
                {
                    //if (structFiles==null|| structFiles.Count == 0 || structFiles.Contains(score.StructureFilename))
                    {
                        if (lineSplit[1] == "assess_ga341")
                        {
                            var ga341Index = -1;
                            var ga341      = line.Substring("; ENERGY assess_ga341 ".Length).Replace("[", "").Replace("]", "").Replace(" ", "").Split(',');
                            score.ModellerGa341                     = ga341[++ga341Index];
                            score.ModellerGa341Comptactness         = ga341[++ga341Index];
                            score.ModellerGa341NativeEnergyPair     = ga341[++ga341Index];
                            score.ModellerGa341NativeEnergySurface  = ga341[++ga341Index];
                            score.ModellerGa341NativeEnergyCombined = ga341[++ga341Index];
                            score.ModellerGa341ZScoreSurface        = ga341[++ga341Index];
                            score.ModellerGa341ZScorePair           = ga341[++ga341Index];
                            score.ModellerGa341ZScoreCombined       = ga341[++ga341Index];
                        }
                        if (lineSplit[1] == "molpdf")
                        {
                            score.ModellerMolPdf = lineSplit[2];
                        }
                        if (lineSplit[1] == "assess_dope")
                        {
                            score.ModellerDope = string.IsNullOrWhiteSpace(lineSplit[2]) ? "" : string.Format("{0:0.00}", Math.Round(decimal.Parse(lineSplit[2]), 2));
                        }
                        if (lineSplit[1] == "assess_dopehr")
                        {
                            score.ModellerDopeHr = lineSplit[2];
                        }
                        if (lineSplit[1] == "assess_normalized_dope")
                        {
                            score.ModellerDopeNormalized = lineSplit[2];
                        }
                        if (lineSplit[1] == "assess_soap_protein_od")
                        {
                            score.ModellerSoap = lineSplit[2];
                        }
                    }
                    continue;
                }

                if (lineSplit[0] == "FINISHED")
                {
                    var lastScore = score;
                    //if (structFiles.Contains(score.StructureFilename))
                    //{
                    result.Add(lastScore);
                    //}

                    score = new EnergyScore();
                    score.StructureFolder         = lastScore.StructureFolder;
                    score.StructureFilename       = lastScore.StructureFilename;
                    score.SubstitutionDescription = lastScore.SubstitutionDescription;
                    score.StructuralTruncation    = lastScore.StructuralTruncation;
                }
            }
            return(result);
        }