// 
// Decompiled by Procyon v0.6.0
// 

package io.netty.handler.codec.http;

import java.util.Collection;
import java.util.Map;
import io.netty.handler.codec.Headers;
import java.util.List;
import java.util.Iterator;
import io.netty.handler.codec.ValueConverter;
import io.netty.util.HashingStrategy;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.ObjectUtil;
import io.netty.handler.codec.DefaultHeaders;
import io.netty.util.AsciiString;

public class CombinedHttpHeaders extends DefaultHttpHeaders
{
    @Deprecated
    public CombinedHttpHeaders(final boolean validate) {
        super(new CombinedHttpHeadersImpl(AsciiString.CASE_INSENSITIVE_HASHER, DefaultHttpHeaders.valueConverter(), DefaultHttpHeaders.nameValidator(validate), DefaultHttpHeaders.valueValidator(validate)));
    }
    
    CombinedHttpHeaders(final DefaultHeaders.NameValidator<CharSequence> nameValidator, final DefaultHeaders.ValueValidator<CharSequence> valueValidator) {
        super(new CombinedHttpHeadersImpl(AsciiString.CASE_INSENSITIVE_HASHER, DefaultHttpHeaders.valueConverter(), ObjectUtil.checkNotNull(nameValidator, "nameValidator"), ObjectUtil.checkNotNull(valueValidator, "valueValidator")));
    }
    
    CombinedHttpHeaders(final DefaultHeaders.NameValidator<CharSequence> nameValidator, final DefaultHeaders.ValueValidator<CharSequence> valueValidator, final int sizeHint) {
        super(new CombinedHttpHeadersImpl(AsciiString.CASE_INSENSITIVE_HASHER, DefaultHttpHeaders.valueConverter(), ObjectUtil.checkNotNull(nameValidator, "nameValidator"), ObjectUtil.checkNotNull(valueValidator, "valueValidator"), sizeHint));
    }
    
    @Override
    public boolean containsValue(final CharSequence name, final CharSequence value, final boolean ignoreCase) {
        return super.containsValue(name, StringUtil.trimOws(value), ignoreCase);
    }
    
    private static final class CombinedHttpHeadersImpl extends DefaultHeaders<CharSequence, CharSequence, CombinedHttpHeadersImpl>
    {
        private static final int VALUE_LENGTH_ESTIMATE = 10;
        private CsvValueEscaper<Object> objectEscaper;
        private CsvValueEscaper<CharSequence> charSequenceEscaper;
        
        private CsvValueEscaper<Object> objectEscaper() {
            if (this.objectEscaper == null) {
                this.objectEscaper = new CsvValueEscaper<Object>() {
                    @Override
                    public CharSequence escape(final CharSequence name, final Object value) {
                        CharSequence converted;
                        try {
                            converted = DefaultHeaders.this.valueConverter().convertObject(value);
                        }
                        catch (final IllegalArgumentException e) {
                            throw new IllegalArgumentException("Failed to convert object value for header '" + (Object)name + '\'', e);
                        }
                        return StringUtil.escapeCsv(converted, true);
                    }
                };
            }
            return this.objectEscaper;
        }
        
        private CsvValueEscaper<CharSequence> charSequenceEscaper() {
            if (this.charSequenceEscaper == null) {
                this.charSequenceEscaper = new CsvValueEscaper<CharSequence>() {
                    @Override
                    public CharSequence escape(final CharSequence name, final CharSequence value) {
                        return StringUtil.escapeCsv(value, true);
                    }
                };
            }
            return this.charSequenceEscaper;
        }
        
        CombinedHttpHeadersImpl(final HashingStrategy<CharSequence> nameHashingStrategy, final ValueConverter<CharSequence> valueConverter, final NameValidator<CharSequence> nameValidator, final ValueValidator<CharSequence> valueValidator) {
            this(nameHashingStrategy, valueConverter, nameValidator, valueValidator, 16);
        }
        
        CombinedHttpHeadersImpl(final HashingStrategy<CharSequence> nameHashingStrategy, final ValueConverter<CharSequence> valueConverter, final NameValidator<CharSequence> nameValidator, final ValueValidator<CharSequence> valueValidator, final int sizeHint) {
            super(nameHashingStrategy, valueConverter, nameValidator, sizeHint, valueValidator);
        }
        
        @Override
        public Iterator<CharSequence> valueIterator(final CharSequence name) {
            final Iterator<CharSequence> itr = super.valueIterator(name);
            if (!itr.hasNext() || cannotBeCombined(name)) {
                return itr;
            }
            final Iterator<CharSequence> unescapedItr = StringUtil.unescapeCsvFields(itr.next()).iterator();
            if (itr.hasNext()) {
                throw new IllegalStateException("CombinedHttpHeaders should only have one value");
            }
            return unescapedItr;
        }
        
        @Override
        public List<CharSequence> getAll(final CharSequence name) {
            final List<CharSequence> values = super.getAll(name);
            if (values.isEmpty() || cannotBeCombined(name)) {
                return values;
            }
            if (values.size() != 1) {
                throw new IllegalStateException("CombinedHttpHeaders should only have one value");
            }
            return StringUtil.unescapeCsvFields(values.get(0));
        }
        
        @Override
        public CombinedHttpHeadersImpl add(final Headers<? extends CharSequence, ? extends CharSequence, ?> headers) {
            if (headers == this) {
                throw new IllegalArgumentException("can't add to itself.");
            }
            if (headers instanceof CombinedHttpHeadersImpl) {
                if (this.isEmpty()) {
                    this.addImpl(headers);
                }
                else {
                    for (final Map.Entry<? extends CharSequence, ? extends CharSequence> header : headers) {
                        this.addEscapedValue((CharSequence)header.getKey(), (CharSequence)header.getValue());
                    }
                }
            }
            else {
                for (final Map.Entry<? extends CharSequence, ? extends CharSequence> header : headers) {
                    this.add((CharSequence)header.getKey(), (CharSequence)header.getValue());
                }
            }
            return this;
        }
        
        @Override
        public CombinedHttpHeadersImpl set(final Headers<? extends CharSequence, ? extends CharSequence, ?> headers) {
            if (headers == this) {
                return this;
            }
            this.clear();
            return this.add(headers);
        }
        
        @Override
        public CombinedHttpHeadersImpl setAll(final Headers<? extends CharSequence, ? extends CharSequence, ?> headers) {
            if (headers == this) {
                return this;
            }
            for (final CharSequence key : headers.names()) {
                ((DefaultHeaders<CharSequence, V, T>)this).remove(key);
            }
            return this.add(headers);
        }
        
        @Override
        public CombinedHttpHeadersImpl add(final CharSequence name, final CharSequence value) {
            return this.addEscapedValue(name, this.charSequenceEscaper().escape(name, value));
        }
        
        @Override
        public CombinedHttpHeadersImpl add(final CharSequence name, final CharSequence... values) {
            return this.addEscapedValue(name, commaSeparate(name, this.charSequenceEscaper(), values));
        }
        
        @Override
        public CombinedHttpHeadersImpl add(final CharSequence name, final Iterable<? extends CharSequence> values) {
            return this.addEscapedValue(name, commaSeparate(name, this.charSequenceEscaper(), values));
        }
        
        @Override
        public CombinedHttpHeadersImpl addObject(final CharSequence name, final Object value) {
            return this.addEscapedValue(name, commaSeparate(name, this.objectEscaper(), value));
        }
        
        @Override
        public CombinedHttpHeadersImpl addObject(final CharSequence name, final Iterable<?> values) {
            return this.addEscapedValue(name, commaSeparate(name, this.objectEscaper(), values));
        }
        
        @Override
        public CombinedHttpHeadersImpl addObject(final CharSequence name, final Object... values) {
            return this.addEscapedValue(name, commaSeparate(name, this.objectEscaper(), values));
        }
        
        @Override
        public CombinedHttpHeadersImpl set(final CharSequence name, final CharSequence... values) {
            ((DefaultHeaders<CharSequence, CharSequence, Headers>)this).set(name, commaSeparate(name, this.charSequenceEscaper(), values));
            return this;
        }
        
        @Override
        public CombinedHttpHeadersImpl set(final CharSequence name, final Iterable<? extends CharSequence> values) {
            ((DefaultHeaders<CharSequence, CharSequence, Headers>)this).set(name, commaSeparate(name, this.charSequenceEscaper(), values));
            return this;
        }
        
        @Override
        public CombinedHttpHeadersImpl setObject(final CharSequence name, final Object value) {
            ((DefaultHeaders<CharSequence, CharSequence, Headers>)this).set(name, commaSeparate(name, this.objectEscaper(), value));
            return this;
        }
        
        @Override
        public CombinedHttpHeadersImpl setObject(final CharSequence name, final Object... values) {
            ((DefaultHeaders<CharSequence, CharSequence, Headers>)this).set(name, commaSeparate(name, this.objectEscaper(), values));
            return this;
        }
        
        @Override
        public CombinedHttpHeadersImpl setObject(final CharSequence name, final Iterable<?> values) {
            ((DefaultHeaders<CharSequence, CharSequence, Headers>)this).set(name, commaSeparate(name, this.objectEscaper(), values));
            return this;
        }
        
        private static boolean cannotBeCombined(final CharSequence name) {
            return HttpHeaderNames.SET_COOKIE.contentEqualsIgnoreCase(name);
        }
        
        private CombinedHttpHeadersImpl addEscapedValue(final CharSequence name, final CharSequence escapedValue) {
            final CharSequence currentValue = ((DefaultHeaders<CharSequence, CharSequence, T>)this).get(name);
            if (currentValue == null || cannotBeCombined(name)) {
                super.add(name, escapedValue);
            }
            else {
                ((DefaultHeaders<CharSequence, CharSequence, Headers>)this).set(name, commaSeparateEscapedValues(currentValue, escapedValue));
            }
            return this;
        }
        
        private static <T> CharSequence commaSeparate(final CharSequence name, final CsvValueEscaper<T> escaper, final T... values) {
            final StringBuilder sb = new StringBuilder(values.length * 10);
            if (values.length > 0) {
                final int end = values.length - 1;
                for (int i = 0; i < end; ++i) {
                    sb.append(escaper.escape(name, values[i])).append(',');
                }
                sb.append(escaper.escape(name, values[end]));
            }
            return sb;
        }
        
        private static <T> CharSequence commaSeparate(final CharSequence name, final CsvValueEscaper<T> escaper, final Iterable<? extends T> values) {
            final StringBuilder sb = (values instanceof Collection) ? new StringBuilder(((Collection)values).size() * 10) : new StringBuilder();
            final Iterator<? extends T> iterator = values.iterator();
            if (iterator.hasNext()) {
                T next = (T)iterator.next();
                while (iterator.hasNext()) {
                    sb.append(escaper.escape(name, next)).append(',');
                    next = (T)iterator.next();
                }
                sb.append(escaper.escape(name, next));
            }
            return sb;
        }
        
        private static CharSequence commaSeparateEscapedValues(final CharSequence currentValue, final CharSequence value) {
            return new StringBuilder(currentValue.length() + 1 + value.length()).append(currentValue).append(',').append(value);
        }
        
        private interface CsvValueEscaper<T>
        {
            CharSequence escape(final CharSequence p0, final T p1);
        }
    }
}
