001/*
002 * Copyright 2025 devteam@scivicslab.com
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing,
011 * software distributed under the License is distributed on an
012 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied.  See the License for the
014 * specific language governing permissions and limitations
015 * under the License.
016 */
017
018package com.scivicslab.actoriac.report.sections.basic;
019
020import com.scivicslab.actoriac.log.DistributedLogStore;
021import com.scivicslab.pojoactor.core.Action;
022import com.scivicslab.pojoactor.core.ActionResult;
023import com.scivicslab.pojoactor.workflow.IIActorRef;
024import com.scivicslab.pojoactor.workflow.IIActorSystem;
025
026import java.sql.Connection;
027import java.util.logging.Logger;
028
029/**
030 * IIAR wrapper for {@link TransitionHistorySection}.
031 *
032 * <p>Exposes the POJO's methods as actions via {@code @Action} annotations.
033 * Handles database connection and session ID retrieval from the system.</p>
034 *
035 * <h2>Usage in workflow YAML:</h2>
036 *
037 * <p>Basic usage (shows nodeGroup transitions):</p>
038 * <pre>{@code
039 * - actor: loader
040 *   method: createChild
041 *   arguments: ["reportBuilder", "transitions", "...TransitionHistorySectionIIAR"]
042 * }</pre>
043 *
044 * <p>With target actor specified (using ":" separator):</p>
045 * <pre>{@code
046 * - actor: loader
047 *   method: createChild
048 *   arguments: ["reportBuilder", "trans:node-server1", "...TransitionHistorySectionIIAR"]
049 * }</pre>
050 *
051 * <p>Include children (add ":children" suffix):</p>
052 * <pre>{@code
053 * - actor: loader
054 *   method: createChild
055 *   arguments: ["reportBuilder", "trans:nodeGroup:children", "...TransitionHistorySectionIIAR"]
056 * }</pre>
057 *
058 * @author devteam@scivicslab.com
059 * @since 2.16.0
060 */
061public class TransitionHistorySectionIIAR extends IIActorRef<TransitionHistorySection> {
062
063    private static final Logger logger = Logger.getLogger(TransitionHistorySectionIIAR.class.getName());
064
065    /**
066     * Constructs the IIAR with a new POJO instance.
067     *
068     * <p>The actor name is parsed to extract target actor and options:</p>
069     * <ul>
070     *   <li>"transitions" → target=nodeGroup, includeChildren=false</li>
071     *   <li>"trans:node-server1" → target=node-server1, includeChildren=false</li>
072     *   <li>"trans:nodeGroup:children" → target=nodeGroup, includeChildren=true</li>
073     * </ul>
074     *
075     * @param actorName the actor name (may encode target actor)
076     * @param system the actor system
077     */
078    public TransitionHistorySectionIIAR(String actorName, IIActorSystem system) {
079        super(actorName, new TransitionHistorySection(), system);
080        parseActorName(actorName);
081        initializeFromSystem();
082    }
083
084    /**
085     * Parses the actor name to extract target actor and options.
086     */
087    private void parseActorName(String actorName) {
088        if (actorName == null) {
089            object.setTargetActorName("nodeGroup");
090            return;
091        }
092
093        // Format: "prefix:targetActor" or "prefix:targetActor:children"
094        String[] parts = actorName.split(":", 3);
095        if (parts.length >= 2) {
096            object.setTargetActorName(parts[1]);
097            if (parts.length >= 3 && "children".equals(parts[2])) {
098                object.setIncludeChildren(true);
099            }
100        } else {
101            // No ":" - default to nodeGroup
102            object.setTargetActorName("nodeGroup");
103        }
104    }
105
106    /**
107     * Initializes the POJO with database connection and session ID.
108     */
109    private void initializeFromSystem() {
110        // Get database connection from DistributedLogStore
111        DistributedLogStore logStore = DistributedLogStore.getInstance();
112        if (logStore != null) {
113            Connection conn = logStore.getConnection();
114            if (conn != null) {
115                object.setConnection(conn);
116                logger.fine("TransitionHistorySectionIIAR: initialized database connection");
117            }
118        }
119
120        // Get session ID from nodeGroup
121        long sessionId = getSessionIdFromNodeGroup();
122        if (sessionId >= 0) {
123            object.setSessionId(sessionId);
124            logger.fine("TransitionHistorySectionIIAR: initialized sessionId=" + sessionId);
125        }
126    }
127
128    /**
129     * Retrieves session ID from nodeGroup actor.
130     */
131    private long getSessionIdFromNodeGroup() {
132        if (actorSystem == null || !(actorSystem instanceof IIActorSystem)) {
133            return -1;
134        }
135        IIActorSystem iiSystem = (IIActorSystem) actorSystem;
136
137        IIActorRef<?> nodeGroup = iiSystem.getIIActor("nodeGroup");
138        if (nodeGroup == null) {
139            return -1;
140        }
141
142        ActionResult result = nodeGroup.callByActionName("getSessionId", "");
143        if (result.isSuccess()) {
144            try {
145                return Long.parseLong(result.getResult());
146            } catch (NumberFormatException e) {
147                logger.warning("TransitionHistorySectionIIAR: invalid sessionId: " + result.getResult());
148            }
149        }
150        return -1;
151    }
152
153    // ========================================================================
154    // Actions - expose POJO methods
155    // ========================================================================
156
157    @Action("generate")
158    public ActionResult generate(String args) {
159        String content = object.generate();
160        return new ActionResult(true, content);
161    }
162
163    @Action("getTitle")
164    public ActionResult getTitle(String args) {
165        String title = object.getTitle();
166        return new ActionResult(true, title != null ? title : "");
167    }
168
169    /**
170     * Sets the target actor name dynamically.
171     *
172     * @param args the target actor name
173     * @return action result
174     */
175    @Action("setTargetActor")
176    public ActionResult setTargetActor(String args) {
177        if (args != null && !args.isEmpty()) {
178            object.setTargetActorName(args.trim());
179        }
180        return new ActionResult(true, "Target actor set");
181    }
182
183    /**
184     * Sets whether to include children.
185     *
186     * @param args "true" or "false"
187     * @return action result
188     */
189    @Action("setIncludeChildren")
190    public ActionResult setIncludeChildren(String args) {
191        boolean include = "true".equalsIgnoreCase(args);
192        object.setIncludeChildren(include);
193        return new ActionResult(true, "Include children: " + include);
194    }
195}