package eu.eudat.models.data.components.commons.datafield;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AutoCompleteData extends ComboBoxData<AutoCompleteData> {
    public static class AutoCompleteSingleData {
        private int autocompleteType;
        private String url;
        private ComboBoxData.Option autoCompleteOptions;
        private String optionsRoot;

        public int getAutocompleteType() {
            return autocompleteType;
        }

        public void setAutocompleteType(int autocompleteType) {
            this.autocompleteType = autocompleteType;
        }

        public String getOptionsRoot() {
            return optionsRoot;
        }
        public void setOptionsRoot(String optionsRoot) {
            this.optionsRoot = optionsRoot;
        }

        public String getUrl() {
            return url;
        }
        public void setUrl(String url) {
            this.url = url;
        }

        public ComboBoxData.Option getAutoCompleteOptions() {
            return autoCompleteOptions;
        }
        public void setAutoCompleteOptions(ComboBoxData.Option autoCompleteOptions) {
            this.autoCompleteOptions = autoCompleteOptions;
        }
    }

    private Boolean multiAutoComplete;
    private List<AutoCompleteSingleData> autoCompleteSingleDataList;

    public Boolean getMultiAutoComplete() { return multiAutoComplete; }
    public void setMultiAutoComplete(Boolean multiAutoComplete) { this.multiAutoComplete = multiAutoComplete; }

    public List<AutoCompleteSingleData> getAutoCompleteSingleDataList() {
        return autoCompleteSingleDataList;
    }

    public void setAutoCompleteSingleDataList(List<AutoCompleteSingleData> autoCompleteSingleDataList) {
        this.autoCompleteSingleDataList = autoCompleteSingleDataList;
    }

    @Override
    public Element toXml(Document doc) {
        Element root = super.toXml(doc);
        if (this.multiAutoComplete != null)
            root.setAttribute("multiAutoComplete", this.multiAutoComplete.toString());
        for (AutoCompleteSingleData singleData: this.autoCompleteSingleDataList) {
            Element parent = doc.createElement("autocompleteSingle");
            parent.setAttribute("url", singleData.url);
            parent.setAttribute("optionsRoot", singleData.optionsRoot);
            parent.setAttribute("autoCompleteType", Integer.toString(singleData.autocompleteType));
            Element element = doc.createElement("option");
            element.setAttribute("label", singleData.autoCompleteOptions.getLabel());
            element.setAttribute("value", singleData.autoCompleteOptions.getValue());
            element.setAttribute("source", singleData.autoCompleteOptions.getSource());
            parent.appendChild(element);
            root.appendChild(parent);
        }
        return root;
    }

    @Override
    public AutoCompleteData fromXml(Element item) {
        super.fromXml(item);
        this.autoCompleteSingleDataList = new ArrayList<>();
        NodeList items = item.getElementsByTagName("autocompleteSingle");
        if (items != null && items.getLength() > 0) {
            for (int i = 0; i < items.getLength(); i++) {
                this.autoCompleteSingleDataList.add(new AutoCompleteSingleData());
                Element single = (Element) items.item(i);
                this.mapFromXml(single, this.autoCompleteSingleDataList.get(i));
            }
        } else {
            this.autoCompleteSingleDataList.add(new AutoCompleteSingleData());
            this.mapFromXml(item, this.autoCompleteSingleDataList.get(0));
        }
        this.multiAutoComplete = Boolean.parseBoolean(item.getAttribute("multiAutoComplete"));
        return this;
    }

    private void mapFromXml(Element item, AutoCompleteSingleData singleData) {
        singleData.url = item.getAttribute("url");
        singleData.optionsRoot = item.getAttribute("optionsRoot");
        this.multiAutoComplete = Boolean.parseBoolean(item.getAttribute("multiAutoComplete"));
        if (item.getAttribute("autoCompleteType") == null || item.getAttribute("autoCompleteType").equals("") ) {
            singleData.autocompleteType = AutocompleteType.UNCACHED.getValue();
        } else {
            singleData.autocompleteType = AutocompleteType.fromValue(Integer.parseInt(item.getAttribute("autoCompleteType"))).getValue();
        }
        Element optionElement = (Element) item.getElementsByTagName("option").item(0);
        if (optionElement != null) {
            singleData.autoCompleteOptions = new Option();
            singleData.autoCompleteOptions.setLabel(optionElement.getAttribute("label"));
            singleData.autoCompleteOptions.setValue(optionElement.getAttribute("value"));
            singleData.autoCompleteOptions.setSource(optionElement.getAttribute("source"));
            singleData.autoCompleteOptions.setUri(optionElement.getAttribute("uri"));
        }
    }

    @Override
    public AutoCompleteData fromData(Object data) {
        super.fromData(data);
        this.autoCompleteSingleDataList = new ArrayList<>();



        if (data != null) {
            this.multiAutoComplete = (Boolean) ((Map<Boolean, Object>) data).get("multiAutoComplete");

            List<Map<String, Object>> dataList = (List<Map<String, Object>>) ((Map<String, Object>) data).get("autocompleteSingle");
            if (dataList == null) {
                dataList = (List<Map<String, Object>>) ((Map<String, Object>) data).get("autoCompleteSingleDataList");
            }

            this.autoCompleteSingleDataList = new ArrayList<>();

            int i = 0;
            for (Map<String, Object> singleData: dataList) {
                this.autoCompleteSingleDataList.add(new AutoCompleteSingleData());
                this.autoCompleteSingleDataList.get(i).autoCompleteOptions = new Option();
                this.autoCompleteSingleDataList.get(i).url = (String) singleData.get("url");
                this.autoCompleteSingleDataList.get(i).optionsRoot = (String) singleData.get("optionsRoot");

                if (singleData.get("autoCompleteType") == null) {
                    this.autoCompleteSingleDataList.get(i).autocompleteType = AutocompleteType.UNCACHED.getValue();
                } else {
                    this.autoCompleteSingleDataList.get(i).autocompleteType = AutocompleteType.fromValue((Integer) singleData.get("autoCompleteType")).getValue();
                }
                Map<String, String> options = (Map<String, String>) singleData.get("autoCompleteOptions");
                if (options != null) {
                    this.autoCompleteSingleDataList.get(i).autoCompleteOptions.setLabel(options.get("label"));
                    this.autoCompleteSingleDataList.get(i).autoCompleteOptions.setValue(options.get("value"));
                    this.autoCompleteSingleDataList.get(i).autoCompleteOptions.setSource(options.get("source"));
                    this.autoCompleteSingleDataList.get(i).autoCompleteOptions.setUri(options.get("uri"));
                }
                i++;
            }
        }

        return this;
    }

    @Override
    public Object toData() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Map<String, Object> toMap(Element item) {
        HashMap dataMap = new HashMap();
        dataMap.put("label", item != null ? item.getAttribute("label") : "");
        //dataMap.put("url", item != null ? item.getAttribute("url") : "");
        dataMap.put("type", item != null ? item.getAttribute("type") : "autocomplete");
        dataMap.put("multiAutoComplete", item != null ? Boolean.valueOf(item.getAttribute("multiAutoComplete")) : false);
        List<Map<String, Object>> autoCompletes = new ArrayList<>();
        NodeList autoCompleteSingles = item.getChildNodes();
        for (int i = 0; i < autoCompleteSingles.getLength(); i++) {
            if (autoCompleteSingles.item(i) instanceof Element) {
                if (!((Element) autoCompleteSingles.item(i)).getTagName().equals("option")) {
                    Element node = (Element) autoCompleteSingles.item(i);
                    if (!node.hasChildNodes()) {
                        node.appendChild(node);
                    }

                    autoCompletes.add(singleToMap(node));
                } else {
                    Element node = item.getOwnerDocument().createElement("autocompleteSingle");
                    node.appendChild(autoCompleteSingles.item(i));
                    node.setAttribute("url", item.getAttribute("url"));
                    node.setAttribute("optionsRoot", item.getAttribute("optionsRoot"));
                    autoCompletes.add(singleToMap(node));
                }
            }
        }
        dataMap.put("autocompleteSingle", autoCompletes);
        //dataMap.put("optionsRoot", item != null ? item.getAttribute("optionsRoot") : "");
        //Element optionElement = (Element) item.getElementsByTagName("option").item(0);
//        if (optionElement != null) {
//            this.autoCompleteOptions = new Option();
//            this.autoCompleteOptions.setLabel(optionElement.getAttribute("label"));
//            this.autoCompleteOptions.setValue(optionElement.getAttribute("value"));
//        }
       // dataMap.put("autoCompleteOptions", item != null ? optionToMap(optionElement) : null);
        return dataMap;
    }

    private Map<String, Object> optionToMap(Element item){
        HashMap dataMap = new HashMap();
        dataMap.put("label", item != null ? item.getAttribute("label") : "");
        dataMap.put("value", item != null ? item.getAttribute("value") : "");
        dataMap.put("source", item != null ? item.getAttribute("source") : "");
        return dataMap;
    }

    private Map<String, Object> singleToMap(Element item) {
        Map<String, Object> dataMap = new HashMap<>();
        if (!item.getAttribute("autoCompleteType").isEmpty()) {
            dataMap.put("autoCompleteType", Integer.parseInt(item.getAttribute("autoCompleteType")));
        }
        dataMap.put("optionsRoot", item != null ? item.getAttribute("optionsRoot") : "");
        dataMap.put("url", item != null ? item.getAttribute("url") : "");
        Element optionElement = (Element) item.getElementsByTagName("option").item(0);
        dataMap.put("autoCompleteOptions", item != null ? optionToMap(optionElement) : null);
        return dataMap;
    }

    public enum AutocompleteType {
        UNCACHED(0), CACHED(1);

        int value;

        AutocompleteType(int value) {
            this.value = value;
        }

        public int getValue() {
            return this.value;
        }

        public static AutocompleteType fromValue(int value) {
            for (AutocompleteType type: AutocompleteType.values()) {
                if (type.getValue() == value) {
                    return type;
                }
            }
            return UNCACHED;
        }
    }
}


