// Path: src/main/java/com/groupon/vertx/memcache/client/JsendStatus.java
// public enum JsendStatus {
//     success,
//     error,
//     fail;
// }
// 
// Path: src/main/java/com/groupon/vertx/memcache/client/response/MemcacheCommandResponse.java
// public class MemcacheCommandResponse {
//     private final JsendStatus status;
//     private final String message;
// 
//     MemcacheCommandResponse(AbstractBuilder<?, ?> builder) {
//         this.status = builder.status;
//         this.message = builder.message;
//     }
// 
//     public JsendStatus getStatus() {
//         return status;
//     }
// 
//     public String getMessage() {
//         return message;
//     }
// 
//     /**
//      * AbstractBuilder for classes extending the MemcacheCommandResponse
//      */
//     public abstract static class AbstractBuilder<B extends AbstractBuilder<B, O>, O extends MemcacheCommandResponse> {
//         private JsendStatus status;
//         private String message;
// 
//         protected abstract B self();
// 
//         public B setStatus(JsendStatus value) {
//             status = value;
//             return self();
//         }
// 
//         public B setMessage(String value) {
//             message = value;
//             return self();
//         }
// 
//         public abstract O build();
//     }
// 
//     /**
//      * Builder for the MemcacheCommandResponse
//      */
//     public static class Builder extends AbstractBuilder<Builder, MemcacheCommandResponse> {
//         @Override
//         protected Builder self() {
//             return this;
//         }
// 
//         @Override
//         public MemcacheCommandResponse build() {
//             return new MemcacheCommandResponse(this);
//         }
//     }
// }
// 
// Path: src/main/java/com/groupon/vertx/memcache/stream/MemcacheResponseType.java
// public enum MemcacheResponseType {
//     VALUE("VALUE ", false),
//     STORED("STORED", true),
//     DELETED("DELETED", true),
//     TOUCHED("TOUCHED", true),
//     NOT_STORED("NOT_STORED", true),
//     EXISTS("EXISTS", true),
//     NOT_FOUND("NOT_FOUND", true),
//     END("END", true),
//     ERROR("ERROR", true),
//     CLIENT_ERROR("CLIENT ERROR", false),
//     SERVER_ERROR("SERVER ERROR", false);
// 
//     public final String type;
//     public final boolean exact;
// 
//     MemcacheResponseType(String type, boolean exact) {
//         this.type = type;
//         this.exact = exact;
//     }
// 
//     public boolean matches(ByteArrayOutputStream line) {
//         boolean match;
//         try {
//             if (!exact) {
//                 match = line.toString("UTF-8").startsWith(type);
//             } else {
//                 match = line.toString("UTF-8").equals(type);
//             }
//         } catch (UnsupportedEncodingException e) {
//             match = false;
//         }
//         return match;
//     }
// }


import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import com.groupon.vertx.memcache.client.JsendStatus;
import com.groupon.vertx.memcache.client.response.MemcacheCommandResponse;
import com.groupon.vertx.memcache.stream.MemcacheResponseType;
import com.groupon.vertx.utils.Logger;
/**
 * Copyright 2014 Groupon.com
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.groupon.vertx.memcache.parser;



/**
 * This represents the generic response parsing from memcache which can be returned from any request.
 *
 * @author Stuart Siegrist (fsiegrist at groupon dot com)
 * @since 1.0.0
 */
public abstract class BaseLineParser<T extends MemcacheCommandResponse, B extends MemcacheCommandResponse.AbstractBuilder<B, T>> implements LineParser {
    private static final Logger log = Logger.getLogger(BaseLineParser.class);
    private static final MemcacheResponseType[] RESPONSE_TYPES = new MemcacheResponseType[]{
            MemcacheResponseType.ERROR, MemcacheResponseType.CLIENT_ERROR, MemcacheResponseType.SERVER_ERROR
    };

    protected abstract B getResponseBuilder();

    public boolean isResponseEnd(ByteArrayOutputStream line) {
        try {
            MemcacheResponseType type = getResponseType(RESPONSE_TYPES, line);
            if (type != null) {
                log.trace("isResponseEnd", "error", new String[]{"type"}, type);
                B builder = getResponseBuilder();
                builder.setStatus(JsendStatus.error);
                builder.setMessage(line.toString(ENCODING));
                return true;
            } else {
                return false;
            }
        } catch (UnsupportedEncodingException e) {
            log.error("getResponse", "unexpected", "unsupported encoding", e);
            return false;
        }
    }

    protected MemcacheResponseType getResponseType(MemcacheResponseType[] list, ByteArrayOutputStream line) {
        MemcacheResponseType type = null;
        for (MemcacheResponseType responseType : list) {
            if (responseType.matches(line)) {
                log.trace("getResponseType", "foundType", new String[]{"type"}, responseType);
// Path: src/main/java/com/groupon/vertx/memcache/client/JsendStatus.java
// public enum JsendStatus {
//     success,
//     error,
//     fail;
// }
// 
// Path: src/main/java/com/groupon/vertx/memcache/client/response/MemcacheCommandResponse.java
// public class MemcacheCommandResponse {
//     private final JsendStatus status;
//     private final String message;
// 
//     MemcacheCommandResponse(AbstractBuilder<?, ?> builder) {
//         this.status = builder.status;
//         this.message = builder.message;
//     }
// 
//     public JsendStatus getStatus() {
//         return status;
//     }
// 
//     public String getMessage() {
//         return message;
//     }
// 
//     /**
//      * AbstractBuilder for classes extending the MemcacheCommandResponse
//      */
//     public abstract static class AbstractBuilder<B extends AbstractBuilder<B, O>, O extends MemcacheCommandResponse> {
//         private JsendStatus status;
//         private String message;
// 
//         protected abstract B self();
// 
//         public B setStatus(JsendStatus value) {
//             status = value;
//             return self();
//         }
// 
//         public B setMessage(String value) {
//             message = value;
//             return self();
//         }
// 
//         public abstract O build();
//     }
// 
//     /**
//      * Builder for the MemcacheCommandResponse
//      */
//     public static class Builder extends AbstractBuilder<Builder, MemcacheCommandResponse> {
//         @Override
//         protected Builder self() {
//             return this;
//         }
// 
//         @Override
//         public MemcacheCommandResponse build() {
//             return new MemcacheCommandResponse(this);
//         }
//     }
// }
// 
// Path: src/main/java/com/groupon/vertx/memcache/stream/MemcacheResponseType.java
// public enum MemcacheResponseType {
//     VALUE("VALUE ", false),
//     STORED("STORED", true),
//     DELETED("DELETED", true),
//     TOUCHED("TOUCHED", true),
//     NOT_STORED("NOT_STORED", true),
//     EXISTS("EXISTS", true),
//     NOT_FOUND("NOT_FOUND", true),
//     END("END", true),
//     ERROR("ERROR", true),
//     CLIENT_ERROR("CLIENT ERROR", false),
//     SERVER_ERROR("SERVER ERROR", false);
// 
//     public final String type;
//     public final boolean exact;
// 
//     MemcacheResponseType(String type, boolean exact) {
//         this.type = type;
//         this.exact = exact;
//     }
// 
//     public boolean matches(ByteArrayOutputStream line) {
//         boolean match;
//         try {
//             if (!exact) {
//                 match = line.toString("UTF-8").startsWith(type);
//             } else {
//                 match = line.toString("UTF-8").equals(type);
//             }
//         } catch (UnsupportedEncodingException e) {
//             match = false;
//         }
//         return match;
//     }
// }


// Path: src/main/java/com/groupon/vertx/memcache/parser/BaseLineParser.java
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import com.groupon.vertx.memcache.client.JsendStatus;
import com.groupon.vertx.memcache.client.response.MemcacheCommandResponse;
import com.groupon.vertx.memcache.stream.MemcacheResponseType;
import com.groupon.vertx.utils.Logger;

/**
 * Copyright 2014 Groupon.com
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.groupon.vertx.memcache.parser;



/**
 * This represents the generic response parsing from memcache which can be returned from any request.
 *
 * @author Stuart Siegrist (fsiegrist at groupon dot com)
 * @since 1.0.0
 */
public abstract class BaseLineParser<T extends MemcacheCommandResponse, B extends MemcacheCommandResponse.AbstractBuilder<B, T>> implements LineParser {
    private static final Logger log = Logger.getLogger(BaseLineParser.class);
    private static final MemcacheResponseType[] RESPONSE_TYPES = new MemcacheResponseType[]{
            MemcacheResponseType.ERROR, MemcacheResponseType.CLIENT_ERROR, MemcacheResponseType.SERVER_ERROR
    };

    protected abstract B getResponseBuilder();

    public boolean isResponseEnd(ByteArrayOutputStream line) {
        try {
            MemcacheResponseType type = getResponseType(RESPONSE_TYPES, line);
            if (type != null) {
                log.trace("isResponseEnd", "error", new String[]{"type"}, type);
                B builder = getResponseBuilder();
                builder.setStatus(JsendStatus.error);
                builder.setMessage(line.toString(ENCODING));
                return true;
            } else {
                return false;
            }
        } catch (UnsupportedEncodingException e) {
            log.error("getResponse", "unexpected", "unsupported encoding", e);
            return false;
        }
    }

    protected MemcacheResponseType getResponseType(MemcacheResponseType[] list, ByteArrayOutputStream line) {
        MemcacheResponseType type = null;
        for (MemcacheResponseType responseType : list) {
            if (responseType.matches(line)) {
                log.trace("getResponseType", "foundType", new String[]{"type"}, responseType);
                type = responseType;