/** * Copyright [2015] [Christian Loehnert] * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.ks.blogging.grav.posts; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import java.util.stream.Collectors; public class HeaderContainer implements Cloneable { private static final Logger log = LoggerFactory.getLogger(HeaderContainer.class); public static final String INDENTATION = " "; protected final String key; protected final int level; protected final Map<String, String> elements = new LinkedHashMap<>(); protected final List<HeaderContainer> childContainers = new ArrayList<>(); public HeaderContainer(String key, int level) { this.key = key; this.level = level; } public List<HeaderElement> getHeaderElements() { ArrayList<HeaderElement> retval = new ArrayList<>(); retval.addAll(elements.entrySet().stream().map(e -> new HeaderElement(e, this)).collect(Collectors.toList())); return retval; } public List<HeaderElement> getHeaderElementsRecursively() { List<HeaderElement> retval = getHeaderElements(); retval.addAll(childContainers.stream().map(e -> e.getHeaderElements()).reduce(new ArrayList<HeaderElement>(), (old, cur) -> { old.addAll(cur); return old; })); return retval; } public String getHeaderElement(String key) { return elements.get(key); } public HeaderContainer setHeaderElement(String key, String value) { elements.put(key, value); return this; } public HeaderContainer getOrCreateChildContainer(String key) { return childContainers.stream().filter(c -> c.getKey().equals(key)).findFirst().orElseGet(() -> { HeaderContainer container = new HeaderContainer(key, level + 1); childContainers.add(container); return container; }); } public String getKey() { return key; } protected void writeContent(StringBuilder builder) { if (key != null && !key.isEmpty()) { for (int i = 0; i < level - 1; i++) { builder.append(INDENTATION); } builder.append(key).append(":\n"); } for (Map.Entry<String, String> entry : elements.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); for (int i = 0; i < level; i++) { builder.append(INDENTATION); } builder.append(key); if (value.isEmpty()) { builder.append(":\n"); } else { builder.append(": ").append(value).append("\n"); } } for (HeaderContainer childContainer : childContainers) { childContainer.writeContent(builder); } // builder.append("\n"); } protected void readHeaderLines(ListIterator<String> headerLineIterator) { String lastIndentation = ""; while (headerLineIterator.hasNext()) { String headerLine = headerLineIterator.next(); String currentIndentation = StringUtils.remove(StringUtils.remove(headerLine, headerLine.trim()), "\n"); if (!lastIndentation.isEmpty() && !currentIndentation.equals(lastIndentation)) { headerLineIterator.previous(); return; } headerLine = headerLine.trim(); if (!headerLine.isEmpty()) { int split = headerLine.indexOf(':'); if (split == -1) { continue; } if (headerLine.trim().startsWith("#")) { continue; } String key = headerLine.substring(0, split); int startValue = split + 1; if (startValue < headerLine.length()) { String value = headerLine.substring(startValue).trim(); elements.put(key, value); log.debug("Found tag {}, with value {}", key, value); } else { HeaderContainer container = new HeaderContainer(key, level + 1); container.readHeaderLines(headerLineIterator); childContainers.add(container); log.debug("Found new child-container {} in level {}.", key, level + 1); } } lastIndentation = currentIndentation; } } public void fillFrom(HeaderContainer other) { other.elements.forEach((key, value) -> { if (elements.get(key) == null) { elements.put(key, value); } }); other.childContainers.forEach(otherChild -> { HeaderContainer childContainer = getOrCreateChildContainer(otherChild.key); if (childContainer == null) { childContainers.add(otherChild.clone()); } else { childContainer.fillFrom(otherChild); } }); } @Override public HeaderContainer clone() { HeaderContainer clone = new HeaderContainer(key, level); elements.forEach(clone.elements::put); childContainers.forEach(cc -> clone.childContainers.add(cc.clone())); return clone; } public List<HeaderContainer> getChildContainers() { return childContainers; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof HeaderContainer)) { return false; } HeaderContainer that = (HeaderContainer) o; if (level != that.level) { return false; } return !(key != null ? !key.equals(that.key) : that.key != null); } @Override public int hashCode() { int result = key != null ? key.hashCode() : 0; result = 31 * result + level; return result; } }