package org.bouncycastle.est;


import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

class HttpUtil
{

    /**
     * Merge kv into comma separated set of key="value" pairs.
     *
     * @param prefix Optional prefix to apply, eg:  prefix key="value" (,key="value")
     * @param kv
     * @return
     */
    static String mergeCSL(String prefix, Map<String, String> kv)
    {
        StringWriter sw = new StringWriter();
        sw.write(prefix);
        sw.write(' ');
        boolean comma = false;
        for (Iterator it = kv.entrySet().iterator(); it.hasNext();)
        {
            Map.Entry<String, String> ent = (Map.Entry<String, String>)it.next();

            if (!comma)
            {
                comma = true;
            }
            else
            {
                sw.write(',');
            }

            sw.write(ent.getKey());
            sw.write("=\"");
            sw.write(ent.getValue());
            sw.write('"');
        }

        return sw.toString();
    }


    static Map<String, String> splitCSL(String skip, String src)
    {
        src = src.trim();
        if (src.startsWith(skip))
        {
            src = src.substring(skip.length());
        }

        return new PartLexer(src).Parse();
    }


    static class PartLexer
    {
        private final String src;
        int last = 0;
        int p = 0;

        PartLexer(String src)
        {
            this.src = src;
        }


        Map<String, String> Parse()
        {
            Map<String, String> out = new HashMap<String, String>();
            String key = null;
            String value = null;
            while (p < src.length())
            {
                skipWhiteSpace();

                key = consumeAlpha();
                if (key.length() == 0)
                {
                    throw new IllegalArgumentException("Expecting alpha label.");
                }
                skipWhiteSpace();
                if (!consumeIf('='))
                {
                    throw new IllegalArgumentException("Expecting assign: '='");
                }


                skipWhiteSpace();
                if (!consumeIf('"'))
                {
                    throw new IllegalArgumentException("Expecting start quote: '\"'");
                }
                discard();

                value = consumeUntil('"');
                discard(1);
                out.put(key, value);

                skipWhiteSpace();
                if (!consumeIf(','))
                {
                    break;
                }
                discard();
            }

            return out;
        }


        private String consumeAlpha()
        {
            char c = src.charAt(p);
            while (p < src.length() && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
            {
                p++;
                c = src.charAt(p);
            }
            String s = src.substring(last, p);
            last = p;
            return s;
        }

        private void skipWhiteSpace()
        {
            while (p < src.length() && (src.charAt(p) < 33))
            {
                p++;
            }
            last = p;
        }

        private boolean consumeIf(char c)
        {

            if (p < src.length() && src.charAt(p) == c)
            {
                p++;
                return true;
            }
            return false;
        }

        private String consumeUntil(char c)
        {
            while (p < src.length() && (src.charAt(p) != c))
            {
                p++;
            }
            String s = src.substring(last, p);
            last = p;
            return s;
        }

        private void discard()
        {
            last = p;
        }

        private void discard(int i)
        {
            p += i;
            last = p;
        }

    }

    static class Headers
        extends HashMap<String, String[]>
    {
        private static final String EMPTY = "";


        public Headers()
        {
            super();
        }

        public String getFirstValue(String key)
        {
            String[] j = getValues(key);
            if (j != null && j.length > 0)
            {
                return j[0];
            }
            return null;
        }

        public String getFirstValueOrEmpty(String key)
        {
            String[] j = getValues(key);
            if (j != null && j.length > 0)
            {
                return j[0];
            }
            return EMPTY;
        }

        public String[] getValues(String key)
        {
            key = actualKey(key);
            if (key == null)
            {
                return null;
            }
            return get(key);
        }

        private String actualKey(String header)
        {
            if (containsKey(header))
            {
                return header;
            }

            for (Iterator it = keySet().iterator(); it.hasNext();)
            {
                String k = (String)it.next();
                if (header.equalsIgnoreCase(k))
                {
                    return k;
                }
            }

            return null;
        }

        private boolean hasHeader(String header)
        {
            return actualKey(header) != null;
        }


        public void set(String key, String value)
        {
            put(key, new String[]{value});
        }

        public void add(String key, String value)
        {
            put(key, append(get(key), value));
        }

        public void ensureHeader(String key, String value)
        {
            if (!containsKey(key))
            {
                set(key, value);
            }
        }
        
        public Object clone()
        {
            Headers n = new Headers();
            for (Iterator it = entrySet().iterator(); it.hasNext();)
            {
                Map.Entry v = (Map.Entry)it.next();

                n.put((String)v.getKey(), copy((String[])v.getValue()));
            }
            return n;
        }

        private String[] copy(String[] vs)
        {
            String[] rv = new String[vs.length];

            System.arraycopy(vs, 0, rv, 0, rv.length);
            
            return rv;
        }
    }


    public static String[] append(String[] a, String b)
    {
        if (a == null)
        {
            return new String[]{b};
        }

        int length = a.length;
        String[] result = new String[length + 1];
        System.arraycopy(a, 0, result, 0, length);
        result[length] = b;
        return result;
    }

}
