/* UtilLib - Copyright (c) 2012-2019 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.request;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.AbstractList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.RandomAccess;
import java.util.Set;
import net.mapeadores.util.attr.AttributeUtils;
import net.mapeadores.util.attr.Attributes;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.LangPreferenceBuilder;
import net.mapeadores.util.mimetype.MimeTypeConstants;
import net.mapeadores.util.request.xml.RequestConfDOMReader;
import net.mapeadores.util.xml.DOMUtils;
import org.w3c.dom.Document;


/**
 *
 * @author Vincent Calame
 */
public final class RequestUtils {

    public final static List<SupplementaryParameter> EMPTY_SUPPLEMENTARYPARAMETERLIST = Collections.emptyList();
    public final static RequestConf EMPTY_REQUESTCONF = new EmptyRequestConf();

    private RequestUtils() {
    }

    public static AppendableRequestMap merge(RequestMap requestMap, List<SupplementaryParameter> supplementaryParameterList) {
        AppendableRequestMap appendableRequestMap = new AppendableRequestMap(requestMap);
        appendableRequestMap.addSupplementaryParameters(supplementaryParameterList);
        return appendableRequestMap;
    }

    public static RequestConf parseRequestConf(File f) throws IOException {
        Document document = DOMUtils.readDocument(f);
        return parseRequestConf(document);
    }

    public static RequestConf parseRequestConf(Document document) {
        RequestConfBuilder requestConfBuilder = new RequestConfBuilder();
        RequestConfDOMReader reader = new RequestConfDOMReader(requestConfBuilder);
        reader.readConf(document.getDocumentElement());
        return requestConfBuilder.toRequestConf();
    }

    public static short getJsonType(RequestMap requestMap) {
        String jsonType = requestMap.getParameter(RequestConstants.JSONTYPE_PARAMETER);
        if (jsonType == null) {
            if (requestMap.getParameter(RequestConstants.CALLBACK_PARAMETER) != null) {
                return JsonType.JSON_P_TYPE;
            } else {
                return JsonType.JSON_TYPE;
            }
        }
        switch (jsonType) {
            case JsonType.JSON_P_STRING:
                return JsonType.JSON_P_TYPE;
            case JsonType.JSON_IN_HTML_STRING:
                return JsonType.JSON_IN_HTML_TYPE;
            default:
                return JsonType.JSON_TYPE;
        }
    }

    public static boolean isJsonDefined(RequestMap requestMap) {
        OutputInfo outputInfo = OutputInfo.buildFromRequest(requestMap);
        return (outputInfo.getType() == OutputInfo.JSON_TYPE);
    }

    public static String jsonTypeToContentType(short jsonType) {
        switch (jsonType) {
            case JsonType.JSON_TYPE:
                return MimeTypeConstants.JSON;
            case JsonType.JSON_IN_HTML_TYPE:
                return MimeTypeConstants.HTML + ";charset=UTF-8";
            case JsonType.JSON_P_TYPE:
                return MimeTypeConstants.JAVASCRIPT + ";charset=UTF-8";
            default:
                throw new IllegalArgumentException("Unknown type: " + jsonType);
        }
    }

    public static Lang getDefaultLang(RequestMap requestMap) {
        return checkLangPreference(requestMap, new LangPreferenceBuilder())
                .addLang(Lang.build("en"))
                .toLangPreference()
                .getFirstLang();
    }

    public static LangPreferenceBuilder checkLangPreference(RequestMap requestMap, LangPreferenceBuilder langPreferenceBuilder) {
        String localeParameter = requestMap.getParameter(RequestConstants.LOCALE_PARAMETER);
        if (localeParameter != null) {
            try {
                Lang lang = Lang.parse(localeParameter);
                langPreferenceBuilder.addLang(lang);
            } catch (ParseException pe) {
            }
        }
        Locale[] acceptableLocaleArray = requestMap.getAcceptableLocaleArray();
        if (acceptableLocaleArray != null) {
            int length = acceptableLocaleArray.length;
            for (int i = 0; i < length; i++) {
                try {
                    Lang lang = Lang.fromLocale(acceptableLocaleArray[i]);
                    langPreferenceBuilder.addLang(lang);
                } catch (ParseException pe) {

                }
            }
        }
        return langPreferenceBuilder;
    }

    public static List<SupplementaryParameter> wrap(SupplementaryParameter[] array) {
        return new SupplementaryParameterList(array);
    }

    public static RequestMap reduceToSuffix(RequestMap requestMap, String suffix) {
        if ((suffix == null) || (suffix.isEmpty())) {
            return requestMap;
        }
        return new SuffixRequestMap(requestMap, suffix);
    }


    private static class EmptyRequestConf implements RequestConf {

        private EmptyRequestConf() {
        }

        @Override
        public List<SupplementaryParameter> getSupplementaryParameterList() {
            return EMPTY_SUPPLEMENTARYPARAMETERLIST;
        }

        @Override
        public Attributes getAttributes() {
            return AttributeUtils.EMPTY_ATTRIBUTES;
        }

    }


    private static class SupplementaryParameterList extends AbstractList<SupplementaryParameter> implements RandomAccess {

        private final SupplementaryParameter[] array;

        private SupplementaryParameterList(SupplementaryParameter[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public SupplementaryParameter get(int index) {
            return array[index];
        }

    }


    private static class SuffixRequestMap implements RequestMap {

        private final RequestMap requestMap;
        private final String suffix;
        private final Set<String> paramNameSet;

        private SuffixRequestMap(RequestMap requestMap, String suffix) {
            this.requestMap = requestMap;
            this.suffix = suffix;
            int suffixLength = suffix.length();
            Set<String> set = new HashSet<String>();
            for (String paramName : requestMap.getParameterNameSet()) {
                if (paramName.startsWith(suffix)) {
                    set.add(paramName.substring(suffixLength));
                }
            }
            this.paramNameSet = Collections.unmodifiableSet(set);
        }

        @Override
        public FileValue getFileValue(String name) {
            return requestMap.getFileValue(suffix + name);
        }

        @Override
        public FileValue[] getFileValues(String name) {
            return requestMap.getFileValues(suffix + name);
        }

        @Override
        public String getParameter(String name) {
            return requestMap.getParameter(suffix + name);
        }

        @Override
        public String[] getParameterValues(String name) {
            return requestMap.getParameterValues(suffix + name);
        }

        @Override
        public Set<String> getParameterNameSet() {
            return paramNameSet;
        }


        @Override
        public Locale[] getAcceptableLocaleArray() {
            return requestMap.getAcceptableLocaleArray();
        }

        @Override
        public Object getSourceObject() {
            return requestMap.getSourceObject();
        }

    }

}
