

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.0.0.170915_Beta4 (15 September 2017)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2017
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - 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. 
//_/_/
//_/_/  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(_TEMPORALMEMORY_H_)
#define _TEMPORALMEMORY_H_

#include "MemoryManager.h"
#include "PsyTime.h"

namespace cmlabs {

	struct SlotEntryStruct {
		uint16 serial; // wraps around
		uint64 eol;
		uint32 bin;
		uint64 offset;
		uint64 size; // if 0 not in use
		uint64 usage; // blocks used * blocksize >= size
		uint32 startBlock;
		uint32 blockUsage;
		//uint32 blockSize;
	};

	struct TemporalMemoryStruct {
		uint64 size;
		uint32 cid;
		uint32 slotCount;
		uint32 slotsInUse;
		uint64 usage;
		uint64 growStep;
		uint64 maxSize;
		uint64 createdTime;		// time of creation
		uint64 lastCheckTime;
		uint64 checkTimeInterval;
		uint16 binCount;
		uint32 bitFieldSize; // number of bytes in the bitfield
		// Bitfield(bitFieldSize)
		// slotCount * SlotEntryStruct
		// bin0(size), bin1(size), bin2(size)...
	};

	struct BinHeaderStruct {
		uint64 size;
		uint32 blockCount;
		uint32 blockSize;
		uint32 blocksInUse;
		uint64 usage;
		uint32 bitFieldSize; // number of bytes in the bitfield
		// Bitfield(bitFieldSize)
		// blockCount * blockSize data
	};

	//struct BinSpaceFit {
	//	uint32 bin;
	//	uint32 blocksNeeded;
	//	uint32 spaceWaisted;
	//};
	//bool BinSpaceFitSort(const BinSpaceFit& a, const BinSpaceFit& b) {
	//	return (a.blocksNeeded < b.blocksNeeded);
	//}

#define GETMSGNODE(id) (uint16)((id & 0xffff000000000000L)>>48)
#define GETMSGSERIAL(id) (uint16)((id & 0x0000ffff00000000L)>>32)
#define GETMSGSLOT(id) (uint32)(id & 0x00000000ffffffffL)
#define SETMSGID(id,node,serial,slot) id = (((uint64)node) << 48) | (((uint64)serial) << 32) | ((uint64)slot)

#define CHECKTEMPORALMEMORYSERIAL 	if (serial != master->getDynamicShmemSerial()) {if (!open()) {mutex->leave();return 0;}}

	class MasterMemory;
	class TemporalMemory {
	public:
		TemporalMemory(MemoryController* master);
		~TemporalMemory();

		bool getMemoryUsage(uint64& alloc, uint64& usage);

		bool open();
		bool create(uint32 slotCount, uint16 binCount, uint32 minBlockSize, uint32 maxBlockSize, uint64 initSize, uint64 maxSize, uint32 growSteps = 8);
		bool setNodeID(uint16 id);

		// Insert new block of memory and return full id
		bool insertMessage(DataMessage* msg, uint64& id);
		// Get copy of block of memory
		DataMessage* getCopyOfMessage(uint64 id);

		bool logUsage();

		bool maintenance();

		static bool UnitTest();

	private:

		std::vector<BinHeaderStruct> calcBinHeaders(uint32 binCount, uint32 minBlockSize, uint32 maxBlockSize, uint64 binDataSize);
		BinHeaderStruct* getBestBin(uint32 size, uint32& bin, uint32 &blocksNeeded);
		char* getMemoryBlock(uint64 id);
		bool checkSlots(uint64 now);

		bool resizeSlots();
		bool resizeBin(uint32 bin, BinHeaderStruct* binHeader, uint32 msgSize);
		std::vector<BinHeaderStruct> calcBinHeadersGrowth(uint32 bin = 0, uint32 msgSize = 0);
		bool resizeMemory(uint32 slotGrowth, std::vector<BinHeaderStruct>& binHeaderSizes);

		utils::Mutex* mutex;
		MemoryController* master;
		TemporalMemoryStruct* header;
		SlotEntryStruct* slotEntries;
		uint64 memorySize;
		uint16 port;
		uint16 node;
		uint32 serial;
	};


//	
//	
//struct TemporalMemoryStruct {
//	uint64 size;
//	uint32 cid;
//	uint64 usage;
//	uint64 growStep;
//	uint64 maxSize;
//	uint64 createdTime;		// time of creation
//	uint16 slotCount;
//	uint64 slotSize;
//	uint32 slotDuration;
//	uint16 startSlot;
//	uint64 startTime;
//	// slots * SlotHeaderStruct
//};
//
//struct SlotHeaderStruct {
//	uint64 size;
//	uint32 count;
//	uint64 usage;
//	uint64 eol;
//	uint64 offset;
//};
//
//#define GETMSGNODE(id) (uint16)((id & 0xffff000000000000L)>>48)
//#define GETMSGSLOT(id) (uint16)((id & 0x0000ffff00000000L)>>32)
//#define GETMSGOFFSET(id) (uint64)(id & 0x00000000ffffffffL)
//#define SETMSGID(id,node,slot,offset) id = (((uint64)node) << 48) | (((uint64)slot) << 32) | ((uint64)offset)
//
//#define CHECKTEMPORALMEMORYSERIAL 	if (serial != master->getDynamicShmemSerial()) {if (!open()) {mutex->leave();return 0;}}
//
//class MasterMemory;
//class TemporalMemory {
//public:
//	TemporalMemory(MemoryController* master);
//	~TemporalMemory();
//
//	bool getMemoryUsage(uint64& alloc, uint64& usage);
//
//	bool open();
//	bool create(uint16 slotCount, uint32 slotDuration, uint64 initSize, uint64 maxSize, uint32 growSteps = 8);
//	bool setNodeID(uint16 id);
//
//	// Insert new block of memory and return full id
//	bool insertMessage(DataMessage* msg, uint64& id);
//	// Get copy of block of memory
//	DataMessage* getCopyOfMessage(uint64 id);
//
//	bool logUsage();
//
//	bool maintenance();
//
//	static bool UnitTest();
//
//private:
//	bool getSlotFromEOL(uint64 eol, uint16& slot);
//	char* getMemoryBlock(uint64 id);
//	bool growSlotSize(uint64 growAmount);
//	bool checkSlots();
//	bool resetSlot(uint16 slot, uint64 eol);
//	uint64 calcResizeAmount(uint32 msgSize);
//
//	utils::Mutex* mutex;
//	MemoryController* master;
//	TemporalMemoryStruct* header;
//	SlotHeaderStruct* slotHeaders;
//	uint64 memorySize;
//	uint16 port;
//	uint16 node;
//	uint32 serial;
//};

} // namespace cmlabs

#endif //_TEMPORALMEMORY_H_

