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 de.isas.lipidomics.palinom.exceptions.ConstraintViolationException; 019import java.util.Collections; 020import java.util.LinkedHashMap; 021import java.util.Map; 022import java.util.Optional; 023import java.util.stream.Collectors; 024import lombok.Builder; 025import lombok.Data; 026import lombok.EqualsAndHashCode; 027import lombok.extern.slf4j.Slf4j; 028 029/** 030 * A molecular subspecies. Child of LipidSpecies. Individual FAs are known, but 031 * neither their sn positions nor double bond positions. 032 * 033 * Example: Phosphatidylinositol (8:0-8:0) or PI(8:0-8:0) 034 * 035 * @author nils.hoffmann 036 * @see LipidSpecies 037 */ 038@Slf4j 039@Data 040@EqualsAndHashCode(callSuper = true) 041public class LipidMolecularSubspecies extends LipidSpecies { 042 043 protected final Map<String, FattyAcid> fa = new LinkedHashMap<>(); 044 045 @Builder 046 public LipidMolecularSubspecies(HeadGroup headGroup, FattyAcid... fa) { 047 super(headGroup); 048 int nCarbon = 0; 049 int nHydroxyl = 0; 050 int nDoubleBonds = 0; 051 ModificationsList mods = new ModificationsList(); 052 for (FattyAcid fas : fa) { 053// if (fas.getPosition() != -1) { 054// throw new ConstraintViolationException("MolecularFattyAcid " + fas.getName() + " must have position set to -1! Was: " + fas.getPosition()); 055// } 056 if (this.fa.containsKey(fas.getName())) { 057 throw new ConstraintViolationException( 058 "FA names must be unique! FA with name " + fas.getName() + " was already added!"); 059 } else { 060 this.fa.put(fas.getName(), fas); 061 nCarbon += fas.getNCarbon(); 062 nHydroxyl += fas.getNHydroxy(); 063 nDoubleBonds += fas.getNDoubleBonds(); 064 mods.addAll(fas.getModifications()); 065 } 066 067 } 068 super.info = Optional.of(LipidSpeciesInfo.lipidSpeciesInfoBuilder(). 069 level(LipidLevel.MOLECULAR_SUBSPECIES). 070 name(headGroup.getName()). 071 position(-1). 072 nCarbon(nCarbon). 073 nHydroxy(nHydroxyl). 074 nDoubleBonds(nDoubleBonds). 075 lipidFaBondType(LipidFaBondType.getLipidFaBondType(headGroup, fa)). 076 modifications(mods). 077 build() 078 ); 079 } 080 081 @Override 082 public Map<String, FattyAcid> getFa() { 083 return Collections.unmodifiableMap(fa); 084 } 085 086 protected String getHeadGroupSuffix() { 087 String hgToFaSep = " "; 088 if (isEtherLipid()) { 089 hgToFaSep = " O-"; 090 } 091 return hgToFaSep; 092 } 093 094 protected StringBuilder buildSubspeciesHeadGroupString(String headGroup, boolean normalizeHeadGroup) { 095 StringBuilder lipidString = new StringBuilder(); 096 lipidString.append(getHeadGroup().getLipidClass().map((lclass) -> { 097 switch (lclass) { 098// case SE: 099 case SE_27_1: 100 case SE_27_2: 101 case SE_28_2: 102 case SE_28_3: 103 case SE_29_2: 104 case SE_30_2: 105 if (!getFa().isEmpty()) { 106 return (normalizeHeadGroup ? headGroup : getNormalizedHeadGroup()) + getHeadGroupSuffix().trim() + "/"; 107 } 108 } 109 return headGroup + (getFa().isEmpty() ? "" : getHeadGroupSuffix()); 110 }).orElse(headGroup + (getFa().isEmpty() ? "" : getHeadGroupSuffix()))); 111 return lipidString; 112 } 113 114 protected String buildLipidSubspeciesName(LipidLevel level, String faSeparator, String headGroup, boolean isNormalized) { 115 StringBuilder sb = new StringBuilder(); 116 String faStrings = getFa().values().stream().map((fa) -> { 117 return fa.buildSubstructureName(level); 118 }).collect(Collectors.joining(faSeparator)); 119 return sb.append(buildSubspeciesHeadGroupString(headGroup, isNormalized) 120 ).append(faStrings).toString(); 121 } 122 123 @Override 124 public String getLipidString(LipidLevel level) { 125 return this.getLipidString(level, false); 126 } 127 128 @Override 129 public String getLipidString(LipidLevel level, boolean normalizeHeadGroup) { 130 String headGroup = normalizeHeadGroup ? getNormalizedHeadGroup() : getHeadGroup().getName(); 131 switch (level) { 132 case MOLECULAR_SUBSPECIES: 133 return buildLipidSubspeciesName(level, "-", headGroup, normalizeHeadGroup); 134 case CATEGORY: 135 case CLASS: 136 case SPECIES: 137 return super.getLipidString(level, normalizeHeadGroup); 138 default: 139 LipidLevel thisLevel = getInfo().orElse(LipidSpeciesInfo.NONE).getLevel(); 140 throw new ConstraintViolationException(getClass().getSimpleName() + " can not create a string for lipid with level " + thisLevel + " for level " + level + ": target level is more specific than this lipid's level!"); 141 } 142 } 143 144 @Override 145 public String getNormalizedLipidString() { 146 return getLipidString(getInfo().orElse(LipidSpeciesInfo.NONE).getLevel(), true); 147 } 148 149 @Override 150 public boolean validate() { 151 return true; 152 } 153 154 @Override 155 public String toString() { 156 return getLipidString(); 157 } 158 159}