//obtain a random false list for ROC generation, using the input file (comptable file) as base.
        public List<CompositionHypothesisEntry> genFalse(String path, List<CompositionHypothesisEntry> trueComhypo, OpenFileDialog oFDPPMSD)
        {
            //table is used to store the data before the calculation
            GlycanHypothesisCombinatorialGenerator DATA = new GlycanHypothesisCombinatorialGenerator();
            List<GlycanCompositionTable> GD = new List<GlycanCompositionTable>();
            //This function is used to read the cpos file and translate it to generatorData format. Converting all letters in bounds to numbers while its at it.
            DATA = extractFile(path);

            //The Final Result will have approximately as many lines as the user input composition hypothesis.
            int usingNumberofFiles = 20;
            List<CompositionHypothesisEntry> FinalAns = new List<CompositionHypothesisEntry>();
            for (int i = 0; i < usingNumberofFiles; i++)
            {
                List<CompositionHypothesisEntry> FalseSet = obtainFalse(DATA, trueComhypo.Count() / usingNumberofFiles, oFDPPMSD);
                FinalAns.AddRange(FalseSet);
            }
            FinalAns.AddRange(trueComhypo);
            return FinalAns;
        }
        public List<CompositionHypothesisEntry> GenerateHypothesis(GlycanHypothesisCombinatorialGenerator GD)
        {
            //If there are letters in the lower bounds and upper bounds section, add those rules into the additional table in the GD variable.
            GD = obtainNewGD(GD);

            //Convert all letters in Bounds to numbers, so that we can calcuate them
            List<GlycanCompositionTable> Table = convertLetters(GD);

            //Now, all bounds in Table only consists of numbers, but they're still not calculated. (e.g. 2+3+4) So, calculate them.
            List<GlycanCompositionTable> CoTa0 = calnumbers(Table);
            //Now, in those bounds, replace them with numbers from all ranges. (ex. if a bound has numbers (2,6,8), replace it with (2,3,4,5,6,7,8) for computations). Afterall, they are bounds.
            CoTa0 = expendBound(CoTa0);
            //Now that all of the bounds are numbers, we can create the composition hypothesis with them, by combining their combinations.
            List<CompositionHypothesisEntry> Ans = calComHypo(CoTa0);
            //Then limit them with the rules from the additional rules table.
            Ans = checkAddRules(Ans, GD);
            //Check if there is any unwanted rows, which have negative values.
            Ans = checkNegative(Ans);
            //Add the adducts into each row data.
            Ans = addAdducts(Ans, GD);
            //Final Check, if any of the values are negative (ex. a negative amount of S or C), remove that row.
            Ans = checkNegative(Ans);
            //Lastly transfer data from eqCount to molnames and eqCounts, to decrease number of columns needed
            Ans = cleanColumns(Ans, GD);
            //Really, this is the last step. Lastly, remove columns of all zero element counts.
            Ans = removeZeroElements(Ans);

            //If "Is is a Glycan?" box is checked, add one water to add compounds automatically.
            if (checkBox1.Checked == true)
                Ans = addWater(Ans);

            return Ans;
        }
 public List<GlycanCompositionTable> convertLetters(GlycanHypothesisCombinatorialGenerator tGD)
 {
     GlycanHypothesisCombinatorialGenerator GD = new GlycanHypothesisCombinatorialGenerator();
     GD = tGD;
     List<GlycanCompositionTable> Table = new List<GlycanCompositionTable>();
     Table.AddRange(GD.comTable);
     Boolean MoreLetters = true;
     //Use the cleanbound function to clean up all letters in the bounds.
     while (MoreLetters)
     {
         MoreLetters = false;
         for (int i = 0; i < Table.Count; i++)
         {
             Table[i].Bound = cleanBounds(Table[i].Bound, tGD);
         }
         for (int i = 0; i < Table.Count; i++)
         {
             foreach (String bound in Table[i].Bound)
             {
                 foreach (char j in bound)
                 {
                     if (char.IsUpper(j))
                     {
                         MoreLetters = true;
                     }
                 }
             }
         }
     }
     return Table;
 }
        //This class calculates delta adduct mass.
        public Double CalculateAdductMass(GlycanHypothesisCombinatorialGenerator GD)
        {
            String adduct = GD.Modification[0];
            String replacement = GD.Modification[1];
            //Regex for the capital letters
            string regexpattern = @"[A-Z]{1}[a-z]?[a-z]?\d?";
            MatchCollection adducts = Regex.Matches(adduct, regexpattern);
            MatchCollection replacements = Regex.Matches(replacement, regexpattern);
            //Regex for the element;
            string elementregexpattern = @"[A-Z]{1}[a-z]?[a-z]?(\(([^)]*)\))?";
            //Regex for the number of the element.
            string numberregexpattern = @"\d+";
            Double adductmass = 0;
            Double replacementmass = 0;
            PeriodicTable pTable = new PeriodicTable();
            //For each element in adducts, add up their masses.
            foreach (Match add in adducts)
            {
                String ad = Convert.ToString(add);
                String element = Convert.ToString(Regex.Match(ad, elementregexpattern));
                String snumber = Convert.ToString(Regex.Match(ad, numberregexpattern));
                Int32 number = 0;
                if (snumber == String.Empty)
                {
                    number = 1;
                }
                else
                {
                    number = Convert.ToInt32(snumber);
                }
                adductmass = adductmass + number * pTable.getMass(element);
            }
            //For each element in replacements, add up their masses.
            foreach (Match el in replacements)
            {
                String element = Convert.ToString(Regex.Match(Convert.ToString(el), elementregexpattern));
                String snumber = Convert.ToString(Regex.Match(Convert.ToString(el), numberregexpattern));
                Int32 number = 0;
                if (snumber == String.Empty)
                {
                    number = 1;
                }
                else
                {
                    number = Convert.ToInt32(snumber);
                }
                replacementmass = replacementmass + number * pTable.getMass(element);
            }

            //Finally, subtract them and obtain delta mass.
            Double dMass = adductmass - replacementmass;
            return dMass;
        }
        //genHypo runs these following functions one by one to do its task://///////////////////////////////////////////////////////
        private GlycanHypothesisCombinatorialGenerator obtainNewGD(GlycanHypothesisCombinatorialGenerator GD)
        {
            List<GlycanCompositionTable> Table = new List<GlycanCompositionTable>();
            Table.AddRange(GD.comTable);
            Boolean hasLetter = false;
            for (int i = 0; i < Table.Count(); i++)
            {
                String bound = Table[i].Bound[0];
                foreach (char j in bound)
                {
                    if (char.IsUpper(j))
                    {
                        hasLetter = true;
                    }
                }
                if (hasLetter == true)
                {
                    hasLetter = false;
                    Boundary AT = new Boundary();
                    AT.Constraint = Table[i].Letter;
                    AT.Relationship = "≤";
                    AT.Formula = bound;
                    GD.aTable.Add(AT);
                }
                String bound2 = Table[i].Bound[1];
                foreach (char j in bound2)
                {
                    if (char.IsUpper(j))
                    {
                        hasLetter = true;
                    }
                }
                if (hasLetter == true)
                {
                    hasLetter = false;
                    Boundary AT = new Boundary();
                    AT.Constraint = Table[i].Letter;
                    AT.Relationship = "≥";
                    AT.Formula = bound2;
                    GD.aTable.Add(AT);
                }

            }
            return GD;
        }
        //This class outputs the elemental composition change from the adduct and replacement.
        private AdductComposition getAdductCompo(GlycanHypothesisCombinatorialGenerator GD)
        {
            String adduct = GD.Modification[0];
            String replacement = GD.Modification[1];
            //Regex for the capital letters
            string regexpattern = @"([A-Z]{1}[a-z]?[a-z]?){1}(\({1}\d+\){1})?\d?";
            MatchCollection adducts = Regex.Matches(adduct, regexpattern);
            MatchCollection replacements = Regex.Matches(replacement, regexpattern);
            //Regex for the element;
            string elementregexpattern = @"([A-Z]{1}[a-z]?[a-z]?){1}(\({1}\d+\){1})?";
            //Regex for the number of the element.
            string numberregexpattern = @"\d+$";

            AdductComposition adc = new AdductComposition();

            //For each element in adducts.
            foreach (Match add in adducts)
            {
                String ad = Convert.ToString(add);
                String element = Convert.ToString(Regex.Match(ad, elementregexpattern));
                String snumber = Convert.ToString(Regex.Match(ad, numberregexpattern));
                Int32 number = 0;
                if (snumber == String.Empty)
                {
                    number = 1;
                }
                else
                {
                    number = Convert.ToInt32(snumber);
                }
                try
                {
                    adc.elementAmount[adc.elementIDs.IndexOf(element)] = adc.elementAmount[adc.elementIDs.IndexOf(element)] + number;
                }
                catch
                {
                    adc.elementIDs.Add(element);
                    adc.elementAmount.Add(number);
                }

            }
            //For each element in replacements.
            foreach (Match ele in replacements)
            {
                String el = Convert.ToString(ele);
                String element = Convert.ToString(Regex.Match(el, elementregexpattern));
                String snumber = Convert.ToString(Regex.Match(el, numberregexpattern));
                Int32 number = 0;
                if (snumber == String.Empty)
                {
                    number = 1;
                }
                else
                {
                    number = Convert.ToInt32(snumber);
                }

                try
                {
                    adc.elementAmount[adc.elementIDs.IndexOf(element)] = adc.elementAmount[adc.elementIDs.IndexOf(element)] - number;
                }
                catch
                {
                    adc.elementIDs.Add(element);
                    adc.elementAmount.Add(number);
                }
            }
            //Finally, subtract them and obtain the answer.

            return adc;
        }
        private void GeneratePrecomputedHypothesisButton_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Button");
            string database = null;
            if (this.UseAllHumanGlycomeDBRadio.Checked)
            {
                Console.WriteLine(this.UseAllHumanGlycomeDBRadio.Text);
                database = Properties.Resources.Human_GlycomeDB_All;
            }
            else if (this.UseNLinkedHumanGlycomeDBRadio.Checked)
            {
                Console.WriteLine(this.UseNLinkedHumanGlycomeDBRadio.Text);
                database = Properties.Resources.Human_GlycomeDB_NLinked;
            }
            else if (this.UseOLinkedHumanGlycomeDBRadio.Checked)
            {
                Console.WriteLine(this.UseOLinkedHumanGlycomeDBRadio.Text);
                database = Properties.Resources.Human_GlycomeDB_OLinked;
            }
            else if (this.UseAllMammalianGlycomeDBRadio.Checked)
            {
                Console.WriteLine(this.UseAllMammalianGlycomeDBRadio.Text);
                database = Properties.Resources.Mammalian_GlycomeDB_All;
            }
            else if (this.UseNLinkedMammalianGlycomeDBRadio.Checked)
            {
                Console.WriteLine(this.UseNLinkedMammalianGlycomeDBRadio.Text);
                database = Properties.Resources.Mammalian_GlycomeDB_NLinked;
            }
            else if (this.UseOLinkedMammalianGlycomeDBRadio.Checked)
            {
                Console.WriteLine(this.UseOLinkedMammalianGlycomeDBRadio.Text);
                database = Properties.Resources.Mammalian_GlycomeDB_OLinked;
            }
            else
            {
                MessageBox.Show("You must have selected a precomputed Database from the radio option list above.", "Select a Database");
                return;
            }
            //foreach (string db in new String[] {
            //    Properties.Resources.Human_GlycomeDB_All,
            //    Properties.Resources.Human_GlycomeDB_NLinked,
            //    Properties.Resources.Human_GlycomeDB_OLinked,
            //    Properties.Resources.Mammalian_GlycomeDB_All,
            //    Properties.Resources.Mammalian_GlycomeDB_OLinked,
            //    Properties.Resources.Mammalian_GlycomeDB_NLinked })
            //{
            //    Console.WriteLine(db.Length);
            //}
            Console.WriteLine(database.Length);
            List<CompositionHypothesisEntry> compHypothesis = getCompHypoFromStream(database.ToStream());
            BackgroundWorker backgroundHypothesisFromDBWorker = new BackgroundWorker();
            backgroundHypothesisFromDBWorker.DoWork += backgroundHypothesisFromDBWorker_DoWork;
            backgroundHypothesisFromDBWorker.RunWorkerCompleted += backgroundHypothesisFromDBWorker_RunWorkerCompleted;

            //foreach (comphypo c in compHypothesis)
            //{
            //    Console.WriteLine(c);
            //}
            //Console.WriteLine(compHypothesis.Count());

            ///Check if the UI indicates there should be adducts. If so, apply
            ///the adduct Modification transformation over the range given by the bounds.
            ///Otherwise generate the hypothesis from the resource stream unmodified.
            bool hasAdduct = true;
            GlycanHypothesisCombinatorialGenerator GD = new GlycanHypothesisCombinatorialGenerator();
            GD.Modification = new string[] { "", "0" };
            String adductModFormula = this.textBox35.Text;
            Double adductMassDelta = Convert.ToDouble(this.textBox44.Text);
            String adductLowerBoundStr = this.textBox46.Text;
            String adductUpperBoundStr = this.textBox45.Text;
            int adductLowerBoundVal = 0;
            int adductUpperBoundVal = 0;
            //Check to see if there are actually adducts to handle
            try
            {
                bool hasAdductFormula = !((adductModFormula == null) || (adductModFormula == ""));
                bool hasMassDelta = !((adductMassDelta == null) || (adductMassDelta == 0.0));
                if (hasAdduct && hasMassDelta)
                {
                    adductLowerBoundVal = Convert.ToInt32(adductLowerBoundStr);
                    adductUpperBoundVal = Convert.ToInt32(adductUpperBoundStr);
                    if (adductUpperBoundVal == 0) throw new Exception("Adduct Upper Bound Can't Be 0");
                }
                hasAdduct = hasAdduct && hasMassDelta;

            }
            catch
            {
                Console.WriteLine("No Adducts");
                hasAdduct = false;
            }
            //Package up the context and ship it to the background worker thread
            backgroundHypothesisFromDBWorker.RunWorkerAsync(
                new BackgroundHypothesisFromDBArgument{
                    Hypothesis = compHypothesis,
                    HasAdduct = hasAdduct,
                    GD = GD,
                    AdductModFormula = adductModFormula,
                    AdductMassDelta = adductMassDelta,
                    AdductLowerBound = adductLowerBoundVal,
                    AdductUpperBound = adductUpperBoundVal

            });
        }
        private List<CompositionHypothesisEntry> obtainFalse(GlycanHypothesisCombinatorialGenerator GD, int numofLines, OpenFileDialog oFDPPMSD)
        {
            //obtain a random list with the correct bounds but the elemental composition randomized:
            List<GlycanCompositionTable> randomCT = randomList(GD.comTable);
            CompositionHypothesisTabbedForm comp = new CompositionHypothesisTabbedForm();
            GD.comTable = randomCT;
            List<CompositionHypothesisEntry> CTAns = comp.GenerateHypothesis(GD);
            List<int> rangeone = Enumerable.Range(0, CTAns.Count()).ToList();
            rangeone.Shuffle();
            //restricting them to numperlist per list, which is half of the number of lines of the original composition hypothesis divided by numofFile            Int32 numperlist = (numofLines / 2) / numofFiles;
            List<CompositionHypothesisEntry> finalAns = new List<CompositionHypothesisEntry>();
            for (int j = 0; j < numofLines; j++)
            {
                finalAns.Add(CTAns[rangeone[j]]);
            }
            Int32 Length = finalAns.Count();
            //Next, mix it with Protein Prospector MS-digest file, if it exists.
            Stream mystream = null;
            try
            {
                if ((mystream = oFDPPMSD.OpenFile()) != null)
                {
                    if (!String.IsNullOrEmpty(oFDPPMSD.FileName))
                    {
                        List<CompositionHypothesisEntry> FinalAns = getPPhypo(finalAns, finalAns, genFalsePPMSD(oFDPPMSD.FileName));
                        List<int> rangethree = Enumerable.Range(0, FinalAns.Count).ToList();
                        rangethree.Shuffle();
                        finalAns.Clear();
                        for (int i = 0; i < Length; i++)
                        {
                            finalAns.Add(FinalAns[rangethree[i]]);
                        }
                    }
                }
            }
            catch
            {
            }
            for (int i = 0; i < finalAns.Count(); i++)
            {
                finalAns[i].IsDecoy = false;
            }

            return finalAns;
        }
        private List<CompositionHypothesisEntry> cleanColumns(List<CompositionHypothesisEntry> Ans, GlycanHypothesisCombinatorialGenerator GD)
        {
            List<string> molnames = new List<string>();
            List<int> index = new List<int>();
            if (Ans.FindIndex(item => item.eqCount["A"] > 0) >= 0)
                index.Add(0);
            if (Ans.FindIndex(item => item.eqCount["B"] > 0) >= 0)
                index.Add(1);
            if (Ans.FindIndex(item => item.eqCount["C"] > 0) >= 0)
                index.Add(2);
            if (Ans.FindIndex(item => item.eqCount["D"] > 0) >= 0)
                index.Add(3);
            if (Ans.FindIndex(item => item.eqCount["E"] > 0) >= 0)
                index.Add(4);
            if (Ans.FindIndex(item => item.eqCount["F"] > 0) >= 0)
                index.Add(5);
            if (Ans.FindIndex(item => item.eqCount["G"] > 0) >= 0)
                index.Add(6);
            if (Ans.FindIndex(item => item.eqCount["H"] > 0) >= 0)
                index.Add(7);
            if (Ans.FindIndex(item => item.eqCount["I"] > 0) >= 0)
                index.Add(8);
            if (Ans.FindIndex(item => item.eqCount["J"] > 0) >= 0)
                index.Add(9);
            if (Ans.FindIndex(item => item.eqCount["K"] > 0) >= 0)
                index.Add(10);
            if (Ans.FindIndex(item => item.eqCount["L"] > 0) >= 0)
                index.Add(11);
            if (Ans.FindIndex(item => item.eqCount["M"] > 0) >= 0)
                index.Add(12);
            if (Ans.FindIndex(item => item.eqCount["N"] > 0) >= 0)
                index.Add(13);
            if (Ans.FindIndex(item => item.eqCount["O"] > 0) >= 0)
                index.Add(14);
            if (Ans.FindIndex(item => item.eqCount["P"] > 0) >= 0)
                index.Add(15);
            if (Ans.FindIndex(item => item.eqCount["Q"] > 0) >= 0)
                index.Add(16);
            Dictionary<Int32, String> toLetter = new Dictionary<Int32, String>();
            toLetter.Add(0, "A");
            toLetter.Add(1, "B");
            toLetter.Add(2, "C");
            toLetter.Add(3, "D");
            toLetter.Add(4, "E");
            toLetter.Add(5, "F");
            toLetter.Add(6, "G");
            toLetter.Add(7, "H");
            toLetter.Add(8, "I");
            toLetter.Add(9, "J");
            toLetter.Add(10, "K");
            toLetter.Add(11, "L");
            toLetter.Add(12, "M");
            toLetter.Add(13, "N");
            toLetter.Add(14, "O");
            toLetter.Add(15, "P");
            toLetter.Add(16, "Q");

            for (int i = 0; i < index.Count(); i++)
            {
                molnames.Add(GD.comTable[index[i]].Molecule);
            }
            for (int i = 0; i < Ans.Count(); i++)
            {
                List<int> eqCountstemp = new List<int>();
                for (int j = 0; j < index.Count(); j++)
                {
                    int value = new int();
                    if (Ans[i].eqCount.TryGetValue(toLetter[index[j]], out value))
                    {
                        eqCountstemp.Add(Convert.ToInt32(value));
                    }
                    else
                        eqCountstemp.Add(0);

                }
                Ans[i].eqCounts = eqCountstemp;
            }
            for (int i = 0; i < Ans.Count(); i++)
            {
                if (Ans[i].ElementNames.Count() > 0)
                {
                    Ans[i].MoleculeNames = molnames;
                    break;
                }
            }
            return Ans;
        }
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //This function is used by ConvertLetters to clean the letters in the lower and upper bound areas. It only clean it once, so if you want to clear the area of all letters, put this into a loop.
 private List<String> cleanBounds(List<String> Bounds, GlycanHypothesisCombinatorialGenerator GD)
 {
     List<String> FinalLS = new List<String>();
     List<String> Ans = new List<String>();
     foreach (String bound in Bounds)
     {
         foreach (char i in bound)
         {
             if (char.IsUpper(i))
             {
                 if (FinalLS.Count == 0)
                 {
                     foreach (String bou in getBound(i, GD.comTable))
                     {
                         FinalLS.Add("(" + bou + ")");
                     }
                 }
                 else
                 {
                     List<String> someLS = new List<String>();
                     foreach (String bou in getBound(i, GD.comTable))
                     {
                         for (int j = 0; j < FinalLS.Count; j++)
                         {
                             someLS.Add(FinalLS[j] + "(" + bou + ")");
                         }
                     }
                     FinalLS.Clear();
                     FinalLS = someLS;
                 }
             }
             else
             {
                 if (FinalLS.Count == 0)
                 {
                     FinalLS.Add(Convert.ToString(i));
                 }
                 else
                 {
                     List<String> someLS = new List<String>();
                     for (int j = 0; j < FinalLS.Count; j++)
                     {
                         someLS.Add(FinalLS[j] + i);
                     }
                     FinalLS.Clear();
                     FinalLS = someLS;
                 }
             }
         }
         Ans.AddRange(FinalLS);
         FinalLS.Clear();
     }
     return Ans;
 }
        private List<CompositionHypothesisEntry> checkAddRules(List<CompositionHypothesisEntry> Ans, GlycanHypothesisCombinatorialGenerator GD)
        {
            List<CompositionHypothesisEntry> CHy = new List<CompositionHypothesisEntry>();
            List<string> elementIDs = new List<string>();
            for (int j = 0; j < Ans.Count(); j++)
            {
                if (Ans[j].ElementNames.Count > 0)
                {
                    for (int i = 0; i < Ans[j].ElementNames.Count(); i++)
                    {
                        elementIDs.Add(Ans[j].ElementNames[i]);
                    }
                    break;
                }
            }

            for (int i = 0; i < CHy.Count(); i++)
            {
                CHy[i].ElementNames.Clear();
                CHy[i].MoleculeNames.Clear();

                if (i == CHy.Count() - 1)
                {
                    CHy[0].ElementNames = elementIDs;
                }
            }
            Boolean RowGood = true;
            try
            {
                if (GD.aTable.Count != 0)
                {
                    for (int j = 0; j < Ans.Count; j++)
                    {
                        for (int i = 0; i < GD.aTable.Count(); i++)
                        {
                            //MessageBox.Show(Convert.ToString(c));
                            String equation = translet(Ans[j], GD.aTable[i]);
                            String Relationship = GD.aTable[i].Relationship;
                            String Constraint = GD.aTable[i].Constraint;
                            Constraint = converConstraints(Ans[j],Constraint);
                            //Five relationships
                            //First one
                            if (Relationship == "=")
                            {
                                MathParser parser = new MathParser();
                                Double solution = parser.Parse(equation, false);
                                //only 3 situation exists
                                //Equals to Even
                                if (Constraint == "even")
                                {
                                    if (solution % 2 != 0)
                                    {
                                        RowGood = false;
                                    }
                                    continue;
                                }
                                //Equals to Odd
                                if (Constraint == "odd")
                                {
                                    if (solution % 2 != 1)
                                    {
                                        RowGood = false;
                                    }
                                    continue;
                                }
                                //Equals to a number
                                MathParser parser2 = new MathParser();
                                Double solution2 = parser2.Parse(Constraint, false);
                                if (solution != solution2)
                                {
                                    RowGood = false;
                                }
                                continue;
                            }
                            //Second one
                            else if (Relationship == ">")
                            {
                                MathParser parser = new MathParser();
                                Double solution = parser.Parse(equation, false);
                                //only 1 situation exists
                                //Equals to a number
                                MathParser parser2 = new MathParser();
                                Double solution2 = parser2.Parse(Constraint, false);
                                if (solution <= solution2)
                                {
                                    RowGood = false;
                                }
                                continue;
                            }
                            //Third one
                            else if (Relationship == "<")
                            {
                                MathParser parser = new MathParser();
                                Double solution = parser.Parse(equation, false);
                                //only 1 situation exists
                                //Equals to a number
                                MathParser parser2 = new MathParser();
                                Double solution2 = parser2.Parse(Constraint, false);
                                if (solution >= solution2)
                                {
                                    RowGood = false;
                                }
                                continue;
                            }
                            //Forth one
                            else if (Relationship == "≥")
                            {
                                MathParser parser = new MathParser();
                                Double solution = parser.Parse(equation, false);
                                //only 1 situation exists
                                //Equals to a number
                                MathParser parser2 = new MathParser();
                                Double solution2 = parser2.Parse(Constraint, false);
                                if (solution < solution2)
                                {
                                    RowGood = false;
                                }
                                continue;
                            }
                            //Fifth one
                            else if (Relationship == "≤")
                            {
                                MathParser parser = new MathParser();
                                Double solution = parser.Parse(equation, false);
                                //only 1 situation exists
                                //Equals to a number
                                MathParser parser2 = new MathParser();
                                Double solution2 = parser2.Parse(Constraint, false);
                                if (solution > solution2)
                                {
                                    RowGood = false;
                                }
                                continue;
                            }
                            //Last one
                            else if (Relationship == "≠")
                            {
                                MathParser parser = new MathParser();
                                Double solution = parser.Parse(equation, false);
                                //only 1 situation exists
                                //Equals to a number
                                MathParser parser2 = new MathParser();
                                Double solution2 = parser2.Parse(Constraint, false);
                                if (solution == solution2)
                                {
                                    RowGood = false;
                                }
                                continue;
                            }
                        }
                        if (RowGood)
                            CHy.Add(Ans[j]);
                        else
                            RowGood = true;
                    }
                }
                else
                {
                    CHy.AddRange(Ans);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in Additional Rule Table. Please refer to the help section and check your input. Error Code:" + ex);
            }

            for (int i = 0; i < CHy.Count(); i++)
            {
                CHy[i].ElementNames.Clear();
                CHy[i].MoleculeNames.Clear();

                if (i == CHy.Count() - 1)
                {
                    CHy[0].ElementNames = elementIDs;
                }
            }
            return CHy;
        }
        private void BuildGlycopeptideHypothesis2(string compositionHypothesisPath, List<MSDigestPeptide> peptides)
        {
            CompositionHypothesis.CompositionHypothesis glycans = CompositionHypothesis.CompositionHypothesis.ParseCsv<GlycanComposition>(compositionHypothesisPath);
            GlycopeptideCompositionHypothesisBuilder glycopeptideHypothesisBuilder = new GlycopeptideCompositionHypothesisBuilder(glycans, peptides);
            glycopeptideHypothesisBuilder.BuildCompositionHypothesis();

            GlycanHypothesisCombinatorialGenerator GD = new GlycanHypothesisCombinatorialGenerator();
            theComhypoOnTab2 = BuildCompositionHypothesisDataTable(glycopeptideHypothesisBuilder.GlycopeptideComposition);
        }
        private void BuildGlycopeptideHypothesis1(string comhypopath)
        {
            List<CompositionHypothesisEntry> CHy = getCompHypo(comhypopath);
            List<string> elementIDs = new List<string>();
            List<string> molename = new List<string>();
            for (int j = 0; j < CHy.Count(); j++)
            {
                if (CHy[j].ElementNames.Count > 0)
                {
                    for (int i = 0; i < CHy[j].ElementNames.Count(); i++)
                    {
                        elementIDs.Add(CHy[j].ElementNames[i]);
                    }
                    for (int i = 0; i < CHy[j].MoleculeNames.Count(); i++)
                    {
                        molename.Add(CHy[j].MoleculeNames[i]);
                    }
                    break;
                }
            }

            String AddRep = CHy[0].AddRep;

            int indexH = 0;
            int indexO = 0;
            int indexWater = 0;
            try
            {
                indexH = elementIDs.IndexOf("H");
                indexO = elementIDs.IndexOf("O");
                indexWater = molename.IndexOf("Water");
                if (indexWater < 0)
                {
                    indexWater = molename.IndexOf("G:Water");
                }
                if (indexWater < 0)
                {
                    throw new Exception("No Water!");
                }
            }
            catch
            {
                MessageBox.Show("Your composition hypothesis contains a compound without Water. Job terminated.");
                return;
            }

            List<Peptide> PP = GetPeptidesFromTable();
            List<CompositionHypothesisEntry> Ans = new List<CompositionHypothesisEntry>();
            //Ans.AddRange(CHy);
            PeriodicTable PT = new PeriodicTable();
            for (int i = 0; i < PP.Count; i++)
            {
                if (PP[i].Selected)
                {
                    Int32 Count = Convert.ToInt32(PP[i].NumGlycosylations);
                    List<CompositionHypothesisEntry> Temp = new List<CompositionHypothesisEntry>();
                    CompositionHypothesisEntry temp = new CompositionHypothesisEntry();
                    //First line:
                    temp.CompoundComposition = "";
                    temp.AdductNum = 0;
                    temp.AddRep = "";
                    temp.MassWeight = PP[i].Mass;
                    for (int s = 0; s < CHy[0].eqCounts.Count; s++)
                    {
                        temp.eqCounts.Add(0);
                    }
                    for (int s = 0; s < CHy[0].ElementAmount.Count; s++)
                    {
                        temp.ElementAmount.Add(0);
                    }
                    //columns for glycopeptides
                    temp.PepModification = PP[i].Modifications;
                    temp.PepSequence = PP[i].Sequence;
                    temp.MissedCleavages = PP[i].MissedCleavages;
                    temp.StartAA = PP[i].StartAA;
                    temp.EndAA = PP[i].EndAA;
                    temp.NumGlycosylations = 0;
                    Temp.Add(temp);
                    for (int j = 0; j < Count; j++)
                    {
                        List<CompositionHypothesisEntry> Temp2 = new List<CompositionHypothesisEntry>();
                        for (int k = 0; k < Temp.Count(); k++)
                        {
                            //need to reread the file and get new reference, because c# keeps passing by reference which creates a problem.
                            List<CompositionHypothesisEntry> CH = getCompHypo(comhypopath);
                            for (int l = 0; l < CH.Count(); l++)
                            {
                                CompositionHypothesisEntry temp2 = new CompositionHypothesisEntry();
                                temp2 = CH[l];
                                temp2.NumGlycosylations = Temp[k].NumGlycosylations + 1;
                                temp2.PepModification = Temp[k].PepModification;
                                temp2.PepSequence = Temp[k].PepSequence;
                                temp2.MissedCleavages = Temp[k].MissedCleavages;
                                temp2.StartAA = Temp[k].StartAA;
                                temp2.EndAA = Temp[k].EndAA;
                                List<string> forsorting = new List<string>();
                                forsorting.Add(Temp[k].CompoundComposition);
                                forsorting.Add(temp2.CompoundComposition);
                                forsorting = forsorting.OrderBy(a => a).ToList();
                                temp2.CompoundComposition = forsorting[0] + forsorting[1];
                                temp2.AdductNum = temp2.AdductNum + Temp[k].AdductNum;
                                for (int s = 0; s < temp2.eqCounts.Count; s++)
                                {
                                    temp2.eqCounts[s] = temp2.eqCounts[s] + Temp[k].eqCounts[s];
                                }
                                for (int s = 0; s < temp2.ElementAmount.Count; s++)
                                {
                                    temp2.ElementAmount[s] = temp2.ElementAmount[s] + Temp[k].ElementAmount[s];
                                }
                                for (int ui = 0; ui < molename.Count(); ui++)
                                {
                                    if (molename[ui] == "Water")
                                    {
                                        if (temp2.eqCounts[ui] > 0)
                                        {
                                            temp2.eqCounts[ui] = temp2.eqCounts[ui] - 1;
                                        }
                                        break;
                                    }
                                }
                                #region Modified by JK
                                //temp2.elementAmount[indexH] = temp2.elementAmount[indexH] - 2;
                                //temp2.elementAmount[indexO] = temp2.elementAmount[indexO] - 1;
                                //if (temp2.elementAmount[indexO] < 0)
                                //    temp2.elementAmount[indexO] = 0;
                                //if (temp2.elementAmount[indexH] < 0)
                                //    temp2.elementAmount[indexH] = 0;

                                /* These fields are not present in the Database-generated hypothesis,
                                 * but they are not appropriately error-checked when computed earlier.
                                 * This bandaid should let existing files work while letting Database-
                                 * generated ones through as well. This function is very difficult to
                                 * trace in and would benefit from rewriting in the future.
                                 */
                                if ((indexH > 0) && (indexO > 0))
                                {
                                    temp2.ElementAmount[indexH] = temp2.ElementAmount[indexH] - 2;
                                    temp2.ElementAmount[indexO] = temp2.ElementAmount[indexO] - 1;
                                    if (temp2.ElementAmount[indexO] < 0)
                                        temp2.ElementAmount[indexO] = 0;
                                    if (temp2.ElementAmount[indexH] < 0)
                                        temp2.ElementAmount[indexH] = 0;
                                }
                                //else
                                //{
                                //    temp2.elementAmount[indexH] = 0;
                                //    temp2.elementAmount[indexO] = 0;
                                //}
                                #endregion
                                //Hard coded removal of extra water from neutral Charge glycan.
                                temp2.MassWeight = temp2.MassWeight + Temp[k].MassWeight - PT.getMass("H") * 2 - PT.getMass("O");
                                Temp2.Add(temp2);
                            }
                        }
                        Temp.AddRange(Temp2);
                    }
                    Ans.AddRange(Temp);
                }
            }
            //Remove Duplicates from CHy
            Ans = Ans.OrderBy(a => a.MassWeight).ToList();
            CHy.Clear();
            for (int i = 0; i < Ans.Count() - 1; i++)
            {
                bool thesame = false;
                bool equal = (Ans[i].eqCounts.Count == Ans[i + 1].eqCounts.Count) && new HashSet<int>(Ans[i].eqCounts).SetEquals(Ans[i + 1].eqCounts);
                if (Ans[i].PepSequence == Ans[i + 1].PepSequence && equal)
                {
                    if (Ans[i].AdductNum == Ans[i + 1].AdductNum && Ans[i].PepModification == Ans[i + 1].PepModification)
                    {
                        thesame = true;
                    }
                }
                if (!thesame)
                    CHy.Add(Ans[i]);
            }
            Console.WriteLine("Ans Length {0}", Ans.Count());
            //Enter elementID and MoleNames into each rows
            CHy.Add(Ans[Ans.Count() - 1]);
            for (int i = 0; i < CHy.Count(); i++)
            {
                CHy[i].ElementNames.Clear();
                CHy[i].MoleculeNames.Clear();

                if (i == CHy.Count() - 1)
                {
                    CHy[0].ElementNames = elementIDs;
                    CHy[0].MoleculeNames = molename;
                }
            }

            //Obtain the Name of the adduct molecules:
            GlycanHypothesisCombinatorialGenerator GD = new GlycanHypothesisCombinatorialGenerator();
            GD.Modification = AddRep.Split('/');

            //Send to generate DataTable
            Console.WriteLine(CHy[0]);
            theComhypoOnTab2 = genDT(CHy, GD);
        }
        //This function is used to read the cpos file and translate it to generatorData format.
        private GlycanHypothesisCombinatorialGenerator extractFile(String path)
        {
            //table is used to store the data before the calculation
            GlycanHypothesisCombinatorialGenerator DATA = new GlycanHypothesisCombinatorialGenerator();
            List<GlycanCompositionTable> GD = new List<GlycanCompositionTable>();
            try
            {
                FileStream reading = new FileStream(path, FileMode.Open, FileAccess.Read);
                StreamReader readcompo = new StreamReader(reading);
                //Read the first line to throw the column names:
                String Line1 = readcompo.ReadLine();
                String[] headers = Line1.Split(',');
                int sh = 2;
                bool moreElements = true;
                List<string> elementIDs = new List<string>();
                while (moreElements)
                {
                    if (headers[sh] != "Lower Bound")
                    {
                        elementIDs.Add(headers[sh]);
                        sh++;
                    }
                    else
                    {
                        moreElements = false;
                    }

                }
                bool firstRow = true;
                while (readcompo.Peek() >= 0)
                {
                    String Line = readcompo.ReadLine();
                    String[] eachentry = Line.Split(',');
                    if (eachentry[0] == "Modification%^&!@#*()iop")
                        break;
                    GlycanCompositionTable CT = new GlycanCompositionTable();
                    CT.Letter = eachentry[0];
                    CT.Molecule = eachentry[1];
                    if (firstRow)
                    {
                        CT.elementIDs = elementIDs;
                        firstRow = false;
                    }
                    for (int i = 0; i < elementIDs.Count(); i++)
                    {
                        CT.elementAmount.Add(Convert.ToInt32(eachentry[2 + i]));
                    }
                        //Random the lower bound and upper bound to get random composition hypothesis
                    CT.Bound = new List<String>();
                    CT.Bound.Add(eachentry[2 + elementIDs.Count()]);
                    CT.Bound.Add(eachentry[2 + elementIDs.Count() + 1]);
                    GD.Add(CT);
                }
                String Line2 = readcompo.ReadLine();
                String[] eachentry2 = Line2.Split(',');
                DATA.comTable = GD;
                DATA.Modification = eachentry2;
                readcompo.Close();
                reading.Close();
            }
            catch (Exception compoex)
            {
                MessageBox.Show("Error in loading GlycanCompositions Table (cpos). Error:" + compoex);
            }

            DATA.aTable = new List<Boundary>();
            DATA.comTable = GD;
            return DATA;
        }
        //This function reads the generate composition page and save it to a variable of class "generator".
        public GlycanHypothesisCombinatorialGenerator getGenerator()
        {
            //compotable is used to store the data from the composition table before they are used.
            List<GlycanCompositionTable> compotable = new List<GlycanCompositionTable>();
            //arTable is used to store the data from additional rules table before they're used.
            List<Boundary> arTable = new List<Boundary>();
            //GD is used to store all the data that will be returned.
            GlycanHypothesisCombinatorialGenerator GD = new GlycanHypothesisCombinatorialGenerator();

            String currentpath = Application.StartupPath + "\\compositionsCurrent.cpos";
            try
            {
                FileStream reading = new FileStream(currentpath, FileMode.Open, FileAccess.Read);
                StreamReader readcompo = new StreamReader(reading);
                //Read the first line to skip the column names:
                String Line1 = readcompo.ReadLine();
                String[] headers = Line1.Split(',');
                List<string> elementIDs = new List<string>();
                bool moreElements = true;
                int sh= 2;
                while (moreElements)
                {
                    if (headers[sh] != "Lower Bound")
                    {
                        elementIDs.Add(headers[sh]);
                        sh++;
                    }
                    else
                        moreElements = false;
                }

                bool firstrow = true;
                //Read the other lines for compTable data.
                while (readcompo.Peek() >= 0)
                {
                    GlycanCompositionTable compTable = new GlycanCompositionTable();
                    if (firstrow)
                    {
                        compTable.elementIDs = elementIDs;
                        firstrow = false;
                    }
                    String Line = readcompo.ReadLine();
                    String[] eachentry = Line.Split(',');
                    //When next line is the Modification line, it breaks.
                    if (eachentry[0] == "Modification%^&!@#*()iop")
                        break;
                    compTable.Letter = eachentry[0];
                    compTable.Molecule = eachentry[1];
                    for (int i = 2; i < elementIDs.Count + 2; i++)
                    {
                        compTable.elementAmount.Add(Convert.ToInt32(eachentry[i]));
                    }
                    List<String> bounds = new List<String>();
                    bounds.Add(eachentry[elementIDs.Count + 2]);
                    bounds.Add(eachentry[elementIDs.Count + 3]);
                    compTable.Bound = bounds;
                    compotable.Add(compTable);
                }
                //Send compotable data to GD
                GD.comTable = compotable;
                //Populate the Modification Table
                String modiLine = readcompo.ReadLine();
                //Send Modification data to GD
                GD.Modification = modiLine.Split(',');

                //Populate the additional rules table
                while (readcompo.Peek() >= 0)
                {
                    String Line = readcompo.ReadLine();
                    String[] eachentry = Line.Split(',');
                    if (eachentry[0] != "" && eachentry[2] != "")
                    {
                        Boundary areTable = new Boundary();
                        areTable.Formula = eachentry[0];
                        areTable.Relationship = eachentry[1];
                        areTable.Constraint = Convert.ToString(eachentry[2]);
                        arTable.Add(areTable);
                    }
                }
                //Send arTable data to GD.
                GD.aTable = arTable;

                readcompo.Close();
                reading.Close();
            }
            catch (Exception compoex)
            {
                MessageBox.Show("Error in loading GlycanCompositions Table. Error:" + compoex);
            }
            return GD;
        }
        private List<CompositionHypothesisEntry> addAdducts(List<CompositionHypothesisEntry> CHy, GlycanHypothesisCombinatorialGenerator GD)
        {
            List<string> elementIDs = new List<string>();
            List<string> molname = new List<string>();
            for (int j = 0; j < CHy.Count(); j++ )
            {
                if (CHy[j].ElementNames.Count > 0)
                {
                    for (int i = 0; i < CHy[j].ElementNames.Count(); i++)
                    {
                        elementIDs.Add(CHy[j].ElementNames[i]);
                    }
                    for (int i = 0; i < CHy[j].MoleculeNames.Count(); i++)
                    {
                        molname.Add(CHy[j].MoleculeNames[i]);
                    }
                    break;
                }
            }

            Double adductMas = CalculateAdductMass(GD);
            Int32 adductLB = new Int32();
            Int32 adductUB = new Int32();
            try
            {
                adductLB = Convert.ToInt32(GD.Modification[2]);
                adductUB = Convert.ToInt32(GD.Modification[3]);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Lower bound and Upper bound in the Modification list must be integers. Error:" + ex);
                this.Close();
            }
            AdductComposition adc = getAdductCompo(GD);

            //update elementID list
            for (int i = 0; i < adc.elementIDs.Count(); i++)
            {
                if (!(elementIDs.Any(a => a.Contains(adc.elementIDs[i]))))
                {
                    elementIDs.Add(adc.elementIDs[i]);
                    foreach (CompositionHypothesisEntry CH in CHy)
                    {
                        CH.ElementAmount.Add(0);
                    }
                }
            }

            List<CompositionHypothesisEntry> supFinalAns = new List<CompositionHypothesisEntry>();
            for (int i = 0; i < CHy.Count(); i++)
            {
                if (adductLB != 0)
                {
                    CompositionHypothesisEntry temp = new CompositionHypothesisEntry();
                    temp.ElementAmount = CHy[i].ElementAmount;
                    temp.AdductNum = 0;
                    temp.eqCount = CHy[i].eqCount;
                    temp.MassWeight = CHy[i].MassWeight;
                    supFinalAns.Add(temp);
                }

                for (int j = adductLB; j <= adductUB; j++)
                {
                    CompositionHypothesisEntry temp = new CompositionHypothesisEntry();
                    for (int k = 0; k < CHy[i].ElementAmount.Count(); k++)
                    {
                        temp.ElementAmount.Add(CHy[i].ElementAmount[k]);
                    }
                    for (int l = 0; l < adc.elementAmount.Count(); l++)
                    {
                        temp.ElementAmount[elementIDs.IndexOf(adc.elementIDs[l])] = CHy[i].ElementAmount[elementIDs.IndexOf(adc.elementIDs[l])] + j * adc.elementAmount[l];
                     }
                    temp.AdductNum = j;
                    temp.eqCount = CHy[i].eqCount;
                    temp.MassWeight = CHy[i].MassWeight + j * adductMas;
                    supFinalAns.Add(temp);
                }
            }
            for (int i = 0; i < supFinalAns.Count(); i++)
            {
                supFinalAns[i].ElementNames.Clear();
                supFinalAns[i].MoleculeNames.Clear();

                if (i == supFinalAns.Count() - 1)
                {
                    supFinalAns[0].ElementNames = elementIDs;
                    supFinalAns[0].MoleculeNames = molname;
                }
            }

            return supFinalAns;
        }
        //This puts comhypo data into a datatable.
        private DataTable genDT(List<CompositionHypothesisEntry> UltFinalAns, GlycanHypothesisCombinatorialGenerator GD)
        {
            //Console.WriteLine("---genDT---");
            DataTable hypo = new DataTable();
            List<string> elementIDs = new List<string>();
            List<string> molname = new List<string>();
            for (int j = 0; j < UltFinalAns.Count(); j++)
            {
                if (UltFinalAns[j].ElementNames.Count > 0)
                {
                    for (int i = 0; i < UltFinalAns[j].ElementNames.Count(); i++)
                    {
                        elementIDs.Add(UltFinalAns[j].ElementNames[i]);
                    }
                    for (int i = 0; i < UltFinalAns[j].MoleculeNames.Count(); i++)
                    {
                        molname.Add(UltFinalAns[j].MoleculeNames[i]);
                    }
                    break;
                }
            }

            hypo.Columns.Add("Molecular Weight", typeof(Double));
            for (int i = 0; i < elementIDs.Count(); i++)
            {
                hypo.Columns.Add(elementIDs[i], typeof(Int32));
            }
            #region Debugging
            //Console.WriteLine("---Molecule Names---");
            //foreach (string s in molname)
            //{
            //    Console.WriteLine(s);
            //}
            ////Console.WriteLine("---Element IDs---");
            //foreach (string s in elementIDs)
            //{
            //    Console.WriteLine(s);
            //}
            #endregion
            hypo.Columns.Add("Compositions", typeof(String));
            for (int i = 0; i < UltFinalAns[0].eqCounts.Count(); i++)
            {
                //Console.WriteLine(i);
                hypo.Columns.Add(molname[i], typeof(Int32));
            }

            hypo.Columns.Add("Adduct/Replacement", typeof(String));
            hypo.Columns.Add("Adduct Amount", typeof(Int32));
            hypo.Columns.Add("Peptide Sequence", typeof(String));
            hypo.Columns.Add("Peptide Modification", typeof(String));
            hypo.Columns.Add("Peptide Missed Cleavage Number", typeof(Int32));
            hypo.Columns.Add("Number of Glycan Attachment to Peptide", typeof(Int32));
            hypo.Columns.Add("Start AA", typeof(Int32));
            hypo.Columns.Add("End AA", typeof(Int32));
            hypo.Columns.Add("Protein ID", typeof(String));

            //This is the variable for the Adduct/Replacement column.
            String AddReplace = GD.Modification[0] + "/" + GD.Modification[1];
            for (int s = 0; s < UltFinalAns.Count(); s++)
            {
                DataRow ab = hypo.NewRow();
                String composition = "";
                if (UltFinalAns[s].eqCounts.Count() == 0)
                    composition = "0";
                else
                {
                    composition = "[" + UltFinalAns[s].eqCounts[0];
                    for (int i = 1; i < UltFinalAns[s].eqCounts.Count(); i++)
                    {
                        composition = composition + ";" + UltFinalAns[s].eqCounts[i];
                    }
                    composition = composition + "]";
                }
                ab[0] = UltFinalAns[s].MassWeight;
                int sh = 1;
                for (int i = 0; i < elementIDs.Count(); i++)
                {
                   ab[sh + i] = UltFinalAns[s].ElementAmount[i];
                }
                ab[sh + elementIDs.Count()] = composition;
                for (int i = 0; i < UltFinalAns[s].eqCounts.Count(); i++)
                {
                    ab[sh + elementIDs.Count() + 1 + i] = UltFinalAns[s].eqCounts[i];
                }
                ab["Adduct/Replacement"] = AddReplace;
                ab["Adduct Amount"] = UltFinalAns[s].AdductNum;
                ab["Peptide Sequence"] = UltFinalAns[s].PepSequence;
                ab["Peptide Modification"] = UltFinalAns[s].PepModification;
                ab["Peptide Missed Cleavage Number"] = UltFinalAns[s].MissedCleavages;
                ab["Number of Glycan Attachment to Peptide"] = UltFinalAns[s].NumGlycosylations;
                ab["Start AA"] = UltFinalAns[s].StartAA;
                ab["End AA"] = UltFinalAns[s].EndAA;
                hypo.Rows.Add(ab);
            }
            for (int i = 0; i < hypo.Columns.Count; i++)
            {
                hypo.Columns[i].SetOrdinal(i);
            }
            return hypo;
        }