001/*
002 * Copyright 2020  nils.hoffmann.
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 de.isas.lipidomics.palinom.hmdb;
017
018import de.isas.lipidomics.domain.Adduct;
019import de.isas.lipidomics.domain.Fragment;
020import de.isas.lipidomics.domain.LipidAdduct;
021import de.isas.lipidomics.domain.LipidCategory;
022import de.isas.lipidomics.domain.LipidSpecies;
023import de.isas.lipidomics.palinom.HMDBBaseVisitor;
024import de.isas.lipidomics.palinom.HMDBParser;
025import de.isas.lipidomics.palinom.exceptions.ParseTreeVisitorException;
026import java.util.Arrays;
027import java.util.BitSet;
028import java.util.Optional;
029
030/**
031 * Base visitor implementation for the GoslinFragments grammar.
032 * 
033 * Overriding implementation of {@link HMDBBaseVisitor}. Creates
034 * {@link LipidAdduct} instances from the provided context.
035 *
036 * @see HmdbVisitorParser
037 * @author nils.hoffmann
038 */
039public class HmdbVisitorImpl extends HMDBBaseVisitor<LipidAdduct> {
040
041    /**
042     * Produces a LipidAdduct given the LipidContext.
043     * @throws ParseTreeVisitorException for structural or state-related issues
044     * while trying to process a parsing context.
045     * @throws RuntimeException
046     * @param ctx
047     * @return a LipidAdduct.
048     */
049    @Override
050    public LipidAdduct visitLipid(HMDBParser.LipidContext ctx) {
051        Optional<HMDBParser.Lipid_pureContext> categoryContext = Optional.ofNullable(ctx.lipid_pure());
052
053        LipidAdduct la = new LipidAdduct(categoryContext.map((cc) -> {
054            return new LipidVisitor().visitLipid_pure(cc);
055        }).orElse(LipidSpecies.NONE), Adduct.NONE, new Fragment(""));
056        return la;
057    }
058
059    private static class LipidVisitor extends HMDBBaseVisitor<LipidSpecies> {
060
061        @Override
062        public LipidSpecies visitLipid_pure(HMDBParser.Lipid_pureContext ctx) {
063            LipidSpecies lipid = null;
064            BitSet bs = new BitSet(5);
065            bs.set(LipidCategory.ST.ordinal(), ctx.lipid_class().st() != null);
066            bs.set(LipidCategory.GL.ordinal(), ctx.lipid_class().gl() != null);
067            bs.set(LipidCategory.FA.ordinal(), ctx.lipid_class().fatty_acid() != null);
068            bs.set(LipidCategory.GP.ordinal(), ctx.lipid_class().pl() != null);
069            bs.set(LipidCategory.SP.ordinal(), ctx.lipid_class().sl() != null);
070            final FattyAcylHelper faHelper = new FattyAcylHelper();
071            final MolecularSubspeciesFasHandler msfh = new MolecularSubspeciesFasHandler(faHelper);
072            final IsomericSubspeciesFasHandler isfh = new IsomericSubspeciesFasHandler(faHelper);
073            final StructuralSubspeciesFasHandler ssfh = new StructuralSubspeciesFasHandler(isfh, faHelper);
074            final IsomericSubspeciesLcbHandler islh = new IsomericSubspeciesLcbHandler(isfh, faHelper);
075            final StructuralSubspeciesLcbHandler sslh = new StructuralSubspeciesLcbHandler(ssfh, islh, faHelper);
076            final FattyAcylHandler faHandler = new FattyAcylHandler();
077            String lipidSuffix = "";
078            if (ctx.lipid_suffix() != null) {
079                lipidSuffix = ctx.lipid_suffix().getText();
080                throw new ParseTreeVisitorException("The lipid suffix '" + lipidSuffix + "' is currently unsupported. Please contact the developers at https://lifs.isas.de/support for assistance.");
081            }
082            LipidCategory contextCategory = LipidCategory.UNDEFINED;
083            switch (bs.cardinality()) {
084                case 0:
085                    throw new ParseTreeVisitorException("Parsing context did not contain content for any lipid category. Must contain exactly one of " + Arrays.toString(LipidCategory.values()));
086                case 1:
087                    contextCategory = LipidCategory.values()[bs.nextSetBit(0)];
088                    break;
089                default:
090                    throw new ParseTreeVisitorException("Parsing context contained content for more than one lipid category. Must contain exactly one of " + Arrays.toString(LipidCategory.values()));
091            }
092            switch (contextCategory) {
093                case ST:
094                    lipid = new SterolLipidHandler(
095                            msfh,
096                            ssfh,
097                            isfh,
098                            faHandler
099                    ).handle(ctx);
100                    break;
101                case GL:
102                    lipid = new GlyceroLipidHandler(
103                            msfh,
104                            ssfh,
105                            isfh,
106                            faHandler
107                    ).handle(ctx);
108                    break;
109                case FA:
110                    lipid = new FattyAcylHandler().handle(ctx);
111                    break;
112                case GP:
113                    lipid = new GlycerophosphoLipidHandler(
114                            msfh,
115                            ssfh,
116                            isfh,
117                            faHandler
118                    ).handle(ctx);
119                    break;
120                case SP:
121                    lipid = new SphingoLipidHandler(
122                            sslh,
123                            islh,
124                            faHandler
125                    ).handle(ctx);
126                    break;
127                default:
128                    throw new ParseTreeVisitorException("Unhandled contextCategory: " + contextCategory);
129            }
130            return lipid;
131        }
132    }
133}