/*
 * Copyright (c) Bounce Storage, Inc. All rights reserved.
 * For more information, please see COPYRIGHT in the top-level directory.
 */

package com.bouncestorage.swiftproxy;

import static java.util.Objects.requireNonNull;

import java.util.Map;

import javax.ws.rs.core.Application;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.Variant;
import javax.ws.rs.ext.RuntimeDelegate;

public final class RuntimeDelegateImpl extends RuntimeDelegate {
    private static final MediaTypeProvider MEDIA_TYPE_PROVIDER = new MediaTypeProvider();
    private final RuntimeDelegate delegate;

    RuntimeDelegateImpl(RuntimeDelegate delegate) {
        this.delegate = requireNonNull(delegate);
    }

    @Override
    public UriBuilder createUriBuilder() {
        return delegate.createUriBuilder();
    }

    @Override
    public Response.ResponseBuilder createResponseBuilder() {
        return delegate.createResponseBuilder();
    }

    @Override
    public Variant.VariantListBuilder createVariantListBuilder() {
        return delegate.createVariantListBuilder();
    }

    @Override
    public <T> T createEndpoint(Application application, Class<T> endpointType) throws IllegalArgumentException, UnsupportedOperationException {
        return delegate.createEndpoint(application, endpointType);
    }

    @Override
    public <T> HeaderDelegate<T> createHeaderDelegate(Class<T> type) {
        if (type.equals(MediaType.class)) {
            return (HeaderDelegate<T>) MEDIA_TYPE_PROVIDER;
        } else {
            return delegate.createHeaderDelegate(type);
        }
    }

    @Override
    public Link.Builder createLinkBuilder() {
        return delegate.createLinkBuilder();
    }

    private static final class InvalidMediaType extends MediaType {
        private final String type;

        InvalidMediaType(String type) {
            this.type = requireNonNull(type);
        }

        public String toString() {
            StringBuilder res = new StringBuilder(type);
            Map<String, String> params = getParameters();
            if (params != null) {
                for (Map.Entry<String, String> entries : params.entrySet()) {
                    res.append("; ");
                    res.append(entries.getKey());
                    res.append('=');
                    res.append(entries.getValue());
                }
            }
            return res.toString();
        }
    }

    private static final class MediaTypeProvider extends org.glassfish.jersey.message.internal.MediaTypeProvider {
        @Override
        public MediaType fromString(String header) {
            try {
                return super.fromString(header);
            } catch (IllegalArgumentException e) {
                return new InvalidMediaType(header);
            }
        }
    }
}

@@ -491,16 +491,55 @@
 egate;%0A%0A
+import com.google.common.base.Joiner;%0A%0A
 public f
@@ -2228,94 +2228,33 @@
 null
-) %7B%0A                for (Map.Entry%3CString, String%3E entries : params.entrySet
+ && !params.isEmpty
 ()) %7B%0A
-    
     
@@ -2291,36 +2291,32 @@
                 
-    
 res.append(entri
@@ -2314,133 +2314,65 @@
 end(
-entries.getKey());%0A                    res.append('=');%0A                    res.append(entries.getValue());%0A                %7D
+Joiner.on(%22; %22).withKeyValueSeparator(%22=%22).join(params));
 %0A   
@@ -2783,32 +2783,32 @@
 iaType(header);%0A
-
             %7D%0A  
@@ -2810,21 +2810,516 @@
  %7D%0A        %7D
+%0A%0A        @Override%0A        public String toString(MediaType type) %7B%0A            StringBuilder res = new StringBuilder();%0A            res.append(type.getType()).append('/').append(type.getSubtype());%0A            Map%3CString, String%3E params = type.getParameters();%0A            if (params != null && !params.isEmpty()) %7B%0A                res.append(%22; %22);%0A                res.append(Joiner.on(%22; %22).withKeyValueSeparator(%22=%22).join(params));%0A            %7D%0A            return res.toString();%0A        %7D
 %0A    %7D%0A%7D%0A

use Joiner to produce parameters string