package org.forge.text.syntax;

import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public interface Encoder {

   public enum Type { TERMINAL, DEBUG }

   void textToken(String text, TokenType type);
   void beginGroup(TokenType type);
   void endGroup(TokenType type);
   void beginLine(TokenType type);
   void endLine(TokenType type);
   
   public static abstract class AbstractEncoder implements Encoder {
      public static final String NEW_LINE = System.getProperty("line.separator");
      
      protected OutputStream out;
      protected Theme theme;
      protected Map<String, Object> options;
      
      public AbstractEncoder(OutputStream out, Theme theme, Map<String, Object> options) {
         this.out = out;
         this.theme = theme;
         this.options = options;
      }
      
      protected Color color(TokenType type) {
         return this.theme.lookup(type);
      }
      
      protected void write(String str) {
         try {
            out.write(str.getBytes());
         } catch(IOException e) {
            throw new RuntimeException("Could not write to output", e);
         }
      }
      protected void writeln(String str) {
         try {
            out.write(str.getBytes());
            out.write(NEW_LINE.getBytes());
         } catch(IOException e) {
            throw new RuntimeException("Could not write to output", e);
         }
      }
      protected void newLine() {
         try {
            out.write(NEW_LINE.getBytes());
         } catch(IOException e) {
            throw new RuntimeException("Could not write to output", e);
         }
      }
      protected void flush() {
         try {
            out.flush();
         } catch(IOException e) {
            throw new RuntimeException("Could not flush", e);
         }
      }
   }
   
   public static class Factory {
      private static Factory factory;
      
      private Map<String, Class<? extends Encoder>> registry;
      
      private Factory() {
         this.registry = new HashMap<String, Class<? extends Encoder>>();
      }
      
      private static Factory instance() {
         if(factory == null) {
            factory = new Factory();
         }
         return factory;
      }

      public static void registrer(String type, Class<? extends Encoder> encoder) {
         instance().registry.put(type, encoder); 
      }
      
      public static Encoder create(String type, OutputStream out, Theme theme, Map<String, Object> options) {
         Class<? extends Encoder> encoder = instance().registry.get(type); 
         if(encoder != null) {
            try {
               Constructor<? extends Encoder> constructor = encoder.getConstructor(OutputStream.class, Theme.class, Map.class);
               return constructor.newInstance(out, theme, options);
            } catch(Exception e) {
               throw new RuntimeException("Could not create new instance of " + encoder);
            }
         }
         throw new RuntimeException("No encoder found for type " + type);
      }
   }
}

@@ -1231,32 +1231,33 @@
       %7D%0A      %7D%0A
+%0A
       protected 
@@ -1270,277 +1270,21 @@
 rite
-ln(String str) %7B%0A         try %7B%0A            out.write(str.getBytes());%0A            out.write(NEW_LINE.getBytes());%0A         %7D catch(IOException e) %7B%0A            throw new RuntimeException(%22Could not write to output%22, e);%0A         %7D%0A      %7D%0A      protected void newLine(
+(byte%5B%5D bytes
 ) %7B%0A
@@ -1324,27 +1324,13 @@
 ite(
-NEW_LINE.getB
+b
 ytes
-()
 );%0A 
@@ -1457,194 +1457,8 @@
   %7D%0A
-      protected void flush() %7B%0A         try %7B%0A            out.flush();%0A         %7D catch(IOException e) %7B%0A            throw new RuntimeException(%22Could not flush%22, e);%0A         %7D%0A      %7D%0A
    %7D

Remove unused methods in Abstract Encoder