/*-
 * ~~~~~~licensing~~~~~~
 * test-producers
 * ==========
 * 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 ru.entaxy.platform.base.objects.shell;

import java.util.List;
import java.util.stream.Collectors;

import org.apache.karaf.shell.api.action.Action;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.shell.support.table.ShellTable;

import ru.entaxy.platform.base.objects.EntaxyObject;
import ru.entaxy.platform.base.objects.EntaxyObject.OBJECT_RELATION;
import ru.entaxy.platform.base.objects.shell.SimpleObjectTree.SimpleObjectTreeHelperCommon;
import ru.entaxy.platform.base.objects.shell.SimpleObjectTree.SimpleObjectTreeNode;

@Service
@Command(name = "object-list", scope = EntaxyObjectServiceSupport.OBJECTS_SCOPE)
public class ListObjects extends EntaxyObjectServiceSupport implements Action {

    @Option(name = "-t", aliases = {"--tree"}, description = "Display factory tree")
    boolean asTree;

    @Option(name = "-f", aliases = {"--show-full-id"}, description = "Show full Id")
    boolean showFullId = false;

    @Override
    public Object execute() throws Exception {

        ShellTable shellTable = new ShellTable();
        shellTable.column("Id");
        shellTable.column("Type");
        shellTable.column("Provided");
        shellTable.column("Complete");
        shellTable.column("Scope");
        if (showFullId)
            shellTable.column("Full Id");
        shellTable.column("Factory");
        shellTable.column("Bundle");

        if (!asTree) {

            for (EntaxyObject object : objectService.getObjects())
                if (showFullId) {
                    shellTable.addRow().addContent(
                            (object.isGhost()
                                    ? "? "
                                    : "") + object.getId(),
                            object.getType(),
                            (object.isProvided() ? "*" : ""),
                            (object.isComplete() ? "*" : ""),
                            object.getScope(),
                            object.getObjectFullId(),
                            object.getFactoryId(),
                            object.getBundleInfo() == null
                                    ? ""
                                    : object.getBundleInfo().getBundleId());
                } else {
                    shellTable.addRow().addContent(
                            (object.isGhost()
                                    ? "? "
                                    : "") + object.getId(),
                            object.getType(),
                            (object.isProvided() ? "*" : ""),
                            (object.isComplete() ? "*" : ""),
                            object.getScope(),
                            object.getFactoryId(),
                            object.getBundleInfo() == null
                                    ? ""
                                    : object.getBundleInfo().getBundleId());
                }
        } else {
            SimpleObjectTree<EntaxyObject> tree = new SimpleObjectTree<>(new EntaxyObjectHelper());
            tree.load(objectService.getObjects());
            for (SimpleObjectTreeNode<EntaxyObject> node : tree.root.children)
                addRowToTable(shellTable, node);
        }


        shellTable.print(System.out);

        return null;
    }

    protected String getLevelPrefix(SimpleObjectTreeNode<EntaxyObject> node) {
        String result = "";
        for (int i = 0; i < node.getLevel() - 1; i++)
            result = result.concat("  ");
        return result;
    }

    protected void addRowToTable(ShellTable table, SimpleObjectTreeNode<EntaxyObject> node) {
        if (node.getObject() == null) {
            table.addRow().addContent(
                    getLevelPrefix(node) + node.getId().split(":")[0],
                    getLevelPrefix(node) + node.getId().split(":")[1], "", "", "", node.getId(), "", "");

        } else {
            EntaxyObject object = node.getObject();
            if (showFullId) {
                table.addRow().addContent(
                        getLevelPrefix(node) + (object.isGhost()
                                ? "? "
                                : "") + object.getId(),
                        object.getType(), booleanToString(object.isProvided()), booleanToString(object.isComplete()),
                        object.getScope(), object.getObjectFullId(), object.getFactoryId(),
                        (object.isGhost() ? "" : object.getBundleInfo().getBundleId()));
            } else {
                table.addRow().addContent(
                        getLevelPrefix(node) + (object.isGhost()
                                ? "? "
                                : "") + object.getId(),
                        object.getType(), booleanToString(object.isProvided()), booleanToString(object.isComplete()),
                        object.getScope(), object.getFactoryId(),
                        (object.isGhost() ? "" : object.getBundleInfo().getBundleId()));
            }
        }
        for (SimpleObjectTreeNode<EntaxyObject> child : node.children) {
            addRowToTable(table, child);
        }
    }

    protected String booleanToString(boolean b) {
        return b ? "*" : "";
    }

    protected class EntaxyObjectHelper extends SimpleObjectTreeHelperCommon<EntaxyObject> {

        @Override
        public String getId(EntaxyObject object) {
            return object.getObjectFullId();
        }

        @Override
        public String getParentId(EntaxyObject object) {
            final String fullId = object.getObjectFullId();
            List<EntaxyObject.Relation> candidates = objectService.getObjects()
                    .stream()
                    .filter(obj -> !obj.getRelations().isEmpty())
                    .map(obj -> obj.getRelations())
                    .flatMap(List::stream)
                    .filter(r -> r.isSubordinating())
                    .filter(r -> fullId.equals(r.getTarget().getObjectFullId()))
                    .collect(Collectors.toList());
            if (candidates.isEmpty())
                return null;
            EntaxyObject parent = null;
            for (EntaxyObject.Relation relation : candidates)
                if (relation.getType().equals(OBJECT_RELATION.COMPOSITION)) {
                    parent = relation.getSource();
                    break;
                }

            parent = candidates.get(0).getSource();

            return parent.getObjectFullId();
        }

    }

}
