content: /*
  * Copyright (c) 1997 - 2016
  * Actelion Pharmaceuticals Ltd.
  * Gewerbestrasse 16
  * CH-4123 Allschwil, Switzerland
  *
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
  * 1. Redistributions of source code must retain the above copyright notice, this
  *    list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
  * 3. Neither the name of the the copyright holder nor the
  *    names of its contributors may be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
  package com.actelion.research.gui.clipboard;
  
  import com.actelion.research.chem.*;
  import com.actelion.research.chem.coords.CoordinateInventor;
  import com.actelion.research.chem.dnd.ChemistryFlavors;
  import com.actelion.research.chem.io.RXNFileCreator;
  import com.actelion.research.chem.io.RXNFileParser;
  import com.actelion.research.chem.name.StructureNameResolver;
  import com.actelion.research.chem.reaction.Reaction;
  import com.actelion.research.chem.reaction.ReactionEncoder;
  import com.actelion.research.gui.clipboard.external.ChemDrawCDX;
  import com.actelion.research.gui.dnd.MoleculeTransferable;
  import com.actelion.research.gui.dnd.ReactionTransferable;
  import com.actelion.research.gui.generic.GenericRectangle;
  import com.actelion.research.gui.wmf.WMF;
  import com.actelion.research.gui.wmf.WMFGraphics2D;
  import com.actelion.research.util.Platform;
  import com.actelion.research.util.Sketch;
  
  import java.awt.*;
  import java.awt.datatransfer.DataFlavor;
  import java.awt.datatransfer.Transferable;
  import java.io.*;
  import java.util.ArrayList;
  
  /**
   * <p>Title: Actelion Library</p>
   * <p>Description: Actelion Java Library</p>
   * <p>Copyright: Copyright (c) 2002-2003</p>
   * <p>Company: Actelion Ltd</p>
   *
   * @author Thomas Sander, Christian Rufener
   * @version 1.0
   */
  public class ClipboardHandler implements IClipboardHandler
  {
  	private static final byte MDLSK[] = {(byte) 'M', (byte) 'D', (byte) 'L', (byte) 'S', (byte) 'K', 0, 0};
  
  	/**
  	 * Get one or more Molecule(s) from the Clipboard. On all platforms the first choice is a serialized StereoMolecule.
  	 * Further supported formats on Windows are: MDLSK,MDLCT,MDL_MOL,CF_ENHMETAFILE with embedded sketch.
  	 * If no supported format is found and the clipboard contains text, which can be interpreted as molfile, then the
  	 * corresponding molecule is returned. If the clipboard contains one or multiple SMILES, IUPAC name(s) or idcode(s),
  	 * then the corresponding molecule(s) is/are returned. These can be multiple if allowMultiple is true.
  	 * Otherwise, if a StructureNameResolver is present, then it tries to interpret the name(s) and returns the
  	 * corresponding molecules, which may be limited to a certain number.
  	 * @return Molecule found or null if no molecule present on the clipboard
  	 */
  	@Override
  	public ArrayList<StereoMolecule> pasteMolecules() {
  		return pasteMolecules(true, true, SmilesParser.SMARTS_MODE_GUESS);
  	}
  
  	/**
  	 * Get one Molecule from the Clipboard. On all platforms the first choice is a serialized StereoMolecule.
  	 * Further supported formats on Windows are: MDLSK,MDLCT,MDL_MOL,CF_ENHMETAFILE with embedded sketch.
  	 * If no supported format is found and the clipboard contains text, which can be interpreted as molfile,
  	 * SMILES (with SMARTS features), IUPAC name or idcode, then the corresponding molecule is returned.
  	 * Otherwise, if a StructureNameResolver is present, then it tries to interpret the name.
  	 * If the clipboard molecule has 3D coordinates, then new 2D-coords are invented and used instead.
  	 * @return Molecule found or null if no molecule present on the clipboard
  	 */
  	@Override
  	public StereoMolecule pasteMolecule() {
  		return pasteMolecule(true, SmilesParser.SMARTS_MODE_GUESS);
  	}
  
  	@Override
  	public StereoMolecule pasteMolecule(boolean prefer2D, int smartsMode) {
  		ArrayList<StereoMolecule> molList = pasteMolecules(prefer2D, false, smartsMode);
  		return molList.isEmpty() ? null : molList.get(0);
  	}
  
  	/**
  	 * Get one or more Molecule(s) from the Clipboard. On all platforms the first choice is a serialized StereoMolecule.
  	 * Further supported formats on Windows are: MDLSK,MDLCT,MDL_MOL,CF_ENHMETAFILE with embedded sketch.
  	 * If no supported format is found and the clipboard contains text, which can be interpreted as molfile, then the
  	 * corresponding molecule is returned. If the clipboard contains one or multiple SMILES, IUPAC name(s) or idcode(s),
  	 * then the corresponding molecule(s) is/are returned. These can be multiple if allowMultiple is true.
  	 * Otherwise, if a StructureNameResolver is present, then it tries to interpret the name(s) and returns the
  	 * corresponding molecules, which may be limited to a certain number.
  	 * @param prefer2D if true and if the clipboard molecule has 3D coordinates, then new 2D-coords are invented
  	 * @param allowMultiple whether multiple molecules may be generated from clipboard text, if no serialized mol or special molecule format present
  	 * @param smartsMode SmilesParser.SMARTS_MODE for parsing strings as SMILES, i.e. how SMARTS features are considered
  	 * @return list of molecules found or generated from SMILES, names, etc; empty list if no molecule present on the clipboard
  	 */
  	private ArrayList<StereoMolecule> pasteMolecules(boolean prefer2D, boolean allowMultiple, int smartsMode) {
  		ArrayList<StereoMolecule> molList = new ArrayList<>();
  
  		StereoMolecule mol = Platform.isWindows() ? pasteMoleculeWindowsNative(prefer2D) : pasteMoleculeLinux();
  		if (mol != null)
  			molList.add(mol);
  
  		if (molList.isEmpty()) {
  			// get StringFlavor from clipboard and try parsing it as idcode, molfile, smiles, or (if NameResolver exists) as name
  			Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
  			String text = null;
  			try {
                  text = (String)t.getTransferData(DataFlavor.stringFlavor);
  				}
  			catch (Exception ioe) {}
  			if (text != null) {
  				try {
  					mol = new MolfileParser().getCompactMolecule(text);
  					if (mol != null && mol.getAllAtoms() != 0)
  						molList.add(mol);
  					}
  				catch (Exception e) {}
  
  				ArrayList<String> unresolvedNameList = null;
  
  				if (molList.isEmpty()) {
  					boolean isFirstLine = true;
  					int column = -1;    // in case we have a TAB-delimited table with '[idcode]' tags, use first tagged column
  					BufferedReader reader = new BufferedReader(new StringReader(text));
  					try {
  						String line = reader.readLine();
  						while (line != null) {
  							line = line.trim();
  							if (isFirstLine) {
  								String[] header = line.split("\\t");
  								for (int i=0; i<header.length; i++) {
  									if (header[i].endsWith("[idcode]")) {
  										column = i;
  										break;
  									}
  								}
  								isFirstLine = false;
  								if (column != -1)
  									continue;
  							}
  							if (line.isEmpty())
  								continue;
  							try {
  								String idcode = line;
  								if (column != -1) {
  									String[] entry = line.split("\\t");
  									if (column < entry.length)
  										idcode = entry[column];
  								}
  								mol = new IDCodeParser(prefer2D).getCompactMolecule(idcode);
  							} catch (Exception e) {
  								mol = null;
  							}
  
  							if (mol == null || mol.getAllAtoms() == 0) {
  								mol = new StereoMolecule();
  								try {
  									new SmilesParser(smartsMode).parse(mol, line);
  								}
  								catch (Exception e) {
  									mol = null;
  								}
  							}
  
  							if (mol == null || mol.getAllAtoms() == 0)
  								mol = StructureNameResolver.resolveLocal(line);
  
  							if ((mol == null || mol.getAllAtoms() == 0) && !allowMultiple)
  								mol = StructureNameResolver.resolveRemote(line);
  
  							if (mol != null && mol.getAllAtoms() != 0) {
  								molList.add(mol);
  
  								if (!allowMultiple)
  									break;
  							}
  							else if (allowMultiple) {
  								if (unresolvedNameList == null)
  									unresolvedNameList = new ArrayList<>();
  								unresolvedNameList.add(line);
  							}
  
  							line = reader.readLine();
  						}
  					}
  					catch (IOException ioe) {}
  				}
  
  				if (unresolvedNameList != null && !unresolvedNameList.isEmpty()) {
  					String[] idcodes = StructureNameResolver.resolveRemote(unresolvedNameList.toArray(new String[0]));
  					for (String idcode:idcodes) {
  						try {
  							mol = new IDCodeParser(prefer2D).getCompactMolecule(idcode);
  							if (mol != null && mol.getAllAtoms() != 0)
  								molList.add(mol);
  						} catch (Exception e) {}
  					}
  				}
  			}
  		}
  
  		if (prefer2D) {
  			for (StereoMolecule m:molList) {
  				if (m.is3D()) {
  					m.ensureHelperArrays(Molecule.cHelperParities);    // to ensure stereo parities
  					new CoordinateInventor().invent(m);
  				}
  			}
  		}
  
  //		System.out.println("returned mol(s): " + molList.size());
  		return molList;
  	}
  
  	private StereoMolecule pasteMoleculeWindowsNative(boolean prefer2D) {
  		byte[] buffer;
  		StereoMolecule mol = null;
  
  		if ((buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_SERIALIZEMOLECULE)) != null) {
  			try {
  				ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(buffer));
  				Object o = is.readObject();
  				if (o instanceof StereoMolecule) {
  					mol = (StereoMolecule) o;
  				}
  				is.close();
  			} catch (Exception e) {
  				e.printStackTrace();
  				System.out.println("Parsing NC_SERIALIZEMOLECULE during clipboard paste: Exception " + e);
  			}
  		}
  		System.out.println("Mol is " + mol);
  		if (mol == null) {
  			if ((buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_CTAB)) != null
  					|| (buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_MOLFILE)) != null) {
  				MolfileParser p = new MolfileParser();
  				mol = new StereoMolecule();
  				if (!p.parse(mol, new String(buffer))) {
  					mol = null;
  					System.out.println("Error Parsing CTAB during clipboard paste");
  				}
  			}
  			if (mol == null) {
  				if ((buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_SKETCH)) != null
  						|| (buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_EMBEDDEDSKETCH)) != null) {
  					try {
  						mol = new StereoMolecule();
  						if (!Sketch.createMolFromSketchBuffer(mol, buffer)) {
  							mol = null;
  						}
  					} catch (IOException e) {
  						mol = null;
  						e.printStackTrace();
  						System.out.println("Parsing NC_SKETCH during clipboard paste: Exception " + e);
  					}
  				}
  			}
  		}
  		String clipboardText = null;
  		if (mol == null) {
  			if ((buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_IDCODE)) != null) {
  				clipboardText = new String(buffer);
  				try {
  					mol = new StereoMolecule();
  					IDCodeParser parser = new IDCodeParser(prefer2D);
  					parser.parse(mol,buffer);
  					if (mol.getAllAtoms() == 0)
  						mol = null;
  					else
  						System.out.printf("NC_IDCODE '%s' successfully interpreted as idcode\n",clipboardText);
  				} catch (Exception e) {
  					e.printStackTrace();
  					System.out.printf("NC_IDCODE '%s' could not be parsed: "+e+"\n", clipboardText);
  					mol = null;
  				}
  			}
  		}
  
  		return mol;
  	}
  
  	private StereoMolecule pasteMoleculeLinux() {
  		try {
  			Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
  			return (StereoMolecule)t.getTransferData(ChemistryFlavors.DF_SERIALIZED_MOLECULE);
  		} catch (Exception e) {}
  	return null;
  	}
  
  	/**
  	 * Get a Reaction from the Clipboard
  	 *
  	 * @return Reaction or null if no reaction present
  	 */
  	public Reaction pasteReaction() {
  		Reaction rxn = Platform.isWindows() ? pasteReactionWindowsNative() : pasteReactionLinux();
  
  		if (rxn == null) {
  			// get StringFlavor from clipboard and try parsing it as rxn-idcode, rxn-file, or reaction-smiles
  			Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
  			String text = null;
  			try {
  				text = (String)t.getTransferData(DataFlavor.stringFlavor);
  			}
  			catch (Exception ioe) {}
  			if (text != null) {
  				try {
  					rxn = ReactionEncoder.decode(text, true);
  					if (rxn != null && rxn.isEmpty())
  						rxn = null;
  					}
  				catch (Exception e) {}
  				if (rxn == null) {
  					try {
  						rxn = new RXNFileParser().getReaction(text);
  						if (rxn != null && rxn.isEmpty())
  							rxn = null;
  					}
  					catch (Exception e) {}
  				}
  				if (rxn == null) {
  					try {
  						rxn = new SmilesParser().parseReaction(text);
  						if (rxn != null && rxn.isEmpty())
  							rxn = null;
  					}
  					catch (Exception e) {}
  				}
  			}
  		}
  
  		return rxn;
  	}
  
  	public Reaction pasteReactionWindowsNative() {
  		byte[] buffer;
  		Reaction rxn = null;
  
  		if ((buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_SERIALIZEREACTION)) != null) {
  			try {
  				ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(buffer));
  				Object o = is.readObject();
  				if (o instanceof Reaction) {
  					rxn = (Reaction) o;
  				}
  				is.close();
  			} catch (Exception e) {
  				e.printStackTrace();
  				System.out.println("ClipboardHandler.pasteReaction(): Exception " + e);
  			}
  		} else if ((buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_CTAB)) != null) {
  			RXNFileParser p = new RXNFileParser();
  			rxn = new Reaction();
  			try {
  				if (!p.parse(rxn, new String(buffer)))
  					rxn = null;
  			} catch (Exception e) {
  				System.err.println("Error parsing Reaction Buffer " + e);
  				rxn = null;
  			}
  		} else if ((buffer = NativeClipboardAccessor.getClipboardData(NativeClipboardAccessor.NC_SKETCH)) != null) {
  			try {
  				rxn = new Reaction();
  				if (!Sketch.createReactionFromSketchBuffer(rxn, buffer)) {
  					rxn = null;
  				}
  			} catch (IOException e) {
  				rxn = null;
  			}
  		}
  		return rxn;
  	}
  
  	private Reaction pasteReactionLinux() {
  		try {
  			Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
  			return (Reaction)t.getTransferData(ChemistryFlavors.DF_SERIALIZED_REACTION);
  		} catch (Exception e) {}
  		return null;
  	}
  
  	public boolean copyMolecule(String molfile) {
  		StereoMolecule m = new StereoMolecule();
  		MolfileParser p = new MolfileParser();
  		p.parse(m, molfile);
  		return copyMolecule(m);
  	}
  
  
  	/**
  	 * Copies a molecule to the clipboard in various formats:
  	 * ENHMETAFILE with an embedded sketch
  	 * MDLSK Sketch
  	 * MDLCT MDL molfile
  	 */
  	public boolean copyMolecule(StereoMolecule mol) {
  		if (!Platform.isWindows()) {
  			MoleculeTransferable transferable = new MoleculeTransferable(mol);
  			Toolkit.getDefaultToolkit().getSystemClipboard().setContents(transferable, transferable);
  			return true;
  			}
  
  		// For now we keep the old handling for Windows...
  		boolean ok = false;
  		try {
  			StereoMolecule m = mol.getCompactCopy();
  			for (int atom=0; atom<m.getAllAtoms(); atom++)
  				m.setAtomMapNo(atom, 0, false);
  
  			byte buffer[] = Sketch.createSketchFromMol(m);
  
  			File temp = File.createTempFile("actnca", ".wmf");
  			temp.deleteOnExit();
  
  			String path = null;
  			if (writeMol2Metafile(temp, m, buffer))
  				path = temp.getAbsolutePath();
  
  			// Serialize to a byte array
  			System.out.println("CopyMolecule");
  			com.actelion.research.gui.clipboard.external.ChemDrawCDX cdx = new com.actelion.research.gui.clipboard.external.ChemDrawCDX();
  			byte[] cdbuffer = cdx.getChemDrawBuffer(m);
  
  			ByteArrayOutputStream bos = new ByteArrayOutputStream();
  			ObjectOutputStream out = new ObjectOutputStream(bos);
  			// Changed from m to mol, because writeMol2Metafile() may have scaled xy-coords of m,
  			// which is unacceptable for 3D molecules.
  			// If an application needs coordinate scaling, then this should be done after pasting. TLS 07Feb2016
  			out.writeObject(mol);
  			out.close();
  			bos.close();
  
  			ok = NativeClipboardAccessor.copyMoleculeToClipboard(path, cdbuffer, bos.toByteArray());
  
  			temp.delete();
  		} catch (IOException e) {
  			System.err.println("ClipboardHandler: Exception copying Molecule " + e);
  		}
  		return ok;
  	}
  
  
  	/**
  	 * Copies a reaction to the clipboard in various formats:
  	 * MDLSK Sketch
  	 * MDLCT MDL molfile
  	 */
  	public boolean copyReaction(Reaction r) {
  		if (!Platform.isWindows()) {
  			ReactionTransferable transferable = new ReactionTransferable(r);
  			Toolkit.getDefaultToolkit().getSystemClipboard().setContents(transferable, transferable);
  			return true;
  		}
  
  		// For now we keep the old handling for Windows...
  		boolean ok = false;
  		try {
  			ok = copyReactionToClipboard(null, r);
  		} catch (IOException e) {
  			System.err.println("ClipboardHandler: Exception Copying Reaction " + e);
  		}
  		return ok;
  	}
  
  	private Reaction makeRXNCopy(Reaction r)  {
  		Reaction rxn = new Reaction(r);
  		int mols = rxn.getMolecules();
  		for (int i = 0; i < mols; i++) {
  			rxn.getMolecule(i).ensureHelperArrays(Molecule.cHelperCIP);
  		}
  		return rxn;
  	}
  
  	/**
  	 * Copies a reaction to the clipboard in various formats:
  	 * CTAB with an embedded sketch
  	 * MDLSK Sketch
  	 * serialized
  	 */
  	public boolean copyReaction(String ctab) {
  		boolean ok = false;
  		try {
  			Reaction rxn = new Reaction();
  			RXNFileParser p = new RXNFileParser();
  			p.parse(rxn, ctab);
  			ok = copyReactionToClipboard(ctab, rxn);
  		} catch (Exception e) {
  			System.err.println("ClipboardHandler: Exception copying reaction " + e);
  		}
  		return ok;
  	}
  
  	private boolean copyReactionToClipboard(String ctab, Reaction rxn) throws IOException {
  		if (ctab == null) {
  			RXNFileCreator mc = new RXNFileCreator(rxn);
  			ctab = mc.getRXNfile();
  		}
  
  		ChemDrawCDX cdx = new com.actelion.research.gui.clipboard.external.ChemDrawCDX();
  		byte[] cdxBuffer = cdx.getChemDrawBuffer(rxn);
  
  		// Serialize to a byte array
  		System.out.println("copyReactionToClipboard");
  
  		ByteArrayOutputStream bos = new ByteArrayOutputStream();
  		ObjectOutputStream out = new ObjectOutputStream(bos);
  		out.writeObject(rxn);
  		out.close();
  		bos.close();
  
  		return NativeClipboardAccessor.copyReactionToClipboard(ctab.getBytes(), cdxBuffer, bos.toByteArray());
  	}
  
  	private boolean writeMol2Metafile(File temp, StereoMolecule m, byte[] sketch) {
  		boolean ok = false;
  		try {
  			ok = writeMol2Metafile(new FileOutputStream(temp), m, sketch);
  		} catch (Exception e) {
  			System.err.println("ClipboardHandler: Exception writing molfile " + e);
  			e.printStackTrace();
  		}
  		return ok;
  	}
  
  
  	private boolean writeMol2Metafile(OutputStream out, StereoMolecule m, byte[] sketch) throws IOException {
  		int w = 300;
  		int h = 200;
  		WMF wmf = new WMF();
  		WMFGraphics2D g = new WMFGraphics2D(wmf, w, h, Color.black, Color.white);
  
  		Depictor2D d = new Depictor2D(m);
  		d.updateCoords(g, new GenericRectangle(0, 0, w, h), AbstractDepictor.cModeInflateToMaxAVBL);
  		d.paint(g);
  
  		if (sketch != null) {
  			byte[] temp = new byte[MDLSK.length + sketch.length];
  			System.arraycopy(MDLSK, 0, temp, 0, MDLSK.length);
  			System.arraycopy(sketch, 0, temp, MDLSK.length, sketch.length);
  			wmf.escape(WMF.MFCOMMENT, temp);
  		}
  		wmf.writeWMF(out);
  		out.close();
  //		g.dispose();
  		return true;
  	}
  
  	public static boolean setClipBoardData(String format, byte[] buffer) {
  		if (Platform.isWindows()) {
  			return NativeClipboardAccessor.setClipBoardData(format,buffer);
  		} else
  			return false;
  	}
  
  	/**
  	 * Copy a windows enhance metafile to the Windows clipboard
  	 * @param data byte[]
  	 * @return boolean
  	 */
  	public static boolean copyMetaFile(byte []data) {
  		return Platform.isWindows() && setClipBoardData(NativeClipboardAccessor.NC_METAFILE, data);
  		}
  
  /*	private boolean writeRXN2Metafile(File temp, byte sketch[], Reaction m)
  	{
  		try {
  			return writeRXN2Metafile(new FileOutputStream(temp), sketch, m);
  		} catch (Exception e) {
  			System.err.println("Error writeRXN2Metafile " + e);
  			e.printStackTrace();
  			return false;
  		}
  	}
  */
  
  /*	private boolean writeRXN2Metafile(OutputStream out, byte sketch[], Reaction m) throws IOException
  	{
  		int w = 400;
  		int h = 300;
  		WMF wmf = new WMF();
  		WMFGraphics2D g = new WMFGraphics2D(wmf, w, h, Color.black, Color.white);
  		AbstractReactionDepictor d = new ReactionDepictor(m);
  		d.updateCoords(new GraphicsContext(g), 8, 8, w - 16, h - 16, AbstractDepictor.cModeInflateToMaxAVBL);
  		d.paint(new GraphicsContext(g));
  		if (sketch != null) {
  //			byte MDLSK[] = {(byte)'M',(byte)'D',(byte)'L',(byte)'S',(byte)'K',0,0};
  			byte temp[] = new byte[MDLSK.length + sketch.length];
  			System.arraycopy(MDLSK, 0, temp, 0, MDLSK.length);
  			System.arraycopy(sketch, 0, temp, MDLSK.length, sketch.length);
  			wmf.escape(WMF.MFCOMMENT, temp);
  		}
  		wmf.writeWMF(out);
  		out.close();
  		return true;
  	}
  */
  
  
  	/**
  	 * Copies an Image to the clipboard
  	 *
  	 * @param img Image to be copied
  	 * @return true on success
  	 */
  	public boolean copyImage(java.awt.Image img) {
  		return ImageClipboardHandler.copyImage(img);
  	}
  
  	public java.awt.Image pasteImage() {
  		return ImageClipboardHandler.pasteImage();
  	}
  
  	/**
  	 * @deprecated Use ImageClipboardHandler.pasteImage for consistency reasons
  	 */
  	public static Image getImage() {
  		return ImageClipboardHandler.pasteImage();
  	}
  
  	/**
  	 * @deprecated You may use ImageClipboardHandler.copyImage for consistency reasons
  	 */
  	public static void putImage(Image image) {
  		ImageClipboardHandler.copyImage(image);
  	}
  }
  