// Path: app/src/main/java/org/hexpresso/elm327/exceptions/BusInitException.java
// public class BusInitException extends ResponseException {
// 
//     public BusInitException() {
//         super("BUS INIT... ERROR");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/MisunderstoodCommandException.java
// public class MisunderstoodCommandException extends ResponseException {
// 
//     public MisunderstoodCommandException() {
//         super("?");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/NoDataException.java
// public class NoDataException extends ResponseException {
// 
//     public NoDataException() {
//         super("NO DATA");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/ResponseException.java
// public class ResponseException extends RuntimeException {
// 
//     private String message;
// 
//     private String response;
// 
//     private String command;
// 
//     private boolean matchRegex;
// 
//     /**
//      * @param message a {@link java.lang.String} object.
//      */
//     protected ResponseException(String message) {
//         this.message = message;
//     }
// 
//     protected ResponseException(String message, boolean matchRegex) {
//         this.message = message;
//         this.matchRegex = matchRegex;
//     }
// 
//     private static String clean(String s) {
//         return s == null ? "" : s.replaceAll("\\s", "").toUpperCase();
//     }
// 
//     /**
//      * @param response a {@link java.lang.String} object.
//      * @return a boolean.
//      */
//     public boolean isError(String response) {
//         this.response = response;
//         if (matchRegex) {
//             return clean(response).matches(clean(message));
//         } else {
//             return clean(response).contains(clean(message));
//         }
//     }
// 
//     /**
//      * @param command a {@link java.lang.String} object.
//      */
//     public void setCommand(String command) {
//         this.command = command;
//     }
// 
//     @Override
//     public String getMessage() {
//         return "Error running " + command + ", response: " + response;
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/StoppedException.java
// public class StoppedException extends ResponseException {
// 
//     public StoppedException() {
//         super("STOPPED");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/UnableToConnectException.java
// public class UnableToConnectException extends ResponseException {
// 
//     public UnableToConnectException() {
//         super("UNABLE TO CONNECT");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/UnknownErrorException.java
// public class UnknownErrorException extends ResponseException {
// 
//     public UnknownErrorException() {
//         super("ERROR");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/UnsupportedCommandException.java
// public class UnsupportedCommandException extends ResponseException {
// 
//     public UnsupportedCommandException() {
//         super("7F 0[0-9] 12", true);
//     }
// 
// }


import org.hexpresso.elm327.exceptions.BusInitException;
import org.hexpresso.elm327.exceptions.MisunderstoodCommandException;
import org.hexpresso.elm327.exceptions.NoDataException;
import org.hexpresso.elm327.exceptions.ResponseException;
import org.hexpresso.elm327.exceptions.StoppedException;
import org.hexpresso.elm327.exceptions.UnableToConnectException;
import org.hexpresso.elm327.exceptions.UnknownErrorException;
import org.hexpresso.elm327.exceptions.UnsupportedCommandException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

package org.hexpresso.elm327.commands;



/**
 * The AbstractCommand class represents an ELM327 command.
 * <p/>
 * Created by Pierre-Etienne Messier <pierre.etienne.messier@gmail.com> on 2015-10-24.
 */
public abstract class AbstractCommand implements Command {

    protected String mCommand = null;                          // ELM327 command
    protected long mResponseTimeDelay = 200;                   // Time delay before receiving the response, in milliseconds
    protected Response mResponse = new Response();             // Response object

    private long mRunStartTimestamp;                           // Timestamp before sending the command
    private long mRunEndTimestamp;                             // Timestamp after receiving the command response
    private boolean mWithAutoProcessResponse = false;          //

    /**
     * Error classes to be tested in order
     */
    private final static Class[] ERROR_CLASSES = {
            UnableToConnectException.class,
            BusInitException.class,
            MisunderstoodCommandException.class,
            NoDataException.class,
            StoppedException.class,
            UnknownErrorException.class,
            UnsupportedCommandException.class
    };

    /**
     * Constructor
     *
     * @param command ELM327 command to send
     */
    public AbstractCommand(String command) {
        mCommand = command;
    }

    private AbstractCommand() {
    }

    /**
     *
     * @param in
     * @param out
     * @throws IOException
     * @throws InterruptedException
     */
    @Override

// Path: app/src/main/java/org/hexpresso/elm327/exceptions/BusInitException.java
// public class BusInitException extends ResponseException {
// 
//     public BusInitException() {
//         super("BUS INIT... ERROR");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/MisunderstoodCommandException.java
// public class MisunderstoodCommandException extends ResponseException {
// 
//     public MisunderstoodCommandException() {
//         super("?");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/NoDataException.java
// public class NoDataException extends ResponseException {
// 
//     public NoDataException() {
//         super("NO DATA");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/ResponseException.java
// public class ResponseException extends RuntimeException {
// 
//     private String message;
// 
//     private String response;
// 
//     private String command;
// 
//     private boolean matchRegex;
// 
//     /**
//      * @param message a {@link java.lang.String} object.
//      */
//     protected ResponseException(String message) {
//         this.message = message;
//     }
// 
//     protected ResponseException(String message, boolean matchRegex) {
//         this.message = message;
//         this.matchRegex = matchRegex;
//     }
// 
//     private static String clean(String s) {
//         return s == null ? "" : s.replaceAll("\\s", "").toUpperCase();
//     }
// 
//     /**
//      * @param response a {@link java.lang.String} object.
//      * @return a boolean.
//      */
//     public boolean isError(String response) {
//         this.response = response;
//         if (matchRegex) {
//             return clean(response).matches(clean(message));
//         } else {
//             return clean(response).contains(clean(message));
//         }
//     }
// 
//     /**
//      * @param command a {@link java.lang.String} object.
//      */
//     public void setCommand(String command) {
//         this.command = command;
//     }
// 
//     @Override
//     public String getMessage() {
//         return "Error running " + command + ", response: " + response;
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/StoppedException.java
// public class StoppedException extends ResponseException {
// 
//     public StoppedException() {
//         super("STOPPED");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/UnableToConnectException.java
// public class UnableToConnectException extends ResponseException {
// 
//     public UnableToConnectException() {
//         super("UNABLE TO CONNECT");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/UnknownErrorException.java
// public class UnknownErrorException extends ResponseException {
// 
//     public UnknownErrorException() {
//         super("ERROR");
//     }
// 
// }
// 
// Path: app/src/main/java/org/hexpresso/elm327/exceptions/UnsupportedCommandException.java
// public class UnsupportedCommandException extends ResponseException {
// 
//     public UnsupportedCommandException() {
//         super("7F 0[0-9] 12", true);
//     }
// 
// }


// Path: app/src/main/java/org/hexpresso/elm327/commands/AbstractCommand.java
import org.hexpresso.elm327.exceptions.BusInitException;
import org.hexpresso.elm327.exceptions.MisunderstoodCommandException;
import org.hexpresso.elm327.exceptions.NoDataException;
import org.hexpresso.elm327.exceptions.ResponseException;
import org.hexpresso.elm327.exceptions.StoppedException;
import org.hexpresso.elm327.exceptions.UnableToConnectException;
import org.hexpresso.elm327.exceptions.UnknownErrorException;
import org.hexpresso.elm327.exceptions.UnsupportedCommandException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

package org.hexpresso.elm327.commands;



/**
 * The AbstractCommand class represents an ELM327 command.
 * <p/>
 * Created by Pierre-Etienne Messier <pierre.etienne.messier@gmail.com> on 2015-10-24.
 */
public abstract class AbstractCommand implements Command {

    protected String mCommand = null;                          // ELM327 command
    protected long mResponseTimeDelay = 200;                   // Time delay before receiving the response, in milliseconds
    protected Response mResponse = new Response();             // Response object

    private long mRunStartTimestamp;                           // Timestamp before sending the command
    private long mRunEndTimestamp;                             // Timestamp after receiving the command response
    private boolean mWithAutoProcessResponse = false;          //

    /**
     * Error classes to be tested in order
     */
    private final static Class[] ERROR_CLASSES = {
            UnableToConnectException.class,
            BusInitException.class,
            MisunderstoodCommandException.class,
            NoDataException.class,
            StoppedException.class,
            UnknownErrorException.class,
            UnsupportedCommandException.class
    };

    /**
     * Constructor
     *
     * @param command ELM327 command to send
     */
    public AbstractCommand(String command) {
        mCommand = command;
    }

    private AbstractCommand() {
    }

    /**
     *
     * @param in
     * @param out
     * @throws IOException
     * @throws InterruptedException
     */
    @Override

    public void execute(InputStream in, OutputStream out) throws IOException, InterruptedException {
