// Copyright (c) Cognitect, Inc.
// All rights reserved.

package com.cognitect.transit;


import com.cognitect.transit.impl.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

public class TransitFactory {
    public static enum Format { JSON, MSGPACK, JSON_HUMAN, JSON_MACHINE }

    public static Writer writer(Format type, OutputStream out)  throws IOException, IllegalArgumentException {
        return writer(type, out, null);
    }

    public static Writer writer(Format type, OutputStream out, Map<Class, Handler> customHandlers) {
        try {
            HashMap<Class, Handler> h = new HashMap<Class, Handler>();
            if (customHandlers != null) h.putAll(customHandlers);
            customHandlers = h;

            switch (type) {
                case JSON_HUMAN:
                    return WriterImpl.getJsonInstance(out, customHandlers, false);
                case JSON:
                case JSON_MACHINE:
                    customHandlers.put(java.util.Date.class, new Handlers.MachineModeTimeHandler());

                    return WriterImpl.getJsonInstance(out, customHandlers, true);
                case MSGPACK:
                    return WriterImpl.getMsgpackInstance(out, customHandlers);
                default:
                    throw new IllegalArgumentException("Unknown Writer type: " + type.toString());
            }
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static Reader reader(Format type, InputStream in) throws IOException, IllegalArgumentException {
        return reader(type, in, null);
    }

    public static Reader reader(Format type, InputStream in, Map<String, Decoder> customDecoders) {
        return reader(type, in, customDecoders, new MapBuilderImpl(), new ListBuilderImpl(), new ArrayBuilderImpl(), new SetBuilderImpl());
    }

    public static Reader reader(Format type, InputStream in,
                                Map<String, Decoder> customDecoders,
                                MapBuilder mapBuilder, ListBuilder listBuilder,
                                ArrayBuilder arrayBuilder, SetBuilder setBuilder) {
        try {
            switch (type) {
                case JSON:
                case JSON_MACHINE:
                case JSON_HUMAN:
                    return ReaderImpl.getJsonInstance(in, customDecoders, mapBuilder, listBuilder, arrayBuilder, setBuilder);
                case MSGPACK:
                    return ReaderImpl.getMsgpackInstance(in, customDecoders, mapBuilder, listBuilder, arrayBuilder, setBuilder);
                default:
                    throw new IllegalArgumentException("Unknown Reader type: " + type.toString());
            }
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static Keyword keyword(Object o) {
        if (o instanceof Keyword)
            return (Keyword) o;
        else if (o instanceof String)
            return new KeywordImpl((String) o);
        else throw new IllegalArgumentException("Cannot make keyword from " + o.getClass().getSimpleName());
    }

    public static Symbol symbol(Object o) {
        if (o instanceof Symbol)
            return (Symbol) o;
        else if (o instanceof String)
            return new SymbolImpl((String) o);
        else throw new IllegalArgumentException("Cannot make keyword from " + o.getClass().getSimpleName());
    }

    public static TaggedValue taggedValue(String tag, Object rep) {
        return new TaggedValueImpl(tag, rep);
    }

    public static TaggedValue taggedValue(String tag, Object rep, String stringRep) {
        return new TaggedValueImpl(tag, rep, stringRep);
    }

    public static Map defaultDecoders() { return ReaderImpl.defaultDecoders(); }
    public static Map defaultHandlers() { return WriterImpl.defaultHandlers(); }
    public static MapBuilder defaultMapBuilder() { return new MapBuilderImpl(); }
    public static ArrayBuilder defaultArrayBuilder() { return new ArrayBuilderImpl(); }
    public static ListBuilder defaultListBuilder() { return new ListBuilderImpl(); }
    public static SetBuilder defaultSetBuilder() { return new SetBuilderImpl(); }
}

@@ -3021,32 +3021,34 @@
 stanceof String)
+ %7B
 %0A            ret
@@ -3048,43 +3048,192 @@
     
-return new KeywordImpl((String) o);
+String s = (String) o;%0A            if (s.charAt(0) == ':')%0A                return new KeywordImpl(s.substring(1));%0A            else%0A                return new KeywordImpl(s);%0A        %7D
 %0A   
@@ -3494,55 +3494,205 @@
 ing)
-%0A            return new SymbolImpl((String) o);
+ %7B%0A            String s = (String) o;%0A            if (s.charAt(0) == ':')%0A                return new SymbolImpl(s.substring(1));%0A            else%0A                return new SymbolImpl(s);%0A        %7D
 %0A   

Add code to account for leading : in Keyword and Symbol factory methods