

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of PSYCLONE version 2.1.1.260726 (26 July 2026)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2026
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  PSYCLONE 2.1 is released under the GNU Lesser General Public License 
//_/_/  (LGPL) version 3.0, and is subject to the following
//_/_/  
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/    
//_/_/  A commercial license for PSYCLONE 2.1 is also available to 
//_/_/  any interested party from the copyright holder.
//_/_/  
//_/_/  You can redistribute this copy of PSYCLONE 2.1 and/or modify it under 
//_/_/  the terms of the GNU General Public License as published by the Free 
//_/_/  Software Foundation, either version 3 of the License, or (at your 
//_/_/  option) any later version.
//_/_/  
//_/_/  You should have received a copy of the GNU General Public License
//_/_/  and the GNU Lesser General Public License along with PSYCLONE 2.1.  
//_/_/  If not, see <http://www.gnu.org/licenses/>.
//_/_/  
//_/_/  PSYCLONE 2.1 is distributed in the hope that it will be useful,
//_/_/  but WITHOUT ANY WARRANTY; without even the implied warranty of
//_/_/  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//_/_/  GNU General Public License for more details.
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#if !defined(_SUBSCRIPTIONENGINE_H_)
#define _SUBSCRIPTIONENGINE_H_

#pragma once

#include "MemoryManager.h"
#include "PsyAPI.h"
#include <map>
#include <queue>

namespace	cmlabs{

class SubscriptionEngine;

class SubTriggers {
public:
	SubTriggers(SubscriptionEngine* engine, uint8 level, uint16 subType);
	~SubTriggers();

	uint8 level;
	uint16 subType;
	uint32 getTriggersForMsg(DataMessage* msg, std::list<TriggerSpec*>* triggers);
	std::string printFriendlyTriggersForMsg(DataMessage* msg);
	bool addSubscription(uint32 compID, TriggerSpec* trigger);
	bool removeSubscription(uint32 compID);

	TriggerSpec* findTrigger(uint32 compID, const char* name);
	std::list<PostSpec*>* findPosts(uint32 compID, const char* name);
	bool getAllTriggers(std::map<uint32, std::list<TriggerSpec*> > &triggerMap);

	std::string printFriendly();
	std::string printFriendlyHTML();
	std::string toXML();
	std::string printTriggerFriendly(TriggerSpec* trigger, const char* tab);
	std::string printTriggerFriendlyHTML(TriggerSpec* trigger);

private:
	SubscriptionEngine* engine;
	std::map<uint16, SubTriggers*> subTriggers;
	std::list<TriggerSpec*> levelTriggers;
};

class Node;
class SubscriptionEngine {
public:
	SubscriptionEngine(Node* node);
	~SubscriptionEngine();

	bool addSubscription(uint32 compID, std::list<TriggerSpec*> &triggers);
	bool removeSubscription(uint32 compID);

	bool syncSubscriptions(DataMessage* msg);
	bool writeTriggersToMsg(DataMessage* msg);

	bool syncContexts(DataMessage* msg);
	bool writeContextsToMsg(DataMessage* msg);

	std::string typeToText(PsyType type);
	std::string subTypeToText(uint16 subType);
	std::string contextToText(PsyContext context);
	std::string subContextToText(uint16 subcontext);
	std::string getComponentName(uint32 compID);

	bool registerSubTrigger(SubTriggers* sub, uint32 compID);

	std::string printFriendlyTriggersForMsg(DataMessage* msg);
	std::list<TriggerSpec*>* getTriggersForMsg(DataMessage* msg);
	// Fill-in-place variant used by the message routing hot path: avoids the
	// per-message heap allocation of the returned list. The list is cleared first.
	void getTriggersForMsg(DataMessage* msg, std::list<TriggerSpec*>& triggers);

	bool setContextActive(const PsyContext& activeContext, const PsyContext& inactiveContext);
	bool setContextInactive(const PsyContext& inactiveContext);
	bool processContext(const PsyContext& context);
	bool isContextActive(const PsyContext& context);

	TriggerSpec* findTrigger(uint32 compID, const char* name);
	std::list<PostSpec*>* findPosts(uint32 compID, const char* name);
	bool getAllTriggers(std::map<uint32, std::list<TriggerSpec*> > &triggerMap);

	std::string printFriendly();
	std::string printFriendlyHTML();
	std::string toXML();
	std::string activeContextsXML();

private:
	bool addSubscription(uint32 compID, TriggerSpec* trigger);
	std::map<uint16, SubTriggers*> subTriggers;
	//std::list<TriggerSpec*> levelTriggers;
	std::map<uint32, std::list<SubTriggers*> > compIDSubTriggers;
	std::map<PsyContext, uint64> activeContexts;
	std::map<PsyContext, uint64> inactiveContexts;
	utils::Mutex entranceMutex;
	utils::Mutex writeMutex;
	uint32 currentReaders;
	Node* node;
};

}
#endif // _SUBSCRIPTIONENGINE_H_
