/*
 * Copyright (c) 2016, Venkatesh-Prasad Ranganath
 *
 * BSD 3-clause License
 *
 * Author: Venkatesh-Prasad Ranganath (rvprasad)
 */
package sindu.jvm.instrumentation.entry;

import org.apache.commons.cli.*;
import org.apache.commons.io.FileUtils;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;

import static org.objectweb.asm.Opcodes.ASM5;

public class CLI {
    // TODO: Add tests for the package

    final static int ASM_VERSION = ASM5;

    public static void main(final String[] args) {
        final Options _options = new Options();
        _options.addOption(Option.builder("f").hasArg().required()
                                 .desc("File listing the fully-qualified paths to classes to be instrumented.")
                                 .build());
        _options.addOption(Option.builder("m").hasArg().desc("Regex identifying the methods to be instrumented. " +
                                                             "This defaults to 'test.*'.").build());
        try {
            final CommandLine _cmdLine = new DefaultParser().parse(_options, args);
            final Collection<String> _fileNames = FileUtils.readLines(new File(_cmdLine.getOptionValue('f')));
            new HashSet<>(_fileNames).parallelStream().forEach(_arg -> {
                try {
                    final File _src = new File(_arg);
                    final File _trg = new File(_arg + ".orig");
                    final byte[] _in = FileUtils.readFileToByteArray(_src);
                    final byte[] _out = instrumentClass(_in, _cmdLine.getOptionValue('m', "test.*"));

                    if (!_trg.exists())
                        FileUtils.moveFile(_src, _trg);

                    FileUtils.writeByteArrayToFile(_src, _out);
                } catch (final IOException _ex) {
                    Logger.getGlobal().log(Level.SEVERE, null, _ex);
                }
            });
        } catch (final ParseException _ex) {
            new HelpFormatter().printHelp(CLI.class.getName(), _options);
        } catch (final IOException _ex) {
            Logger.getGlobal().log(Level.SEVERE, null, _ex);
        }
    }

    public static byte[] instrumentClass(final byte[] b, final String methodNamePattern) {
        final ClassReader _cr = new ClassReader(b);
        final ClassWriter _cw = new ClassWriter(_cr, ClassWriter.COMPUTE_MAXS);
        final org.objectweb.asm.ClassVisitor _cv = new ClassVisitor(_cw, methodNamePattern);
        _cr.accept(_cv, 0);
        return _cw.toByteArray();
    }
}

@@ -784,10 +784,23 @@
 der(
-%22f
+).longOpt(%22file
 %22).h
@@ -1020,169 +1020,151 @@
 der(
-%22m%22).hasArg().desc(%22Regex identifying the methods to be instrumented. %22 +%0A                                                             %22This defaults to '
+).longOpt(%22methodNameRegex%22).hasArg()%0A                                 .desc(%22Regex identifying the methods to be instrumented. Default: 
 test.*
-'
 .%22).
@@ -1378,11 +1378,14 @@
 lue(
-'f'
+%22file%22
 )));
@@ -1763,11 +1763,25 @@
 lue(
-'m'
+%22methodNameRegex%22
 , %22t

Change command line option name.