001/*
002 * Copyright 2019 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.domain;
017
018import java.util.Map;
019import java.util.stream.Collectors;
020import lombok.Builder;
021import lombok.Data;
022import lombok.EqualsAndHashCode;
023
024/**
025 * This class summarizes the FA parts of a lipid, independent of its head group.
026 * Thus, it accounts the total number of carbon atoms, double bonds, the number
027 * of hydroxylations, the overall FA-headgroup bond type, e.g. PLASMANYL /
028 * PLASMENYL, if any of a lipid's FA chains has such a bond type, or ESTER or
029 * UNDEFINED for other cases.
030 *
031 * @author nils.hoffmann
032 */
033@Data
034@EqualsAndHashCode(callSuper = true)
035public class LipidSpeciesInfo extends FattyAcid {
036
037    private static final class None extends LipidSpeciesInfo {
038
039        private None() {
040            super(LipidLevel.UNDEFINED, "NONE", -1, 0, 0, 0, LipidFaBondType.UNDEFINED, false, ModificationsList.NONE);
041        }
042    }
043
044    /**
045     * Use this class to indicate that no lipid species info is available.
046     */
047    public static final LipidSpeciesInfo NONE = new LipidSpeciesInfo.None();
048
049    private final LipidLevel level;
050
051    /**
052     * Create a new LipidSpeciesInfo on the provided level.
053     *
054     * @param level the level of the species info.
055     * @param name the name, e.g. FA1 for the first FA.
056     * @param position the sn position. -1 if undefined or unknown.
057     * @param nCarbon the number of carbons in this FA.
058     * @param nHydroxy the number of hydroxyls on this FA.
059     * @param nDoubleBonds the number of double bonds in this FA.
060     * @param lipidFaBondType the bond type, e.g. ESTER.
061     * @param lcb true if this is a long-chain base, e.g. in a Ceramide.
062     * @param modifications optional modifications for this FA.
063     * @see LipidFaBondType
064     */
065    @Builder(builderMethodName = "lipidSpeciesInfoBuilder")
066    public LipidSpeciesInfo(LipidLevel level, String name, int position, int nCarbon, int nHydroxy, int nDoubleBonds, LipidFaBondType lipidFaBondType, boolean lcb, ModificationsList modifications) {
067        super(name, position, nCarbon, nHydroxy, nDoubleBonds, lipidFaBondType, lcb, modifications);
068        this.level = level;
069    }
070
071    /**
072     * Create a new LipidSpeciesInfo on the provided level.
073     *
074     * @param level the level of the species info.
075     * @param name the name, e.g. FA1 for the first FA.
076     * @param position the sn position. -1 if undefined or unknown.
077     * @param nCarbon the number of carbons in this FA.
078     * @param nHydroxy the number of hydroxyls on this FA.
079     * @param lipidFaBondType the bond type, e.g. ESTER.
080     * @param lcb true if this is a long-chain base, e.g. in a Ceramide.
081     * @param modifications optional modifications for this FA.
082     * @param nDoubleBonds the number of double bonds in this FA.
083     * @param doubleBondPositions double bond positions in this FA.
084     * @see LipidFaBondType
085     */
086    @Builder(builderMethodName = "lipidSubspeciesInfoBuilder", builderClassName = "LipidSubspeciesInfoBuilder")
087    public LipidSpeciesInfo(LipidLevel level, String name, int position, int nCarbon, int nHydroxy, LipidFaBondType lipidFaBondType, boolean lcb, ModificationsList modifications, int nDoubleBonds, Map<Integer, String> doubleBondPositions) {
088        super(name, position, nCarbon, nHydroxy, lipidFaBondType, lcb, modifications, nDoubleBonds, doubleBondPositions);
089        this.level = level;
090    }
091
092    /**
093     * Create a new LipidSpeciesInfo on the provided level. The name is inferred
094     * from the level.
095     *
096     * @param level the level of the species info.
097     * @param nCarbon the number of carbons in this FA.
098     * @param nHydroxy the number of hydroxyls on this FA.
099     * @param lipidFaBondType the bond type, e.g. ESTER.
100     */
101    public LipidSpeciesInfo(LipidLevel level, int nCarbon, int nHydroxy, int nDoubleBonds, LipidFaBondType lipidFaBondType) {
102        this(level, level.name(), -1, nCarbon, nHydroxy, nDoubleBonds, lipidFaBondType, false, ModificationsList.NONE);
103    }
104
105    @Override
106    public String buildSubstructureName(LipidLevel level) {
107        final StringBuilder sb = new StringBuilder();
108        sb.
109                append(getName()).
110                append(" ").
111                append(getNCarbon()).
112                append(":").
113                append(getNDoubleBonds());
114        if (getNHydroxy() > 0) {
115            sb.append(";").append(getNHydroxy());
116        }
117        if (!getModifications().isEmpty()) {
118            sb.append("(");
119            sb.append(getModifications().stream().map((t) -> {
120                return (t.getLeft() == -1 ? "" : t.getLeft()) + "" + t.getRight();
121            }).collect(Collectors.joining(",")));
122            sb.append(")");
123        }
124        return sb.toString();
125    }
126
127    /**
128     * Returns the element table for this species info adjusted for oxygen and
129     * hydrogen.
130     *
131     * @param numFa the number of fatty acyls to account for.
132     * @return the element table.
133     */
134    public ElementTable getElements(int numFa) {
135        ElementTable elements = super.getElements();
136        if (numFa > 0) {
137            elements.incrementBy(Element.ELEMENT_O, numFa - 1);
138            elements.decrementBy(Element.ELEMENT_H, numFa - 1);
139        }
140        return elements;
141    }
142}