/*
 * RESTHeart - the Web API for MongoDB
 * Copyright (C) SoftInstigate Srl
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.restheart.handlers;

import com.mongodb.MongoBulkWriteException;
import com.mongodb.MongoException;
import com.mongodb.MongoTimeoutException;
import org.restheart.utils.HttpStatus;
import org.restheart.utils.ResponseHelper;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import org.restheart.hal.Representation;
import org.restheart.metadata.transformers.RepresentationTransformer.PHASE;
import org.restheart.metadata.transformers.PlainJsonTransformer;
import org.restheart.handlers.bulk.BulkResultRepresentationFactory;
import org.restheart.handlers.metadata.TransformerHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Andrea Di Cesare {@literal <andrea@softinstigate.com>}
 */
public class ErrorHandler implements HttpHandler {
    private HttpHandler next;
    
    private PipedHttpHandler sender = new TransformerHandler(
            new ResponseSenderHandler(null),
            PHASE.RESPONSE,
                        new PlainJsonTransformer());
    
    private final Logger LOGGER = LoggerFactory.getLogger(ErrorHandler.class);

    /**
     * Creates a new instance of ErrorHandler
     *
     * @param next
     */
    public ErrorHandler(HttpHandler next) {
        this.next = next;
    }

    /**
     *
     * @param exchange
     * @param context
     * @throws Exception
     */
    @Override
    public void handleRequest(
            HttpServerExchange exchange)
            throws Exception {
        try {
            next.handleRequest(exchange);
        } catch (MongoTimeoutException nte) {
            RequestContext errorContext = new RequestContext(exchange, "/", "_error");
            
            ResponseHelper.endExchangeWithMessage(
                    exchange,
                    errorContext,
                    HttpStatus.SC_INTERNAL_SERVER_ERROR,
                    "Timeout connecting to MongoDB, is it running?", nte);
            
            sender.handleRequest(exchange, errorContext);
        } catch (MongoBulkWriteException mce) {
            MongoBulkWriteException bmce = (MongoBulkWriteException) mce;

            BulkResultRepresentationFactory rf = new BulkResultRepresentationFactory();

            Representation rep = rf.getRepresentation(exchange, bmce);
            
            RequestContext errorContext = new RequestContext(exchange, "/", "_error");

            ResponseHelper.endExchangeWithRepresentation(
                    exchange,
                    errorContext,
                    HttpStatus.SC_MULTI_STATUS,
                    rep);

            sender.handleRequest(exchange, errorContext);
        } catch (MongoException mce) {
            int httpCode = ResponseHelper.getHttpStatusFromErrorCode(mce.getCode());

            LOGGER.error("Error handling the request", mce);

            RequestContext errorContext = new RequestContext(exchange, "/", "_error");
            
            if (httpCode >= 500
                    && mce.getMessage() != null
                    && !mce.getMessage().trim().isEmpty()) {

                ResponseHelper.endExchangeWithMessage(
                        exchange,
                        errorContext,
                        httpCode,
                        mce.getMessage());

            } else {
                ResponseHelper.endExchangeWithMessage(
                        exchange,
                        errorContext,
                        httpCode,
                        ResponseHelper.getMessageFromErrorCode(mce.getCode()));
            }

            sender.handleRequest(exchange, errorContext);
        } catch (Throwable t) {
            LOGGER.error("Error handling the request", t);
            
            RequestContext errorContext = new RequestContext(exchange, "/", "_error");

            ResponseHelper.endExchangeWithMessage(
                    exchange,
                    errorContext,
                    HttpStatus.SC_INTERNAL_SERVER_ERROR,
                    "Error handling the request, see log for more information", t);
            sender.handleRequest(exchange, errorContext);
        }
    }
}

@@ -851,32 +851,83 @@
 MongoException;%0A
+import com.mongodb.MongoExecutionTimeoutException;%0A
 import com.mongo
@@ -2751,32 +2751,468 @@
 );%0A            %0A
+            sender.handleRequest(exchange, errorContext);%0A        %7D catch (MongoExecutionTimeoutException mete) %7B%0A            RequestContext errorContext = new RequestContext(exchange, %22/%22, %22_error%22);%0A%0A            ResponseHelper.endExchangeWithMessage(%0A                    exchange,%0A                    errorContext,%0A                    HttpStatus.SC_REQUEST_TIMEOUT,%0A                    %22Operation exceeded time limit%22%0A            );%0A%0A
             send

add MongoExecutionTimeoutException handler to ErrorHandler