package com.mapr.synth;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Joiner;
import com.mapr.synth.samplers.SchemaSampler;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.OptionDef;
import org.kohsuke.args4j.spi.IntOptionHandler;
import org.kohsuke.args4j.spi.Setter;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * Generates plausible database tables in JSON, CSV or TSV format.
 */
public class Synth {
    public static void main(String[] args) throws IOException, CmdLineException {
        Options opts = new Options();
        CmdLineParser parser = new CmdLineParser(opts);
        try {
            parser.parseArgument(args);
        } catch (CmdLineException e) {
            System.err.println("Usage: [ -count <number>G|M|K ] -schema schema-file [-format JSON|TSV|CSV ]");
            throw e;
        }

        SchemaSampler s = new SchemaSampler(opts.schema);
        header(opts.format, s.getFieldNames());
        for (int i = 0; i < opts.count; i++) {
            format(opts.format, s.getFieldNames(), s.sample());
        }
    }

    static Joiner withCommas = Joiner.on(",");
    static Joiner withTabs = Joiner.on("\t");

    private static void header(Format format, List<String> names) {
        switch (format) {
            case TSV:
                System.out.printf("%s\n", withTabs.join(names));
                break;
            case CSV:
                System.out.printf("%s\n", withCommas.join(names));
                break;
        }
    }

    private static void format(Format format, List<String> names, JsonNode fields) {
        switch (format) {
            case JSON:
                System.out.printf("%s\n", fields.toString());
                break;
            case TSV:
                printDelimited(names, fields, "\t");
                break;
            case CSV:
                printDelimited(names, fields, ",");
                break;
        }
    }

    private static void printDelimited(List<String> names, JsonNode fields, String separator) {
        String x = "";
        for (String name : names) {
            System.out.printf("%s%s", x, fields.get(name));
            x = separator;
        }
        System.out.printf("\n");
    }

    public static enum Format {
        JSON, TSV, CSV
    }

    private static class Options {
        @Option(name = "-count", handler = SizeParser.class)
        int count = 1000;

        @Option(name = "-schema")
        File schema;

        @Option(name = "-format")
        Format format = Format.CSV;

        public static class SizeParser extends IntOptionHandler {
            public SizeParser(CmdLineParser parser, OptionDef option, Setter<? super Integer> setter) {
                super(parser, option, setter);
            }

            @Override
            protected Integer parse(String argument) throws NumberFormatException {
                int n = Integer.parseInt(argument.replaceAll("[KMG]?$", ""));

                switch (argument.charAt(argument.length() - 1)) {
                    case 'G':
                        n *= 1e9;
                        break;
                    case 'M':
                        n *= 1e6;
                        break;
                    case 'K':
                        n *= 1e3;
                        break;
                    default:
                        // no suffix leads here
                        break;
                }
                return n;
            }
        }
    }

}

@@ -914,16 +914,60 @@
 ema-file
+ %5B-quote DOUBLE_QUOTE%7CBACK_SLASH%7COPTIMISTIC%5D
  %5B-forma
@@ -1194,32 +1194,44 @@
 mat(opts.format,
+ opts.quote,
  s.getFieldNames
@@ -1728,32 +1728,55 @@
 t(Format format,
+ Quote quoteConvention,
  List%3CString%3E na
@@ -1978,32 +1978,49 @@
  printDelimited(
+quoteConvention, 
 names, fields, %22
@@ -2101,16 +2101,33 @@
 limited(
+quoteConvention, 
 names, f
@@ -2218,16 +2218,39 @@
 limited(
+Quote quoteConvention, 
 List%3CStr
@@ -2373,55 +2373,491 @@
     
-System.out.printf(%22%25s%25s%22, x, fields.get(name));
+switch (quoteConvention) %7B%0A                case DOUBLE_QUOTE:%0A                    System.out.printf(%22%25s%25s%22, x, fields.get(name));%0A                    break;%0A                case OPTIMISTIC:%0A                    System.out.printf(%22%25s%25s%22, x, fields.get(name).asText());%0A                    break;%0A                case BACK_SLASH:%0A                    System.out.printf(%22%25s%25s%22, x, fields.get(name).asText().replaceAll(%22(%5B,%5Ct%5C%5Cs%5C%5C%5C%5C%5D)%22, %22%5C%5C%5C%5C$1%22));%0A                    break;%0A            %7D
 %0A   
@@ -2984,32 +2984,115 @@
 TSV, CSV%0A    %7D%0A%0A
+    public static enum Quote %7B%0A        DOUBLE_QUOTE, BACK_SLASH, OPTIMISTIC%0A    %7D%0A%0A
     private stat
@@ -3325,16 +3325,92 @@
 t.CSV;%0A%0A
+        @Option(name = %22-quote%22)%0A        Quote quote = Quote.DOUBLE_QUOTE;%0A%0A
         

Add different quoting conventions