
/*
 * Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
 */

package org.jsimpledb.cli.cmd;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Map;

import org.dellroad.stuff.io.AtomicUpdateFileOutputStream;
import org.jsimpledb.SessionMode;
import org.jsimpledb.cli.CliSession;
import org.jsimpledb.kv.util.XMLSerializer;
import org.jsimpledb.parse.Parser;
import org.jsimpledb.util.ParseContext;

public class KVSaveCommand extends AbstractCommand {

    public KVSaveCommand() {
        super("kvsave -i:indent file.xml:file minKey? maxKey? limit?");
    }

    @Override
    public String getHelpSummary() {
        return "Exports key/value pairs to an XML file";
    }

    @Override
    public String getHelpDetail() {
        return "Writes all key/value pairs to the specified XML file. Data can be read back in later via `kvload'."
          + "\n\nIf `minKey', `maxKey', and/or `limit' are specified, the keys are restricted to the specified range"
          + " and/or count limit. `minKey' and `maxKey' may be given as hexadecimal strings or C-style doubly-quoted strings."
          + " The `-i' flag causes the output XML to be indented.";
    }

    @Override
    public EnumSet<SessionMode> getSessionModes() {
        return EnumSet.allOf(SessionMode.class);
    }

    @Override
    protected Parser<?> getParser(String typeName) {
        return "file".equals(typeName) ? new OutputFileParser() : super.getParser(typeName);
    }

    @Override
    public CliSession.Action getAction(CliSession session, ParseContext ctx, boolean complete, Map<String, Object> params) {

        // Parse parameters
        final File file = (File)params.get("file.xml");
        final boolean indent = params.containsKey("indent");
        final byte[] key = (byte[])params.get("key");
        final byte[] maxKey = (byte[])params.get("maxKey");
        final Integer limit = (Integer)params.get("limit");

        // Return action
        return new CliSession.TransactionalAction() {
            @Override
            public void run(CliSession session) throws Exception {
                final FileOutputStream updateOutput = !this.isWindows() ?
                  new AtomicUpdateFileOutputStream(file) : new FileOutputStream(file);
                final BufferedOutputStream output = new BufferedOutputStream(updateOutput);
                boolean success = false;
                final int count;
                try {
                    final XMLSerializer serializer = new XMLSerializer(session.getKVTransaction());
                    count = serializer.write(output, indent);
                    output.flush();
                    success = true;
                } finally {
                    if (success) {
                        try {
                            output.close();
                        } catch (IOException e) {
                            // ignore
                        }
                    } else if (updateOutput instanceof AtomicUpdateFileOutputStream)
                        ((AtomicUpdateFileOutputStream)updateOutput).cancel();
                }
                session.getWriter().println("Wrote " + count + " key/value pairs to `" + file + "'");
            }

            private boolean isWindows() {
                return System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH).indexOf("win") != -1;
            }
        };
    }
}


@@ -298,58 +298,195 @@
 ort 
-org.dellroad.stuff.io.AtomicUpdateFileOutputStream
+javax.xml.stream.XMLOutputFactory;%0Aimport javax.xml.stream.XMLStreamWriter;%0A%0Aimport org.dellroad.stuff.io.AtomicUpdateFileOutputStream;%0Aimport org.dellroad.stuff.xml.IndentXMLStreamWriter
 ;%0Aim
@@ -822,15 +822,8 @@
 Key?
- limit?
 %22);%0A
@@ -1142,19 +1142,8 @@
 Key'
-, %60maxKey',
  and
@@ -1147,21 +1147,22 @@
 and/or %60
-limit
+maxKey
 ' are sp
@@ -1216,16 +1216,17 @@
 ed range
+.
 %22%0A      
@@ -1236,28 +1236,8 @@
  + %22
- and/or count limit.
  %60mi
@@ -1996,17 +1996,20 @@
  byte%5B%5D 
-k
+minK
 ey = (by
@@ -2025,17 +2025,20 @@
 ms.get(%22
-k
+minK
 ey%22);%0A  
@@ -2098,68 +2098,8 @@
 y%22);
-%0A        final Integer limit = (Integer)params.get(%22limit%22);
 %0A%0A  
@@ -2605,32 +2605,311 @@
           try %7B%0A
+                    XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(output, %22UTF-8%22);%0A                    if (indent)%0A                        writer = new IndentXMLStreamWriter(writer);%0A                    writer.writeStartDocument(%22UTF-8%22, %221.0%22);%0A
                 
@@ -3041,22 +3041,30 @@
 ite(
-output
+writer
 , 
+m
 in
-dent
+Key, maxKey
 );%0A 

Fix bugs in 'kvsave': implement 'minKey'/'maxKey' and remove 'limit'.