/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * 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
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 io.gravitee.policy.mock;

import io.gravitee.common.http.HttpHeaders;
import io.gravitee.gateway.api.*;
import io.gravitee.gateway.api.handler.Handler;
import io.gravitee.gateway.api.http.BodyPart;
import io.gravitee.gateway.api.http.StringBodyPart;
import io.gravitee.policy.api.PolicyChain;
import io.gravitee.policy.api.annotations.OnRequest;
import io.gravitee.policy.mock.configuration.MockPolicyConfiguration;

/**
 * @author David BRASSELY (brasseld at gmail.com)
 * @author GraviteeSource Team
 */
public class MockPolicy {

    /**
     * Mock policy configuration
     */
    private final MockPolicyConfiguration mockPolicyConfiguration;

    public MockPolicy(MockPolicyConfiguration mockPolicyConfiguration) {
        this.mockPolicyConfiguration = mockPolicyConfiguration;
    }

    @OnRequest
    public void onRequest(Request request, Response response, ExecutionContext executionContext, PolicyChain policyChain) {
        // Dynamically set the default invoker and provide a custom implementation
        // to returns data from mock.
        executionContext.setAttribute(ExecutionContext.ATTR_INVOKER, new MockInvoker());

        policyChain.doNext(request, response);
    }

    class MockInvoker implements Invoker {

        @Override
        public ClientRequest invoke(ExecutionContext executionContext, Request serverRequest, Handler<ClientResponse> result) {
            final ClientRequest clientRequest = new MockClientRequest(new MockClientResponse(), result);

            serverRequest
                    .bodyHandler(clientRequest::write)
                    .endHandler(endResult -> clientRequest.end());

            return clientRequest;
        }
    }

    class MockClientRequest implements ClientRequest {

        private final MockClientResponse clientResponse;
        private final Handler<ClientResponse> clientResponseHandler;

        MockClientRequest(final MockClientResponse clientResponse, final Handler<ClientResponse> clientResponseHandler) {
            this.clientResponse = clientResponse;
            this.clientResponseHandler = clientResponseHandler;
        }

        @Override
        public ClientRequest connectTimeoutHandler(Handler<Throwable> timeoutHandler) {
            return this;
        }

        @Override
        public ClientRequest write(BodyPart bodyPart) {
            return this;
        }

        @Override
        public void end() {
            clientResponse.headers.set(HttpHeaders.CONTENT_LENGTH, Integer.toString(
                    mockPolicyConfiguration.getContent().length()));

            clientResponseHandler.handle(clientResponse);

            clientResponse.bodyHandler.handle(new StringBodyPart(mockPolicyConfiguration.getContent()));
            clientResponse.endHandler.handle(null);
        }
    }

    class MockClientResponse implements ClientResponse {

        private final HttpHeaders headers = new HttpHeaders();

        private Handler<BodyPart> bodyHandler;
        private Handler<Void> endHandler;

        MockClientResponse() {
            this.init();
        }

        private void init() {
            mockPolicyConfiguration.getHeaders()
                    .stream()
                    .filter(header -> header.getName() != null && !header.getName().trim().isEmpty())
                    .forEach(header -> headers.add(header.getName(), header.getValue()));
        }

        @Override
        public int status() {
            return mockPolicyConfiguration.getStatus();
        }

        @Override
        public HttpHeaders headers() {
            return headers;
        }

        @Override
        public ClientResponse bodyHandler(Handler<BodyPart> bodyPartHandler) {
            this.bodyHandler = bodyPartHandler;
            return this;
        }

        @Override
        public ClientResponse endHandler(Handler<Void> endHandler) {
            this.endHandler = endHandler;
            return this;
        }
    }
}

@@ -3050,24 +3050,202 @@
 oid end() %7B%0A
+            String content = mockPolicyConfiguration.getContent();%0A            boolean hasContent = (content != null && content.length() %3E 0);%0A%0A            if (hasContent) %7B%0A    
             
@@ -3329,32 +3329,36 @@
                 
+    
 mockPolicyConfig
@@ -3389,16 +3389,30 @@
 gth()));
+%0A            %7D
 %0A%0A      
@@ -3460,24 +3460,58 @@
 Response);%0A%0A
+            if (hasContent) %7B%0A    
             
@@ -3599,24 +3599,51 @@
 ontent()));%0A
+            %7D%0A            %0A
             

Send content only if provided in configuration