/*-
 * ~~~~~~licensing~~~~~~
 * objects-core
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
package org.apache.karaf.cellar.shell;

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

import org.apache.karaf.cellar.core.Group;

// TODO move to base-support
public class SimpleGroupTree<T> {

	public Map<String, SimpleGroupTreeNode<T>> allNodes = new HashMap<>();
	
	public SimpleGroupTreeHelper<T> helper;
	
	public SimpleGroupTreeNode<T> root;
	
	public SimpleGroupTree(SimpleGroupTreeHelper<T> helper) {
		this.helper = helper;
		this.root = helper.createNode("@root");
	}
	
	public void load(List<T> objects) {
		
		for (T object: objects) {
			SimpleGroupTreeNode<T> node = get(helper.getId(object));
			node.object = object;
			String parentId = helper.getParentId(object);
			if (parentId != null && !parentId.isBlank())
				get(helper.getParentId(object)).addChild(node);
		}
		
	}
	
	public SimpleGroupTreeNode<T> get(String id) {
		if (!allNodes.containsKey(id)) {
			SimpleGroupTreeNode<T> node = helper.createNode(id);
			root.addChild(node);
			allNodes.put(id, node);
		}
		return allNodes.get(id);
	}
	

	public static class SimpleGroupTreeNode<T> {
		
		public String id;
		public T object;
		
		public List<SimpleGroupTreeNode<T>> children = new ArrayList<>();
		
		public SimpleGroupTreeNode<T> parent;
		
		public SimpleGroupTreeNode (String id) {
			this.id = id;
		}
		
		public void addChild(SimpleGroupTreeNode<T> child) {
			this.children.add(child);
			if (child.parent != null)
				child.parent.children.remove(child);
			child.parent = this;
		}
		
		public int getLevel() {
			if (parent == null)
				return 0;
			return parent.getLevel() + 1;
		}

		public String getId() {
			return id;
		}

		public T getObject() {
			return object;
		}
		
	}
	
	public static interface SimpleGroupTreeHelper<T> {
		
		String getId(T object);
		String getParentId(T object);
		
		SimpleGroupTreeNode<T> createNode(T object);
		SimpleGroupTreeNode<T> createNode(String id);
	}
	
	public static abstract class SimpleGroupTreeHelperCommon<T> implements SimpleGroupTreeHelper<T> {
		
		@Override
		public SimpleGroupTreeNode<T> createNode(String id) {
			SimpleGroupTreeNode<T> result = new SimpleGroupTreeNode<>(id); 
			return result;
		}

		@Override
		public SimpleGroupTreeNode<T> createNode(T object) {
			SimpleGroupTreeNode<T> result = new SimpleGroupTreeNode<>(getId(object));
			result.object = object;
			return result;
		}
		
	}  
	
	public static class GroupTreeHelper extends SimpleGroupTreeHelperCommon<GroupNode> {

		@Override
		public String getId(GroupNode object) {
			return object.group.getName();
		}

		@Override
		public String getParentId(GroupNode object) {
			return object.group.getParent();
		}
		
	}
	
	public static class GroupNode {
		
		public Group group;
		public boolean isLocal = false;
		public String nodesString = "";
		
	}
}
