// Path: src/main/java/de/danielbasedow/prospecter/core/document/Document.java
// public class Document {
//     protected final HashMap<String, Field> fields;
// 
//     public Document() {
//         fields = new HashMap<String, Field>();
//     }
// 
//     /**
//      * Add a Field to the Document
//      *
//      * @param name  name of the field
//      * @param field Field instance
//      */
//     public void addField(String name, Field field) {
//         fields.put(name, field);
//     }
// 
//     /**
//      * Gets a Field instance by it's field name
//      *
//      * @param name name of the field
//      * @return Field instance
//      */
//     public Field getField(String name) {
//         return fields.get(name);
//     }
// 
//     /**
//      * Get Iterator over all fields in this Document
//      *
//      * @return iterator over all available fields
//      */
//     public FieldIterator getFields() {
//         return new FieldIterator(fields);
//     }
// 
// }
// 
// Path: src/main/java/de/danielbasedow/prospecter/core/document/MalformedDocumentException.java
// public class MalformedDocumentException extends RuntimeException {
//     public MalformedDocumentException(String msg) {
//         super(msg);
//     }
// 
//     public MalformedDocumentException(String msg, Throwable cause) {
//         super(msg, cause);
//     }
// }
// 
// Path: src/main/java/de/danielbasedow/prospecter/core/schema/Schema.java
// public interface Schema {
//     /**
//      * Add a new FieldIndex to the schema
//      *
//      * @param fieldName name of the field
//      * @param index     index instance used to back this field
//      */
//     public void addFieldIndex(String fieldName, FieldIndex index) throws SchemaConfigurationError;
// 
//     /**
//      * Get matches for a specific field. Useful for debugging index implementations.
//      *
//      * @param fieldIndexName name of the field
//      * @param field          field instance from a Document
//      * @throws UndefinedIndexFieldException
//      */
//     public void matchField(String fieldIndexName, Field field, Matcher matcher) throws UndefinedIndexFieldException;
// 
//     /**
//      * Add query to index. The postings will be added to the corresponding field indices.
//      *
//      * @param query the parsed query
//      * @throws UndefinedIndexFieldException
//      */
//     public void addQuery(Query query) throws UndefinedIndexFieldException;
// 
//     /**
//      * Add query to index. The supplied String will be parsed as JSON and the resulting Query object is passed to
//      * addQuery(Query query)
//      *
//      * @param json raw JSON string
//      * @throws UndefinedIndexFieldException
//      */
//     public void addQuery(String json) throws UndefinedIndexFieldException, MalformedQueryException;
// 
//     /**
//      * Collect all matches for a document
//      *
//      * @param doc     document instance
//      * @param matcher an unused matcher
//      * @return matcher
//      */
//     public Matcher matchDocument(Document doc, Matcher matcher);
// 
//     /**
//      * Collect all matches from a document. A new Matcher instance is automatically created
//      *
//      * @param doc document instance
//      * @return matcher
//      */
//     public Matcher matchDocument(Document doc);
// 
//     public int getFieldCount();
// 
//     public FieldIndex getFieldIndex(String name);
// 
//     public AdvancedQueryBuilder getQueryBuilder();
// 
//     public DocumentBuilder getDocumentBuilder();
// 
//     public Matcher getMatcher();
// 
//     public QueryManager getQueryManager();
// 
//     public void setQueryStorage(QueryStorage queryStorage);
// 
//     /**
//      * Tidy up before shutting down, close files and network connections
//      */
//     public void close();
// 
//     /**
//      * execute any code that should run after the SchemaBuilder is finished. For example loading queries from disk
//      */
//     public void init();
// 
//     public void deleteQuery(Integer queryId);
// 
//     /**
//      * optimize storage requirements
//      */
//     public void trim();
// }


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import de.danielbasedow.prospecter.core.*;
import de.danielbasedow.prospecter.core.document.Document;
import de.danielbasedow.prospecter.core.document.MalformedDocumentException;
import de.danielbasedow.prospecter.core.schema.Schema;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package de.danielbasedow.prospecter.server;



public class HttpApiRequestHandler extends SimpleChannelInboundHandler<Object> {
    private static final ObjectMapper mapper = new ObjectMapper();

    private final Instance instance;
    private FullHttpRequest request;
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpApiRequestHandler.class);

    public HttpApiRequestHandler(Instance instance) {
        this.instance = instance;
    }

    private final StringBuilder responseBuffer = new StringBuilder();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {
            this.request = (FullHttpRequest) msg;
        } else {
            throw new Exception();
        }
        FullHttpResponse response;
        try {
            response = dispatch();
        } catch (Exception e) {
            LOGGER.warn(e.getLocalizedMessage(), e);
            response = new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1,
                    HttpResponseStatus.INTERNAL_SERVER_ERROR,
                    Unpooled.copiedBuffer(e.getLocalizedMessage(), CharsetUtil.UTF_8)
            );
        }

        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

// Path: src/main/java/de/danielbasedow/prospecter/core/document/Document.java
// public class Document {
//     protected final HashMap<String, Field> fields;
// 
//     public Document() {
//         fields = new HashMap<String, Field>();
//     }
// 
//     /**
//      * Add a Field to the Document
//      *
//      * @param name  name of the field
//      * @param field Field instance
//      */
//     public void addField(String name, Field field) {
//         fields.put(name, field);
//     }
// 
//     /**
//      * Gets a Field instance by it's field name
//      *
//      * @param name name of the field
//      * @return Field instance
//      */
//     public Field getField(String name) {
//         return fields.get(name);
//     }
// 
//     /**
//      * Get Iterator over all fields in this Document
//      *
//      * @return iterator over all available fields
//      */
//     public FieldIterator getFields() {
//         return new FieldIterator(fields);
//     }
// 
// }
// 
// Path: src/main/java/de/danielbasedow/prospecter/core/document/MalformedDocumentException.java
// public class MalformedDocumentException extends RuntimeException {
//     public MalformedDocumentException(String msg) {
//         super(msg);
//     }
// 
//     public MalformedDocumentException(String msg, Throwable cause) {
//         super(msg, cause);
//     }
// }
// 
// Path: src/main/java/de/danielbasedow/prospecter/core/schema/Schema.java
// public interface Schema {
//     /**
//      * Add a new FieldIndex to the schema
//      *
//      * @param fieldName name of the field
//      * @param index     index instance used to back this field
//      */
//     public void addFieldIndex(String fieldName, FieldIndex index) throws SchemaConfigurationError;
// 
//     /**
//      * Get matches for a specific field. Useful for debugging index implementations.
//      *
//      * @param fieldIndexName name of the field
//      * @param field          field instance from a Document
//      * @throws UndefinedIndexFieldException
//      */
//     public void matchField(String fieldIndexName, Field field, Matcher matcher) throws UndefinedIndexFieldException;
// 
//     /**
//      * Add query to index. The postings will be added to the corresponding field indices.
//      *
//      * @param query the parsed query
//      * @throws UndefinedIndexFieldException
//      */
//     public void addQuery(Query query) throws UndefinedIndexFieldException;
// 
//     /**
//      * Add query to index. The supplied String will be parsed as JSON and the resulting Query object is passed to
//      * addQuery(Query query)
//      *
//      * @param json raw JSON string
//      * @throws UndefinedIndexFieldException
//      */
//     public void addQuery(String json) throws UndefinedIndexFieldException, MalformedQueryException;
// 
//     /**
//      * Collect all matches for a document
//      *
//      * @param doc     document instance
//      * @param matcher an unused matcher
//      * @return matcher
//      */
//     public Matcher matchDocument(Document doc, Matcher matcher);
// 
//     /**
//      * Collect all matches from a document. A new Matcher instance is automatically created
//      *
//      * @param doc document instance
//      * @return matcher
//      */
//     public Matcher matchDocument(Document doc);
// 
//     public int getFieldCount();
// 
//     public FieldIndex getFieldIndex(String name);
// 
//     public AdvancedQueryBuilder getQueryBuilder();
// 
//     public DocumentBuilder getDocumentBuilder();
// 
//     public Matcher getMatcher();
// 
//     public QueryManager getQueryManager();
// 
//     public void setQueryStorage(QueryStorage queryStorage);
// 
//     /**
//      * Tidy up before shutting down, close files and network connections
//      */
//     public void close();
// 
//     /**
//      * execute any code that should run after the SchemaBuilder is finished. For example loading queries from disk
//      */
//     public void init();
// 
//     public void deleteQuery(Integer queryId);
// 
//     /**
//      * optimize storage requirements
//      */
//     public void trim();
// }


// Path: src/main/java/de/danielbasedow/prospecter/server/HttpApiRequestHandler.java
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import de.danielbasedow.prospecter.core.*;
import de.danielbasedow.prospecter.core.document.Document;
import de.danielbasedow.prospecter.core.document.MalformedDocumentException;
import de.danielbasedow.prospecter.core.schema.Schema;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

package de.danielbasedow.prospecter.server;



public class HttpApiRequestHandler extends SimpleChannelInboundHandler<Object> {
    private static final ObjectMapper mapper = new ObjectMapper();

    private final Instance instance;
    private FullHttpRequest request;
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpApiRequestHandler.class);

    public HttpApiRequestHandler(Instance instance) {
        this.instance = instance;
    }

    private final StringBuilder responseBuffer = new StringBuilder();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {
            this.request = (FullHttpRequest) msg;
        } else {
            throw new Exception();
        }
        FullHttpResponse response;
        try {
            response = dispatch();
        } catch (Exception e) {
            LOGGER.warn(e.getLocalizedMessage(), e);
            response = new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1,
                    HttpResponseStatus.INTERNAL_SERVER_ERROR,
                    Unpooled.copiedBuffer(e.getLocalizedMessage(), CharsetUtil.UTF_8)
            );
        }

        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    protected FullHttpResponse dispatch() throws UndefinedIndexFieldException, MalformedQueryException, MalformedDocumentException, JsonProcessingException {