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