package de.lmu.ifi.dbs.elki.visualization.css;

import java.util.HashMap;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;


/**
 * Manager class to track CSS classes used in a particular SVG document.
 * 
 * @author Erich Schubert
 */
public class CSSClassManager extends HashMap<String, CSSClass> {
  /**
   * Serial version.
   */
  private static final long serialVersionUID = 8807736974456191901L;

  /**
   * Add a single class to the map.
   * 
   * @param clss
   * @return existing (old) class
   * @throws CSSNamingConflict when a class of the same name but different owner object exists.
   */
  public CSSClass addClass(CSSClass clss) throws CSSNamingConflict {
    CSSClass existing = super.get(clss.getName());
    if (existing != null && existing.getOwner() != null && existing.getOwner() != clss.getOwner()) {
      throw new CSSNamingConflict("CSS class naming conflict between "+clss.getOwner().toString()+" and "+existing.getOwner().toString());
    }
    return super.put(clss.getName(), clss);
  }
  
  /**
   * Check if a name is already used in the classes.
   * 
   * @param name
   * @return true if the class name is already used.
   */
  public boolean contains(String name) {
    return containsKey(name);
  }

  /**
   * Serialize managed CSS classes to rule file.
   * 
   * @param buf String buffer
   */
  public void serialize(StringBuffer buf) {
    for (CSSClass clss : values()) {
      clss.appendCSSDefinition(buf);
    }
  }
  
  /**
   * Class to signal a CSS naming conflict.
   * 
   */
  public class CSSNamingConflict extends Exception {
    /**
     * Serial version UID
     */
    private static final long serialVersionUID = 4163822727195636747L;
    
    /**
     * Exception to signal a CSS naming conflict.
     * 
     * @param msg Exception message
     */
    public CSSNamingConflict(String msg) {
      super(msg);
    }
  }

  /**
   * Update the text contents of an existing style element.
   * 
   * @param document Document element (factory)
   * @param style Style element
   */
  public void updateStyleElement(Document document, Element style) {
    StringBuffer buf = new StringBuffer();
    serialize(buf);
    Text cont = document.createTextNode(buf.toString());
    while (style.hasChildNodes()) {
      style.removeChild(style.getFirstChild());
    }
    style.appendChild(cont);    
  }
  
  /**
   * Make a (filled) CSS style element for the given document.
   * 
   * @param document Document
   * @return Style element
   */
  public Element makeStyleElement(Document document) {
    Element style = SVGUtil.makeStyleElement(document);
    updateStyleElement(document, style);
    return style;
  }
}

@@ -41,16 +41,45 @@
 n.css;%0A%0A
+import java.util.Collection;%0A
 import j
@@ -380,43 +380,139 @@
 ger 
-extends HashMap%3CString, CSSClass%3E %7B
+%7B%0A  /**%0A   * Store the contained CSS classes.%0A   */%0A  private HashMap%3CString, CSSClass%3E store = new HashMap%3CString, CSSClass%3E();%0A  
 %0A  /
@@ -906,20 +906,20 @@
 ting = s
-uper
+tore
 .get(cls
@@ -1190,20 +1190,20 @@
 return s
-uper
+tore
 .put(cls
@@ -1422,16 +1422,22 @@
  return 
+store.
 contains
@@ -1618,16 +1618,22 @@
  clss : 
+store.
 values()
@@ -1688,24 +1688,930 @@
  %7D%0A  %0A  /**%0A
+   * Get all CSS classes in this manager.%0A   * %0A   * @return CSS classes.%0A   */%0A  public Collection%3CCSSClass%3E getClasses() %7B%0A    return store.values();%0A  %7D%0A  %0A  /**%0A   * Check compatibility%0A   */%0A  public boolean testMergeable(CSSClassManager other) %7B%0A    for (CSSClass clss : other.getClasses()) %7B%0A      CSSClass existing = store.get(clss.getName());%0A      // Check for a naming conflict.%0A      if (existing != null && existing.getOwner() != null && clss.getOwner() != null && existing.getOwner() != clss.getOwner()) %7B%0A        return false;%0A      %7D%0A    %7D%0A    return true;%0A  %7D%0A  %0A  /**%0A   * Merge CSS classes, for example to merge two plots.%0A   * %0A   * @throws CSSNamingConflict If there is a naming conflict.%0A   */%0A  public boolean mergeCSSFrom(CSSClassManager other) throws CSSNamingConflict %7B%0A    for (CSSClass clss : other.getClasses()) %7B%0A      this.addClass(clss);%0A    %7D%0A    return true;%0A  %7D%0A  %0A  /**%0A
    * Class t

Add support for merging CSS classes from another CSS Class Manager.