package de.codeworld.modules.demo.ui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.vaadin.treegrid.container.Measurable;

import com.vaadin.data.Collapsible;
import com.vaadin.data.Item;
import com.vaadin.data.util.HierarchicalContainer;

import de.codeworld.modules.demo.pojo.StyleTreeData;
import de.codeworld.modules.demo.pojo.StyleTreeRow;

public class DemoFirstContainer extends HierarchicalContainer implements Collapsible, Measurable {

    private static final long serialVersionUID = -8508398611246515670L;

    public static final String DEACTIVATED = "deactivated";
    public static final String LAST_MODIFIED = "lastModified";
    public static final String STATUS = "status";
    public static final String NUMBER = "number";

    private final List<StyleTreeRow> rootItems = new ArrayList<>();
    private final Map<StyleTreeRow, List<StyleTreeRow>> childrens = new HashMap<>();
    private final Map<StyleTreeRow, Boolean> expandedNodes = new HashMap<>();
    private final List<StyleTreeRow> leaves = new ArrayList<>();

    public DemoFirstContainer() {
        addContainerProperty(DemoFirstContainer.NUMBER, String.class, "");
        addContainerProperty(DemoFirstContainer.STATUS, String.class, "");
        addContainerProperty(DemoFirstContainer.LAST_MODIFIED, Date.class, new Date());
        addContainerProperty(DemoFirstContainer.DEACTIVATED, Boolean.class, Boolean.TRUE);
    }

    public void setItems(final List<StyleTreeData> items) {
        for (final StyleTreeData row : items) {
            this.rootItems.add(row.getTreeRow());
            this.childrens.put(row.getTreeRow(), row.getChildrens());
            this.leaves.addAll(row.getChildrens());
        }

        this.rootItems.forEach(this::addRootItem);
    }

    private void addRootItem(final StyleTreeRow root) {
        final Item addItem = addItem(root);
        setProperties(addItem, root);
        setCollapsed(root, false);
    }

    @SuppressWarnings("unchecked")
    private void setProperties(final Item addItem, final StyleTreeRow root) {
        addItem.getItemProperty(DemoFirstContainer.NUMBER).setValue(root.getNumber());
        addItem.getItemProperty(DemoFirstContainer.STATUS).setValue(root.getStatus());
        addItem.getItemProperty(DemoFirstContainer.LAST_MODIFIED).setValue(root.getLastModified());
        addItem.getItemProperty(DemoFirstContainer.DEACTIVATED).setValue(root.getDeactivated());
    }

    @Override
    public int getDepth(Object itemId) {
        int depth = 0;
        while (!isRoot(itemId)) {
            depth++;
            itemId = getParent(itemId);
        }
        return depth;
    }

    @Override
    public void setCollapsed(final Object itemId, final boolean collapsed) {
        final StyleTreeRow item = (StyleTreeRow) itemId;
        this.expandedNodes.put(item, !collapsed);

        if (collapsed) {
            removeChildrenRecursively(itemId);
        } else {
            addChildren(item);
        }
    }

    private void addChildren(final StyleTreeRow item) {
        final List<StyleTreeRow> childrenList = this.childrens.getOrDefault(item, new ArrayList<StyleTreeRow>());
        for (final StyleTreeRow child : childrenList) {
            final StyleTreeRow addChild = addChild(child, item);
            if (Boolean.TRUE.equals(this.expandedNodes.get(addChild))) {
                addChildren(addChild);
            }
        }
    }

    private StyleTreeRow addChild(final StyleTreeRow child, final StyleTreeRow parentId) {
        final Item item = addItemAfter(parentId, child);
        setProperties(item, child);
        setParent(child, parentId);
        return child;
    }

    private boolean removeChildrenRecursively(final Object itemId) {
        boolean success = true;
        final Collection<?> children2 = getChildren(itemId);
        if (children2 != null) {
            final Object[] array = children2.toArray();
            for (final Object element : array) {
                final boolean removeItemRecursively = HierarchicalContainer.removeItemRecursively(this, element);
                if (!removeItemRecursively) {
                    success = false;
                }
            }
        }
        return success;
    }

    @Override
    public boolean isCollapsed(final Object itemId) {
        return !Boolean.TRUE.equals(this.expandedNodes.get(itemId));
    }

}
