/**
         * For facing colunit definition line, for example:
         * MTD  colunit-protein retention_time=[UO, UO:000031, minute, ]
         * after parse metadata and header lines, need calling
         * {@link #refineColUnit(uk.ac.ebi.pride.jmztab.model.MZTabColumnFactory)} manually.
         */
        public new void Parse(int lineNumber, string mtdLine, MZTabErrorList errorList)
        {
            base.Parse(lineNumber, mtdLine, errorList);

            if (_items.Length != 3){
                MZTabError error = new MZTabError(FormatErrorType.MTDLine, lineNumber, mtdLine);
                throw new MZTabException(error);
            }

            string defineLabel = _items[1].Trim().ToLower();
            string valueLabel = _items[2].Trim();

            if (defineLabel.Contains("colunit")){
                // ignore colunit parse. In the stage, just store them into colUnitMap<defineLabel, valueLabel>.
                // after table section columns created, call checkColUnit manually.
                _colUnitMap.Add(defineLabel, valueLabel);

                if (! defineLabel.Equals("colunit-protein") &&
                    ! defineLabel.Equals("colunit-peptide") &&
                    ! defineLabel.Equals("colunit-psm") &&
                    ! defineLabel.Equals("colunit-small_molecule")){
                    MZTabError error = new MZTabError(FormatErrorType.MTDDefineLabel, lineNumber, defineLabel);
                    throw new MZTabException(error);
                }
            }
            else{
                parseNormalMetadata(defineLabel, valueLabel);
            }
        }
        /**
        * We assume that user before call this method, have parse the raw line
        * is not empty line and start with section prefix.
        */
        protected void Parse(int lineNumber, string line, MZTabErrorList errorList)
        {
            _lineNumber = lineNumber;
            _line = line;
            _errorList = errorList ?? new MZTabErrorList();

            _items = line.Split(MZTabConstants.TAB);
            _items[0] = _items[0].Trim();
            _items[_items.Length - 1] = _items[_items.Length - 1].Trim();

            _section = Section.findSection(_items[0]);

            if (_section == null){
                MZTabError error = new MZTabError(FormatErrorType.LinePrefix, lineNumber, _items[0]);
                _errorList.Add(error);
            }
        }
        /**
         * A limit max capacity list, if contains a couple of {@link MZTabError} objects.
         * If overflow, system will raise {@link MZTabErrorOverflowException}. Besides this, during
         * add a new {@link MZTabError} object, it's {@link MZTabErrorType#level} SHOULD equal or
         * great than its level setting.
         *
         * @param error SHOULD NOT set null
         */
        public bool Add(MZTabError error)
        {
            if (error == null){
                throw new NullReferenceException("Can not add a null error into list.");
            }

            if (error.Type.Level.CompareTo(level) < 0){
                return false;
            }

            if (_errorList.Count >= MZTabProperties.MAX_ERROR_COUNT){
                throw new MZTabErrorOverflowException();
            }

            if (_errorList.Any(x => x.Type == error.Type && x.Message == error.Message)){
                return false;
            }
            _errorList.Add(error);
            return true;
        }
        private Url checkURL(string defineLabel, string valueLabel)
        {
            Url url = MZTabUtils.ParseUrl(valueLabel);
            if (url == null){
                MZTabError error = new MZTabError(FormatErrorType.URL, _lineNumber, Error_Header + defineLabel,
                                                  valueLabel);
                throw new MZTabException(error);
            }

            return url;
        }
        private SplitList<PublicationItem> checkPublication(string defineLabel, string valueLabel)
        {
            SplitList<PublicationItem> publications = MZTabUtils.ParsePublicationItems(valueLabel);
            if (publications.Count == 0){
                MZTabError error = new MZTabError(FormatErrorType.Publication, _lineNumber, Error_Header + defineLabel,
                                                  valueLabel);
                throw new MZTabException(error);
            }

            return publications;
        }
        private MetadataProperty checkProperty(MetadataSubElement subElement, string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName)){
                return null;
            }

            MetadataProperty property = MetadataProperty.FindProperty(subElement, propertyName);
            if (property == null){
                MZTabError error = new MZTabError(FormatErrorType.MTDDefineLabel, _lineNumber,
                                                  subElement.Name + "-" + propertyName);
                throw new MZTabException(error);
            }

            return property;
        }
        private SplitList<Param> checkParamList(string defineLabel, string valueLabel)
        {
            SplitList<Param> paramList = MZTabUtils.ParseParamList(valueLabel);
            if (paramList == null || paramList.Count == 0){
                MZTabError error = new MZTabError(FormatErrorType.ParamList, _lineNumber, Error_Header + defineLabel,
                                                  valueLabel);
                throw new MZTabException(error);
            }

            return paramList;
        }
        private Param checkParam(string defineLabel, string valueLabel)
        {
            Param param = MZTabUtils.ParseParam(valueLabel);
            if (param == null){
                MZTabError error = new MZTabError(FormatErrorType.Param, _lineNumber, Error_Header + defineLabel,
                                                  valueLabel);
                throw new MZTabException(error);
            }

            return param;
        }
        /**
         * Check XXXX_abundance_assay[id] column header. If parse error, stop validate and raise
         * {@link MZTabException}.
         */
        private void checkAbundanceAssayColumn(string abundanceHeader)
        {
            string valueLabel = checkAbundanceSection(abundanceHeader);
            Regex regex = new Regex("assay\\[(\\d+)\\]");
            Match match = regex.Match(valueLabel);
            if (! match.Success){
                MZTabError error = new MZTabError(FormatErrorType.AbundanceColumn, _lineNumber, abundanceHeader);
                throw new MZTabException(error);
            }

            int id = checkIndex(abundanceHeader, match.Groups[1].Value);
            Assay assay = null;
            if (metadata.AssayMap.ContainsKey(id)){
                assay = metadata.AssayMap[id];
            }
            if (assay == null){
                MZTabError error = new MZTabError(LogicalErrorType.AssayNotDefined, _lineNumber, abundanceHeader);
                throw new MZTabException(error);
            }

            factory.AddAbundanceOptionalColumn(assay);
        }
        // the id is not correct number in the define label.
        private int checkIndex(string defineLabel, string id)
        {
            try{
                int index = int.Parse(id);
                if (index < 1){
                    throw new FormatException();
                }

                return index;
            }
            catch (FormatException){
                MZTabError error = new MZTabError(LogicalErrorType.IdNumber, _lineNumber, Error_Header + defineLabel, id);
                throw new MZTabException(error);
            }
        }
        private string checkEmail(string defineLabel, string valueLabel)
        {
            string email = MZTabUtils.ParseEmail(valueLabel);

            if (email == null){
                MZTabError error = new MZTabError(FormatErrorType.Email, _lineNumber, Error_Header + defineLabel,
                                                  valueLabel);
                throw new MZTabException(error);
            }

            return email;
        }
        /**
         * Focus on validate and parse for stable columns and optional columns which have stable order;
         * All of them defined in the {@link ProteinColumn}, {@link PeptideColumn}, {@link PSMColumn}
         * or {@link SmallMoleculeColumn}.
         *
         * NOTICE: there not exist optional columns with stable order in {@link PSMColumn}
         */
        private int parseStableOrderColumns()
        {
            List<string> headerList = _items.ToList();

            // step 1: confirm stable columns have been included in the header line.
            foreach (MZTabColumn column in factory.StableColumnMapping.Values){
                if (! headerList.Contains(column.Header)){
                    MZTabError error = new MZTabError(FormatErrorType.StableColumn, _lineNumber, column.Header);
                    throw new MZTabException(error);
                }
            }

            // step 2: checking some optional columns which have stable order.
            foreach (string header in headerList){
                if (header.Equals(ProteinColumn.GO_TERMS.Header)){
                    factory.addGoTermsOptionalColumn();
                }
                else if (header.Equals(ProteinColumn.RELIABILITY.Header)){
                    factory.addReliabilityOptionalColumn();
                }
                else if (header.Equals(ProteinColumn.URI.Header)){
                    factory.addURIOptionalColumn();
                }
            }

            // step 3: checking some flexible optional columns which have stable order.
            if (_items != null){
                MZTabColumn column = null;
                Regex regex = new Regex("(\\w+)_ms_run\\[(\\d+)\\]");

                for (int i = 1; i < _items.Length; i++){
                    string header = _items[i];

                    Match match = regex.Match(header);
                    if (regex.IsMatch(header)){
                        int id = checkIndex(header, match.Groups[2].Value);

                        MsRun msRun = null;
                        if (metadata.MsRunMap.ContainsKey(id)){
                            msRun = metadata.MsRunMap[id];
                        }
                        if (msRun == null){
                            throw new MZTabException(new MZTabError(LogicalErrorType.MsRunNotDefined, _lineNumber,
                                                                    header));
                        }

                        if (_section.Equals(Section.Protein_Header)){
                            if (header.StartsWith(ProteinColumn.SEARCH_ENGINE_SCORE.Name)){
                                column = ProteinColumn.SEARCH_ENGINE_SCORE;
                            }
                            else if (header.StartsWith(ProteinColumn.NUM_PSMS.Name)){
                                column = ProteinColumn.NUM_PSMS;
                            }
                            else if (header.StartsWith(ProteinColumn.NUM_PEPTIDES_DISTINCT.Name)){
                                column = ProteinColumn.NUM_PEPTIDES_DISTINCT;
                            }
                            else if (header.StartsWith(ProteinColumn.NUM_PEPTIDES_UNIQUE.Name)){
                                column = ProteinColumn.NUM_PEPTIDES_UNIQUE;
                            }
                            else if (header.StartsWith("opt_")){
                                // ignore opt_ms_run....
                                // This kind of optional columns will be processed in the parseOptionalColumns() method.
                            }
                            else{
                                throw new MZTabException(new MZTabError(FormatErrorType.MsRunOptionalColumn,
                                                                        _lineNumber,
                                                                        header, _section.Name));
                            }
                        }
                        else if (_section.Equals(Section.Peptide_Header)){
                            if (header.StartsWith(PeptideColumn.SEARCH_ENGINE_SCORE.Name)){
                                column = PeptideColumn.SEARCH_ENGINE_SCORE;
                            }
                            else if (header.StartsWith("opt_")){
                                // ignore opt_ms_run....
                                // This kind of optional columns will be processed in the parseOptionalColumns() method.
                            }
                            else{
                                throw new MZTabException(new MZTabError(FormatErrorType.MsRunOptionalColumn,
                                                                        _lineNumber,
                                                                        header, _section.Name));
                            }
                        }
                        else if (_section.Equals(Section.Small_Molecule_Header)){
                            if (header.StartsWith(SmallMoleculeColumn.SEARCH_ENGINE_SCORE.Name)){
                                column = SmallMoleculeColumn.SEARCH_ENGINE_SCORE;
                            }
                            else if (header.StartsWith("opt_")){
                                // ignore opt_ms_run....
                                // This kind of optional columns will be processed in the parseOptionalColumns() method.
                            }
                            else{
                                throw new MZTabException(new MZTabError(FormatErrorType.MsRunOptionalColumn,
                                                                        _lineNumber,
                                                                        header, _section.Name));
                            }
                        }

                        if (column != null){
                            factory.AddOptionalColumn(column, msRun);
                        }
                    }
                }
            }

            return factory.StableColumnMapping.Values.Count;
        }
        /**
         * Additional columns can be added to the end of the protein table. These column headers MUST start with the prefix "opt_".
         * Column names MUST only contain the following characters: 'A’-'Z’, 'a’-'z’, '0’-'9’, '_’, '-’, '[’, ']’, and ':’.
         *
         * the format: opt_{IndexedElement[id]}_{value}. Spaces within the parameter's name MUST be replaced by '_'.
         */
        private bool checkOptColumnName(string nameLabel)
        {
            nameLabel = nameLabel.Trim();

            const string regexp = "opt_((assay|study_variable|ms_run)\\[(\\w+)\\]|global)_([A-Za-z0-9_\\-\\[\\]:\\.]+)";
            Regex regex = new Regex(regexp);
            Match match = regex.Match(nameLabel);

            if (match.Success){
                string object_id = match.Groups[1].Value;
                string value = match.Groups[4].Value;

                CVParam param = null;
                if (value.StartsWith("cv_")){
                    param = checkCVParamOptColumnName(nameLabel, value);
                }

                Type dataType = getDataType(param);

                if (object_id.Contains("global")){
                    if (param == null){
                        factory.AddOptionalColumn(value, dataType);
                    }
                    else{
                        factory.AddOptionalColumn(param, dataType);
                    }
                }
                else{
                    int id = checkIndex(nameLabel, match.Groups[3].Value);

                    MZTabError error;
                    if (object_id.Contains("assay")){
                        Assay element = null;
                        if (metadata.AssayMap.ContainsKey(id)){
                            element = metadata.AssayMap[id];
                        }
                        // not found assay_id in metadata.
                        if (element == null){
                            error = new MZTabError(LogicalErrorType.AssayNotDefined, _lineNumber, nameLabel);
                            throw new MZTabException(error);
                        }
                        if (param == null){
                            factory.AddOptionalColumn(element, value, dataType);
                        }
                        else{
                            factory.AddOptionalColumn(element, param, dataType);
                        }
                    }
                    else if (object_id.Contains("study_variable")){
                        StudyVariable element = null;
                        if (metadata.StudyVariableMap.ContainsKey(id)){
                            element = metadata.StudyVariableMap[id];
                        }
                        // not found study_variable_id in metadata.
                        if (element == null){
                            error = new MZTabError(LogicalErrorType.StudyVariableNotDefined, _lineNumber, nameLabel);
                            throw new MZTabException(error);
                        }
                        if (param == null){
                            factory.AddOptionalColumn(element, value, dataType);
                        }
                        else{
                            factory.AddOptionalColumn(element, param, dataType);
                        }
                    }
                    else if (object_id.Contains("ms_run")){
                        MsRun element = null;
                        if (metadata.MsRunMap.ContainsKey(id)){
                            element = metadata.MsRunMap[id];
                        }
                        // not found ms_run_id in metadata.
                        if (element == null){
                            error = new MZTabError(LogicalErrorType.MsRunNotDefined, _lineNumber, nameLabel);
                            throw new MZTabException(error);
                        }
                        if (param == null){
                            factory.AddOptionalColumn(element, value, dataType);
                        }
                        else{
                            factory.AddOptionalColumn(element, param, dataType);
                        }
                    }
                }

                return true;
            }
            throw new MZTabException(new MZTabError(FormatErrorType.OptionalCVParamColumn, _lineNumber, nameLabel));
        }
        /**
         * Check XXXX_abundance_study_variable[id], XXXX_abundance_stdev_study_variable[id], XXXX_abundance_std_error_study_variable[id]
         * column header. If parse error, stop validate and raise {@link MZTabException}.
         */
        private void checkAbundanceStudyVariableColumns(string abundanceHeader, string abundanceStdevHeader,
                                                        string abundanceStdErrorHeader)
        {
            abundanceHeader = abundanceHeader.Trim().ToLower();
            abundanceStdevHeader = abundanceStdevHeader.Trim().ToLower();
            abundanceStdErrorHeader = abundanceStdErrorHeader.Trim().ToLower();

            if (! abundanceHeader.Contains("_abundance_study_variable")){
                string missHeader = Section.toDataSection(_section).Name + "_abundance_study_variable";

                MZTabError error = new MZTabError(LogicalErrorType.AbundanceColumnTogether, _lineNumber, missHeader);
                throw new MZTabException(error);
            }

            if (! abundanceStdevHeader.Contains("_abundance_stdev_study_variable")){
                string missHeader = Section.toDataSection(_section).Name + "_abundance_stdev_study_variable";

                MZTabError error = new MZTabError(LogicalErrorType.AbundanceColumnTogether, _lineNumber, missHeader);
                throw new MZTabException(error);
            }

            if (! abundanceStdErrorHeader.Contains("_abundance_std_error_study_variable")){
                string missHeader = Section.toDataSection(_section).Name + "_abundance_std_error_study_variable";

                MZTabError error = new MZTabError(LogicalErrorType.AbundanceColumnTogether, _lineNumber, missHeader);
                throw new MZTabException(error);
            }

            StudyVariable abundanceStudyVariable = checkAbundanceStudyVariableColumn(abundanceHeader);
            StudyVariable abundanceStdevStudyVariable = checkAbundanceStudyVariableColumn(abundanceStdevHeader);
            StudyVariable abundanceStdErrorStudyVariable = checkAbundanceStudyVariableColumn(abundanceStdErrorHeader);

            if (abundanceStudyVariable != abundanceStdevStudyVariable ||
                abundanceStudyVariable != abundanceStdErrorStudyVariable){
                MZTabError error = new MZTabError(LogicalErrorType.AbundanceColumnSameId, _lineNumber, abundanceHeader,
                                                  abundanceStdevHeader, abundanceStdErrorHeader);
                throw new MZTabException(error);
            }

            factory.AddAbundanceOptionalColumn(abundanceStudyVariable);
        }
        /**
         * Check XXXX_abundance_study_variable[id], XXXX_abundance_stdev_study_variable[id], XXXX_abundance_std_error_study_variable[id]
         * column header. If parse error, stop validate and raise {@link MZTabException}.
         */
        private StudyVariable checkAbundanceStudyVariableColumn(string abundanceHeader)
        {
            string valueLabel = checkAbundanceSection(abundanceHeader);

            Regex regex = new Regex("study_variable\\[(\\d+)\\]");
            Match match = regex.Match(valueLabel);

            if (! match.Success){
                MZTabError error = new MZTabError(FormatErrorType.AbundanceColumn, _lineNumber, abundanceHeader);
                throw new MZTabException(error);
            }

            int id = checkIndex(abundanceHeader, match.Groups[1].Value);
            StudyVariable studyVariable = null;
            if (metadata.StudyVariableMap.ContainsKey(id)){
                studyVariable = metadata.StudyVariableMap[id];
            }

            if (studyVariable == null){
                MZTabError error = new MZTabError(LogicalErrorType.StudyVariableNotDefined, _lineNumber, abundanceHeader);
                throw new MZTabException(error);
            }

            return studyVariable;
        }
        /**
         * Check (protein|peptide|smallmolecule)_abundance is correct, and return object value label.
         * For example, protein_abundance_std_error_study_variable[id], return study_variable[id].
         */
        private string checkAbundanceSection(string abundanceHeader)
        {
            abundanceHeader = abundanceHeader.Trim().ToLower();

            Regex regex = new Regex("(protein|peptide|smallmolecule)_abundance_(.+)");
            Match match = regex.Match(abundanceHeader);

            if (match.Success){
                string sectionName = translate(match.Groups[1].Value);
                if (sectionName != null &&
                    !(sectionName.Equals(Section.Protein.Name) && _section != Section.Protein_Header) &&
                    !(sectionName.Equals(Section.Peptide.Name) && _section != Section.Peptide_Header) &&
                    !(sectionName.Equals(Section.Small_Molecule.Name) && _section != Section.Small_Molecule_Header)){
                    return match.Groups[2].Value;
                }

                MZTabError error = new MZTabError(FormatErrorType.AbundanceColumn, _lineNumber, abundanceHeader);
                throw new MZTabException(error);
            }
            else{
                MZTabError error = new MZTabError(FormatErrorType.AbundanceColumn, _lineNumber, abundanceHeader);
                throw new MZTabException(error);
            }
        }
 public MZTabException(MZTabError error)
     : base(error.ToString())
 {
     _error = error;
 }
        private List<IndexedElement> checkIndexedElementList(string defineLabel, string valueLabel,
                                                             MetadataElement element)
        {
            List<IndexedElement> indexedElementList = MZTabUtils.ParseIndexedElementList(valueLabel, element);
            if (indexedElementList == null || indexedElementList.Count == 0){
                MZTabError error = new MZTabError(FormatErrorType.IndexedElement, _lineNumber,
                                                  Error_Header + defineLabel, valueLabel);
                throw new MZTabException(error);
            }

            return indexedElementList;
        }
        /**
         * Query {@link uk.ac.ebi.pride.jmztab.utils.errors.MZTabErrorList} to check exist errors or not.
         * @throws java.io.IOException
         * @throws uk.ac.ebi.pride.jmztab.utils.errors.MZTabException during parse metadata, protein/peptide/small_molecule header line, exists error.
         * @throws uk.ac.ebi.pride.jmztab.utils.errors.MZTabErrorOverflowException reference mztab.properties file mztab.max_error_count parameter.
         */
        public void check(StreamReader reader)
        {
            COMLineParser comParser = new COMLineParser();
            MTDLineParser mtdParser = new MTDLineParser();
            PRHLineParser prhParser = null;
            PRTLineParser prtParser = null;
            PEHLineParser pehParser = null;
            PEPLineParser pepParser = null;
            PSHLineParser pshParser = null;
            PSMLineParser psmParser = null;
            SMHLineParser smhParser = null;
            SMLLineParser smlParser = null;

            SortedDictionary<int, Comment> commentMap = new SortedDictionary<int, Comment>();
            SortedDictionary<int, Protein> proteinMap = new SortedDictionary<int, Protein>();
            SortedDictionary<int, Peptide> peptideMap = new SortedDictionary<int, Peptide>();
            SortedDictionary<int, PSM> psmMap = new SortedDictionary<int, PSM>();
            SortedDictionary<int, SmallMolecule> smallMoleculeMap = new SortedDictionary<int, SmallMolecule>();

            PositionMapping prtPositionMapping = null;
            PositionMapping pepPositionMapping = null;
            PositionMapping psmPositionMapping = null;
            PositionMapping smlPositionMapping = null;

            string line;
            int highWaterMark = 1;
            int lineNumber = 0;
            while ((line = reader.ReadLine()) != null){
                lineNumber++;

                if (string.IsNullOrEmpty(line) || line.StartsWith("MTH") || line.StartsWith("#")){
                    continue;
                }

                if (line.StartsWith(Section.Comment.Prefix)){
                    comParser.Parse(lineNumber, line, errorList);
                    commentMap.Add(lineNumber, comParser.getComment());
                    continue;
                }

                Section section = getSection(line);
                MZTabError error;
                if (section == null){
                    error = new MZTabError(FormatErrorType.LinePrefix, lineNumber, subString(line));
                    throw new MZTabException(error);
                }
                if (section.Level < highWaterMark){
                    Section currentSection = Section.FindSection(highWaterMark);
                    error = new MZTabError(LogicalErrorType.LineOrder, lineNumber, currentSection.Name, section.Name);
                    throw new MZTabException(error);
                }

                highWaterMark = section.Level;
                // There exists errors during checking metadata section.
                if (highWaterMark == 1 && ! errorList.IsNullOrEmpty()){
                    break;
                }

                switch (highWaterMark){
                    case 1:
                        // metadata section.
                        mtdParser.Parse(lineNumber, line, errorList);
                        break;
                    case 2:
                        if (prhParser != null){
                            // header line only display once!
                            error = new MZTabError(LogicalErrorType.HeaderLine, lineNumber, subString(line));
                            throw new MZTabException(error);
                        }

                        // protein header section
                        prhParser = new PRHLineParser(mtdParser.Metadata);
                        prhParser.Parse(lineNumber, line, errorList);
                        prtPositionMapping = new PositionMapping(prhParser.getFactory(), line);

                        // tell system to continue check protein data line.
                        highWaterMark = 3;
                        break;
                    case 3:
                        if (prhParser == null){
                            // header line should be check first.
                            error = new MZTabError(LogicalErrorType.NoHeaderLine, lineNumber, subString(line));
                            throw new MZTabException(error);
                        }

                        if (prtParser == null){
                            prtParser = new PRTLineParser(prhParser.getFactory(), prtPositionMapping, mtdParser.Metadata,
                                                          errorList);
                        }
                        prtParser.Parse(lineNumber, line, errorList);
                        proteinMap.Add(lineNumber, prtParser.getRecord(line));

                        break;
                    case 4:
                        if (pehParser != null){
                            // header line only display once!
                            error = new MZTabError(LogicalErrorType.HeaderLine, lineNumber, subString(line));
                            throw new MZTabException(error);
                        }

                        if (mtdParser.Metadata.MzTabType == MzTabType.Identification){
                            errorList.Add(new MZTabError(LogicalErrorType.PeptideSection, lineNumber, subString(line)));
                        }

                        // peptide header section
                        pehParser = new PEHLineParser(mtdParser.Metadata);
                        pehParser.Parse(lineNumber, line, errorList);
                        pepPositionMapping = new PositionMapping(pehParser.getFactory(), line);

                        // tell system to continue check peptide data line.
                        highWaterMark = 5;
                        break;
                    case 5:
                        if (pehParser == null){
                            // header line should be check first.
                            error = new MZTabError(LogicalErrorType.NoHeaderLine, lineNumber, subString(line));
                            throw new MZTabException(error);
                        }

                        if (pepParser == null){
                            pepParser = new PEPLineParser(pehParser.getFactory(), pepPositionMapping, mtdParser.Metadata,
                                                          errorList);
                        }
                        pepParser.Parse(lineNumber, line, errorList);
                        peptideMap.Add(lineNumber, pepParser.getRecord(line));

                        break;
                    case 6:
                        if (pshParser != null){
                            // header line only display once!
                            error = new MZTabError(LogicalErrorType.HeaderLine, lineNumber, subString(line));
                            throw new MZTabException(error);
                        }

                        // psm header section
                        pshParser = new PSHLineParser(mtdParser.Metadata);
                        pshParser.Parse(lineNumber, line, errorList);
                        psmPositionMapping = new PositionMapping(pshParser.getFactory(), line);

                        // tell system to continue check peptide data line.
                        highWaterMark = 7;
                        break;
                    case 7:
                        if (pshParser == null){
                            // header line should be check first.
                            error = new MZTabError(LogicalErrorType.NoHeaderLine, lineNumber, subString(line));
                            throw new MZTabException(error);
                        }

                        if (psmParser == null){
                            psmParser = new PSMLineParser(pshParser.getFactory(), psmPositionMapping, mtdParser.Metadata,
                                                          errorList);
                        }
                        psmParser.Parse(lineNumber, line, errorList);
                        psmMap.Add(lineNumber, psmParser.getRecord(line));

                        break;
                    case 8:
                        if (smhParser != null){
                            // header line only display once!
                            error = new MZTabError(LogicalErrorType.HeaderLine, lineNumber, subString(line));
                            throw new MZTabException(error);
                        }

                        // small molecule header section
                        smhParser = new SMHLineParser(mtdParser.Metadata);
                        smhParser.Parse(lineNumber, line, errorList);
                        smlPositionMapping = new PositionMapping(smhParser.getFactory(), line);

                        // tell system to continue check small molecule data line.
                        highWaterMark = 9;
                        break;
                    case 9:
                        if (smhParser == null){
                            // header line should be check first.
                            error = new MZTabError(LogicalErrorType.NoHeaderLine, lineNumber, subString(line));
                            throw new MZTabException(error);
                        }

                        if (smlParser == null){
                            smlParser = new SMLLineParser(smhParser.getFactory(), smlPositionMapping, mtdParser.Metadata,
                                                          errorList);
                        }
                        smlParser.Parse(lineNumber, line, errorList);
                        smallMoleculeMap.Add(lineNumber, smlParser.getRecord(line));

                        break;
                }
            }

            if (reader != null){
                reader.Close();
            }

            if (errorList.IsNullOrEmpty()){
                _mzTabFile = new MZTabFile(mtdParser.Metadata);
                foreach (int id in commentMap.Keys){
                    _mzTabFile.addComment(id, commentMap[id]);
                }

                if (prhParser != null){
                    MZTabColumnFactory proteinColumnFactory = prhParser.getFactory();
                    _mzTabFile.setProteinColumnFactory(proteinColumnFactory);
                    foreach (int id in proteinMap.Keys){
                        _mzTabFile.addProtein(id, proteinMap[id]);
                    }
                }

                if (pehParser != null){
                    MZTabColumnFactory peptideColumnFactory = pehParser.getFactory();
                    _mzTabFile.setPeptideColumnFactory(peptideColumnFactory);
                    foreach (int id in peptideMap.Keys){
                        _mzTabFile.addPeptide(id, peptideMap[id]);
                    }
                }

                if (pshParser != null){
                    MZTabColumnFactory psmColumnFactory = pshParser.getFactory();
                    _mzTabFile.setPSMColumnFactory(psmColumnFactory);
                    foreach (int id in psmMap.Keys){
                        _mzTabFile.addPSM(id, psmMap[id]);
                    }
                }

                if (smhParser != null){
                    MZTabColumnFactory smallMoleculeColumnFactory = smhParser.getFactory();
                    _mzTabFile.setSmallMoleculeColumnFactory(smallMoleculeColumnFactory);
                    foreach (int id in smallMoleculeMap.Keys){
                        _mzTabFile.addSmallMolecule(id, smallMoleculeMap[id]);
                    }
                }
            }
        }
 private MzTabType checkMZTabType(string defineLabel, string valueLabel)
 {
     try{
         return (MzTabType) Enum.Parse(typeof (MzTabType), valueLabel);
     }
     catch (ArgumentException){
         MZTabError error = new MZTabError(FormatErrorType.MZTabType, _lineNumber, Error_Header + defineLabel,
                                           valueLabel);
         throw new MZTabException(error);
     }
 }