content: package com.abstratt.mdd.modelrenderer.dot;
  
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.io.StringWriter;
  import java.net.URI;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Map.Entry;
  
  import org.apache.commons.io.FilenameUtils;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.emf.ecore.EObject;
  import org.eclipse.emf.ecore.resource.Resource;
  import org.eclipse.emf.ecore.resource.ResourceSet;
  import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
  
  import com.abstratt.mdd.modelrenderer.IRendererSelector;
  import com.abstratt.mdd.modelrenderer.IRenderingSession;
  import com.abstratt.mdd.modelrenderer.IRenderingSettings;
  import com.abstratt.mdd.modelrenderer.IndentedPrintWriter;
  import com.abstratt.mdd.modelrenderer.RenderingSession;
  import com.abstratt.mdd.modelrenderer.RenderingUtils;
  import com.abstratt.pluginutils.LogUtils;
  
  public class DOTRendering implements DOTRenderingConstants {
      private static final String ID = DOTRendering.class.getPackage().getName();
  
      public static byte[] generateDOTFromModel(URI modelURI, IRendererSelector<? extends EObject> selector,
              IRenderingSettings settings) throws CoreException {
          return generateDOTFromModel(modelURI, selector, settings, new HashMap<String, Map<String, Object>>());
      }
  
      public static byte[] generateDOTFromModel(URI modelURI, IRendererSelector<? extends EObject> selector,
              IRenderingSettings settings, Map<String, Map<String, Object>> defaultDotSettings) throws CoreException {
          org.eclipse.emf.common.util.URI emfURI = org.eclipse.emf.common.util.URI.createURI(modelURI.toASCIIString());
          ResourceSet resourceSet = new ResourceSetImpl();
          Resource resource = resourceSet.createResource(emfURI);
          try {
              // TODO cache option map and use XMLResource constants (requires
              // dependency change)
              Map<String, Object> resourceOptions = new HashMap<String, Object>();
              resourceOptions.put("DISABLE_NOTIFY", Boolean.TRUE);
              resource.load(resourceOptions);
              Collection<EObject> contents = resource.getContents();
              return generateDOTFromModel(modelURI, contents, selector, settings, defaultDotSettings);
          } catch (FileNotFoundException e) {
              // file was deleted before we could read it - that is alright, don't
              // make a fuss
              return null;
          } catch (IOException e) {
              throw new CoreException(new Status(IStatus.ERROR, ID, "", e));
          } catch (RuntimeException e) {
              // invalid file formats might cause runtime exceptions
              throw new CoreException(new Status(IStatus.ERROR, ID, "", e));
          } finally {
              try {
                  unloadResources(resourceSet);
              } catch (RuntimeException re) {
                  logUnexpected("Unloading resources", re);
              }
          }
  
      }
  
      public static byte[] generateDOTFromModel(URI modelURI, Collection<EObject> modelContents,
              IRendererSelector<? extends EObject> selector, IRenderingSettings settings,
              Map<String, Map<String, Object>> defaultDotSettings) throws CoreException {
  
          StringWriter sw = new StringWriter();
          IndentedPrintWriter out = new IndentedPrintWriter(sw);
          IRenderingSession session = new RenderingSession(selector, settings, out);
          String modelName = FilenameUtils.removeExtension(FilenameUtils.getName(modelURI.getPath()));
          printPrologue(modelName, defaultDotSettings, out);
          boolean anyRendered = RenderingUtils.renderAll(session, modelContents);
          if (!anyRendered) {
              out.println("NIL [ label=\"No objects selected for rendering\"]");
          }
          printEpilogue(out);
          out.close();
          byte[] dotContents = sw.getBuffer().toString().getBytes();
          if (Boolean.getBoolean(ID + ".showDOT")) {
              LogUtils.log(IStatus.INFO, ID, "DOT output for " + modelURI, null);
              LogUtils.log(IStatus.INFO, ID, sw.getBuffer().toString(), null);
          }
          if (Boolean.getBoolean(ID + ".showMemory"))
              System.out.println("*** free: " + toMB(Runtime.getRuntime().freeMemory()) + " / total: "
                      + toMB(Runtime.getRuntime().totalMemory()) + " / max: " + toMB(Runtime.getRuntime().maxMemory()));
          return dotContents;
      }
  
      private static void printEpilogue(IndentedPrintWriter w) {
          w.exitLevel();
          w.println();
          w.println("}"); //$NON-NLS-1$
      }
  
      private static void printPrologue(String modelName, Map<String, Map<String, Object>> defaultDotSettings,
              IndentedPrintWriter w) {
          w.println("graph " + modelName + " {");
          w.enterLevel();
          DOTRenderingUtils.addAttribute(w, "sep", "+0.15");
      	DOTRenderingUtils.addAttribute(w, "K", "0.2");
      	DOTRenderingUtils.addAttribute(w, "overlap", false);
          dumpDotSettings(w, defaultDotSettings.get(DOTRenderingConstants.GLOBAL_SETTINGS_KEY));
          w.println("graph [");
          
          w.runInNewLevel(() -> {
  	        dumpDotSettings(w, defaultDotSettings.get(DOTRenderingConstants.GRAPH_SETTINGS_KEY));
          });
          w.println("]");
          w.println("node [");
          w.runInNewLevel(() -> {
              DOTRenderingUtils.addAttribute(w, "width", "1.5");
  	        DOTRenderingUtils.addAttribute(w, "fontsize", 11);
  	        DOTRenderingUtils.addAttribute(w, "shape", "plaintext");
  	        dumpDotSettings(w, defaultDotSettings.get(DOTRenderingConstants.NODE_SETTINGS_KEY));
          });
          w.println("]");
          w.println("edge [");
          w.runInNewLevel(() -> {
          	DOTRenderingUtils.addAttribute(w, "fontsize", 9);
          	DOTRenderingUtils.addAttribute(w, "dir", "both");
          	dumpDotSettings(w, defaultDotSettings.get(DOTRenderingConstants.EDGE_SETTINGS_KEY));
          });
          w.println("]");
      }
  
      private static void dumpDotSettings(IndentedPrintWriter w, Map<String, Object> map) {
          if (map == null)
              return;
          for (Entry<String, Object> entry : map.entrySet()) {
              if (entry.getValue() instanceof Integer)
                  DOTRenderingUtils.addAttribute(w, entry.getKey(), (int) (Integer) entry.getValue());
              else
                  DOTRenderingUtils.addAttribute(w, entry.getKey(), entry.getValue().toString());
          }
      }
  
      private static void unloadResources(ResourceSet resourceSet) {
          for (Resource current : resourceSet.getResources())
              current.unload();
      }
  
      public static void logUnexpected(String message, Exception e) {
          LogUtils.logError(ID, message, e);
      }
  
      private static String toMB(long byteCount) {
          return byteCount / (1024 * 1024) + "MB";
      }
  }
  