diff --git a/uk/ac/sanger/artemis/io/GffToEMBL.java b/uk/ac/sanger/artemis/io/GffToEMBL.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b2825c7643fd35605ecc1b35ed2d4a5beccac1e
--- /dev/null
+++ b/uk/ac/sanger/artemis/io/GffToEMBL.java
@@ -0,0 +1,287 @@
+/* 
+ * This file is part of Artemis
+ *
+ * Copyright(C) 2013  Genome Research Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or(at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+package uk.ac.sanger.artemis.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Vector;
+
+import javax.swing.JOptionPane;
+
+import uk.ac.sanger.artemis.EntryGroup;
+import uk.ac.sanger.artemis.Options;
+import uk.ac.sanger.artemis.SimpleEntryGroup;
+import uk.ac.sanger.artemis.sequence.NoSequenceException;
+import uk.ac.sanger.artemis.util.Document;
+import uk.ac.sanger.artemis.util.DocumentFactory;
+import uk.ac.sanger.artemis.util.FileDocument;
+import uk.ac.sanger.artemis.util.OutOfRangeException;
+import uk.ac.sanger.artemis.util.ReadOnlyException;
+
+class GffToEMBL
+{
+  /**
+   * Convert GFF to EMBL
+   * @param inGff
+   * @param outDir
+   * @param emblSubmission
+   * @param flatten
+   * @param gzip
+   */
+  public GffToEMBL(final String inGff, 
+                   final String outDir, 
+                   final boolean emblSubmission,
+                   final boolean flatten,
+                   final boolean gzip)
+  {
+    final Entry entry = getEntry(inGff);
+    if(entry == null || !(entry instanceof GFFDocumentEntry) )
+    {
+      JOptionPane.showMessageDialog(null, 
+          "No GFF entry found.", "Error", JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    
+    EntryGroup egrp = null;
+    try
+    {
+      uk.ac.sanger.artemis.Entry artEntry = new  uk.ac.sanger.artemis.Entry(entry);
+      egrp = new SimpleEntryGroup(artEntry.getBases());
+      egrp.add(artEntry);
+    }
+    catch (OutOfRangeException e)
+    {
+      e.printStackTrace();
+    }
+    catch (NoSequenceException e) {} // no sequence
+
+
+    if(egrp == null) // no sequence found
+    {
+      final FeatureVector features = entry.getAllFeatures();
+      final HashSet<String> seqNames = new HashSet<String>();
+      for(Feature f: features)
+        seqNames.add(((GFFStreamFeature)f).getGffSeqName());
+      
+      for(String seq: seqNames)
+      {
+        Entry newEntry = getEntryForSeqName(seq, features);
+        writeEMBL(newEntry, seq, outDir, emblSubmission, flatten, gzip);
+      }
+    }
+    else
+    {
+      writeEMBL(entry, entry.getName(), outDir, emblSubmission, flatten, gzip);
+    }
+  }
+
+  /**
+   * Write EMBL file
+   * @param entry
+   * @param seqName
+   * @param outDir
+   * @param emblSubmission
+   * @param gzip
+   */
+  private void writeEMBL(
+      final Entry entry,
+      final String seqName,
+      final String outDir,
+      final boolean emblSubmission,
+      final boolean flatten,
+      final boolean gzip)
+  {
+    final EntryInformation entryInfo;
+    if(emblSubmission)
+      entryInfo =Options.getDBEntryInformation();
+    else
+      entryInfo = Options.getArtemisEntryInformation();
+    
+    if(!flatten)
+    {
+      final FeatureVector features = entry.getAllFeatures();
+      for(int i=0; i<features.size(); i++)
+        ReadAndWriteEntry.addAllKeysQualifiers(entryInfo, features.elementAt(i));
+
+      if(entry instanceof GFFDocumentEntry)
+        ReadAndWriteEntry.addQualifierToEntryInfo(entryInfo, 
+          (String)PublicDBDocumentEntry.getDatabaseQualifiersToRemove()[0]);
+    }
+      
+    try
+    {
+      final EmblDocumentEntry emblEntry =
+          new EmblDocumentEntry (entryInfo, entry, true);
+      FileDocument out = new FileDocument(new File(outDir+File.separator+
+          seqName+".embl"+(gzip ? ".gz" : "")));
+      emblEntry.save(out);
+      
+      System.out.println("Written... "+out.getFile().getAbsolutePath());
+    }
+    catch (EntryInformationException e)
+    {
+      e.printStackTrace();
+    }
+    catch (IOException e)
+    {
+      JOptionPane.showMessageDialog(null, 
+          e.getMessage(), "I/O Error", JOptionPane.ERROR_MESSAGE);
+      e.printStackTrace();
+    }
+  }
+  
+  /**
+   * Get a new entry for a sequence
+   * @param seqName
+   * @param features
+   * @return
+   */
+  private Entry getEntryForSeqName(
+                final String seqName, 
+                final FeatureVector features)
+  {
+    final GFFDocumentEntry newEntry = new GFFDocumentEntry(null);
+    for(Feature f: features)
+    {
+      final GFFStreamFeature gff = (GFFStreamFeature)f;
+      if(gff.getGffSeqName().equals(seqName))
+      try
+      {
+        newEntry.forcedAdd(new GFFStreamFeature(gff));
+      }
+      catch (ReadOnlyException e)
+      {
+        e.printStackTrace();
+      }
+    }
+    return newEntry;
+  }
+  
+  private Entry getEntry(final String fileName)
+  {
+    try
+    {
+      // move away index file
+      File f = new File(fileName);
+      if(IndexedGFFDocumentEntry.isIndexed( f ))
+      {
+        f = new File(f.getAbsolutePath() + ".tbi");
+        File tmp = new File(f.getAbsolutePath() + ".old");
+        f.renameTo(tmp);
+        f = tmp;
+      }
+      else
+        f = null;
+        
+      final Document doc = DocumentFactory.makeDocument(fileName);
+      final Entry entry =  DocumentEntryFactory.makeDocumentEntry(
+          Options.getArtemisEntryInformation(),doc,null);
+      
+      // move back index file
+      if(f != null)
+      {
+        String name = f.getAbsolutePath();
+        f.renameTo(new File(name.substring(0, name.length()-4)));
+      }
+      return entry;
+    }
+    catch(EntryInformationException e) 
+    {
+      JOptionPane.showMessageDialog(null, 
+          e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
+    }
+    catch(IOException e) 
+    {
+      JOptionPane.showMessageDialog(null, 
+          e.getMessage(), "I/O Error", JOptionPane.ERROR_MESSAGE);
+      e.printStackTrace();
+    }
+    return null;
+  }
+  
+  public static void main(String args[])
+  {
+    if( (args != null && args.length == 1 && args[0].startsWith("-h")) ||
+        (args == null || args.length < 1))
+    {
+      System.out.println("-h\tshow help");
+      System.out.println("-s\tspace separated list of sequences to read and write out");
+      System.out.println("-o\toutput directory");
+      System.out.println("-f\t[y|n] flatten the gene model, default is y");
+      System.out.println("-l\tlocation of EMBL mapping files (qualifier_mapping and key_mapping)");
+      System.out.println("-z\t[y|n] gzip output, default is y");
+      System.out.println("-a\t[y|n] for EMBL submission format change to n, default is y");
+      System.exit(0);
+    }
+
+    boolean gzip = true;
+    boolean emblSubmission = true;
+    boolean flatten = true;
+    Vector<String> files = null;
+    String outDir = null;
+    for(int i=0; i<args.length; i++)
+    {
+      String s = args[i];
+      if(s.equals("-z"))
+      {
+        if(i + 1 < args.length && args[i + 1].toLowerCase().equals("n"))
+          gzip = false;
+      }
+      else if(s.equals("-a"))
+      {
+        if(i + 1 < args.length && args[i + 1].toLowerCase().equals("n"))
+          emblSubmission = false;
+      }
+      else if(s.equals("-f"))
+      {
+        if(i + 1 < args.length && args[i + 1].toLowerCase().equals("n"))
+          flatten = false;
+      }
+      else if(s.equals("-o"))
+      {
+        if(i + 1 < args.length)
+          outDir= args[i + 1];
+      }
+      else if(args[i].toLowerCase().equals("-s"))
+      {
+        if(files == null)
+          files = new java.util.Vector<String>();
+        for(int j = i + 1; j < args.length; j++)
+        {
+          if(args[j].startsWith("-"))
+            break;
+          files.add(args[j]);
+        }
+      }
+    }
+    
+    if(outDir == null)
+    {
+      File f = new File(files.get(0));
+      outDir = f.getParentFile().getAbsolutePath();
+    }
+
+    for(String fn: files)
+      new GffToEMBL(fn, outDir, emblSubmission, flatten, gzip);
+    System.exit(0);
+  }
+}