001/* 
002 * Copyright 2018 Leibniz-Institut für Analytische Wissenschaften – ISAS – e.V..
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package uk.ac.ebi.pride.jmztab2.utils.parser;
017
018import de.isas.mztab2.model.Assay;
019import de.isas.mztab2.model.Metadata;
020import de.isas.mztab2.model.Parameter;
021import de.isas.mztab2.model.StudyVariable;
022import java.util.*;
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025import uk.ac.ebi.pride.jmztab2.model.IMZTabColumn;
026import uk.ac.ebi.pride.jmztab2.model.ISmallMoleculeColumn;
027import uk.ac.ebi.pride.jmztab2.model.MZTabColumnFactory;
028import uk.ac.ebi.pride.jmztab2.model.MZTabConstants;
029import uk.ac.ebi.pride.jmztab2.model.Section;
030import uk.ac.ebi.pride.jmztab2.model.SmallMoleculeColumn;
031import uk.ac.ebi.pride.jmztab2.model.SmallMoleculeColumn.Stable;
032import uk.ac.ebi.pride.jmztab2.utils.errors.FormatErrorType;
033import uk.ac.ebi.pride.jmztab2.utils.errors.LogicalErrorType;
034import uk.ac.ebi.pride.jmztab2.utils.errors.MZTabError;
035import uk.ac.ebi.pride.jmztab2.utils.errors.MZTabErrorList;
036import uk.ac.ebi.pride.jmztab2.utils.errors.MZTabException;
037
038/**
039 * Parse and validate Small Molecule header line into a {@link uk.ac.ebi.pride.jmztab2.model.MZTabColumnFactory}.
040 *
041 * @author qingwei
042 * @author ntoro
043 * @author nilshoffmann
044 * @since 10/02/13
045 * 
046 */
047public class SMHLineParser extends MZTabHeaderLineParser {
048
049    private static final Logger LOGGER = LoggerFactory.getLogger(SMHLineParser.class);
050    private Map<Integer, String> physPositionToOrder;
051
052
053    /**
054     * <p>Constructor for SMHLineParser.</p>
055     *
056     * @param context a {@link uk.ac.ebi.pride.jmztab2.utils.parser.MZTabParserContext} object.
057     * @param metadata a {@link de.isas.mztab2.model.Metadata} object.
058     */
059    public SMHLineParser(MZTabParserContext context, Metadata metadata) {
060        super(context, MZTabColumnFactory.getInstance(Section.Small_Molecule_Header), metadata);
061    }
062
063    /** {@inheritDoc} */
064    @Override
065    protected int parseColumns() throws MZTabException {
066        String header;
067        Integer physicalPosition;
068
069        ISmallMoleculeColumn column;
070        SortedMap<String, IMZTabColumn> columnMapping = factory.getColumnMapping();
071        SortedMap<String, IMZTabColumn> optionalMapping = factory.getOptionalColumnMapping();
072        SortedMap<String, IMZTabColumn> stableMapping = factory.getStableColumnMapping();
073
074        physPositionToOrder = generateHeaderPhysPositionToOrderMap(items);
075
076        //Iterates through the tokens in the protein header
077        //It will identify the type of column and the position accordingly
078        for (physicalPosition = 1; physicalPosition < items.length; physicalPosition++) {
079
080            column = null;
081            header = items[physicalPosition];
082            if (header.startsWith(MZTabConstants.ABUNDANCE_PREFIX)) {
083                checkAbundanceColumns(physicalPosition, physPositionToOrder.get(physicalPosition));
084            } else if (header.startsWith(MZTabConstants.OPT_PREFIX)) {
085                checkOptColumnName(header);
086            } else {
087                try {
088                    column = SmallMoleculeColumn.Stable.columnFor(header);
089                } catch(IllegalArgumentException iae) {
090                    throw new MZTabException(new MZTabError(LogicalErrorType.ColumnNotValid,lineNumber,header,section.getName()));
091                }
092            }
093
094            if (column != null) {
095                if (!column.getOrder().equals(physPositionToOrder.get(physicalPosition))) {
096                    column.setOrder(physPositionToOrder.get(physicalPosition));
097                    LOGGER.debug(column.toString());
098                }
099                if(column.isOptional()){
100                    optionalMapping.put(column.getLogicPosition(), column);
101                } else {
102                    stableMapping.put(column.getLogicPosition(), column);
103                }
104                columnMapping.put(column.getLogicPosition(), column);
105            }
106        }
107        return physicalPosition;
108    }
109
110    private Map<Integer, String> generateHeaderPhysPositionToOrderMap(String[] items) {
111        Integer physicalPosition;
112        Map<Integer, String> physicalPositionToOrder = new LinkedHashMap<>();
113        int order = 0;
114
115        for (physicalPosition = 1; physicalPosition < items.length; physicalPosition++) {
116            if(physicalPositionToOrder.containsKey(physicalPosition)) {
117                throw new IllegalArgumentException("Physical position "+physicalPosition+" for item "+items[physicalPosition-1]+" is already assigned!");
118            }
119            physicalPositionToOrder.put(physicalPosition, fromIndexToOrder(++order));
120        }
121        return physicalPositionToOrder;
122    }
123
124    /**
125     * {@inheritDoc}
126     *
127     * The following optional columns are mandatory:
128     * 1. abundance_assay[1-n]
129     * 2. abundance_study_variable[1-m]
130     * 3. abundance_variation_study_variable[1-m]
131     * 
132     * NOTICE: this method will be called at end of parse() function.
133     * @see MZTabHeaderLineParser#parse(int, String, MZTabErrorList)
134     * @see MZTabHeaderLineParser#parse(int, String, MZTabErrorList)
135     */
136    @Override
137    protected void refine() throws MZTabException {
138
139        for (Stable columnHeader : SmallMoleculeColumn.Stable.values()) {
140            ISmallMoleculeColumn smc = Stable.columnFor(columnHeader);
141            if (factory.findColumnByHeader(smc.getHeader()) == null) {
142                throw new MZTabException(new MZTabError(FormatErrorType.StableColumn, lineNumber, smc.getHeader()));
143            }
144        }
145
146        Parameter smallMoleculeQuantificationUnit = Optional.ofNullable(metadata.getSmallMoleculeQuantificationUnit()).orElseThrow(() ->
147            new MZTabException(new MZTabError(LogicalErrorType.NoSmallMoleculeQuantificationUnit, lineNumber)));
148
149        if (metadata.getSmallMoleculeIdentificationReliability() == null) {
150            throw new MZTabException(new MZTabError(LogicalErrorType.NoSmallMoleculeIdentificationReliability, lineNumber));
151        }
152        for (StudyVariable studyVariable : metadata.getStudyVariable()) {
153            String svLabel = "_"+Metadata.Properties.studyVariable+"[" + studyVariable.getId() + "]";
154            refineOptionalColumn(Section.Small_Molecule_Header, "abundance" + svLabel);
155            refineOptionalColumn(Section.Small_Molecule_Header, "abundance_variation" + svLabel);
156        }
157        for (Assay assay : metadata.getAssay()) {
158            String assayLabel = "_"+Metadata.Properties.assay+"[" + assay.getId() + "]";
159            refineOptionalColumn(Section.Small_Molecule_Header, "abundance" + assayLabel);
160        }
161    }
162}