package com.cube.index;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Cubic Index Node - Revolutionary indexing based on cube numbers.
*
* Formula: Index = N³ × 6
* Each node has 6 sides (like a cube) for data storage.
*
* Index progression: 1³×6=6, 2³×6=48, 3³×6=162, 4³×6=384, 5³×6=750...
*/
public class CubicIndexNode {
private final int level; // N in N³×6
private final long indexValue; // N³×6
private final CubeSide[] sides; // 6 sides of the cube
private final ReadWriteLock lock;
// 6 sides of a cube: Front, Back, Left, Right, Top, Bottom
public enum Side {
FRONT(0), // Side 0
BACK(1), // Side 1
LEFT(2), // Side 2
RIGHT(3), // Side 3
TOP(4), // Side 4
BOTTOM(5); // Side 5
private final int index;
Side(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public static Side fromIndex(int index) {
for (Side side : values()) {
if (side.index == index) {
return side;
}
}
throw new IllegalArgumentException("Invalid side index: " + index);
}
}
/**
* One side of the cubic index node
*/
public static class CubeSide {
private final Side position;
private final Map<String, byte[]> data;
private final ReadWriteLock sideLock;
public CubeSide(Side position) {
this.position = position;
this.data = new HashMap<>();
this.sideLock = new ReentrantReadWriteLock();
}
public void put(String key, byte[] value) {
sideLock.writeLock().lock();
try {
data.put(key, value);
} finally {
sideLock.writeLock().unlock();
}
}
public byte[] get(String key) {
sideLock.readLock().lock();
try {
return data.get(key);
} finally {
sideLock.readLock().unlock();
}
}
public boolean containsKey(String key) {
sideLock.readLock().lock();
try {
return data.containsKey(key);
} finally {
sideLock.readLock().unlock();
}
}
public boolean remove(String key) {
sideLock.writeLock().lock();
try {
return data.remove(key) != null;
} finally {
sideLock.writeLock().unlock();
}
}
public int size() {
sideLock.readLock().lock();
try {
return data.size();
} finally {
sideLock.readLock().unlock();
}
}
public Set<String> keys() {
sideLock.readLock().lock();
try {
return new HashSet<>(data.keySet());
} finally {
sideLock.readLock().unlock();
}
}
public Side getPosition() {
return position;
}
}
/**
* Create a cubic index node at level N
*/
public CubicIndexNode(int level) {
if (level < 1) {
throw new IllegalArgumentException("Level must be >= 1");
}
this.level = level;
this.indexValue = calculateCubicIndex(level);
this.sides = new CubeSide[6];
this.lock = new ReentrantReadWriteLock();
// Initialize all 6 sides
for (Side side : Side.values()) {
sides[side.getIndex()] = new CubeSide(side);
}
}
/**
* Calculate cubic index: N³ × 6
*/
public static long calculateCubicIndex(int n) {
return (long) n * n * n * 6;
}
/**
* Calculate which level a given value belongs to
*/
public static int calculateLevel(long value) {
// Solve for N in: N³ × 6 = value
// N³ = value / 6
// N = ∛(value / 6)
double cubeRoot = Math.cbrt(value / 6.0);
return (int) Math.ceil(cubeRoot);
}
/**
* Determine which side to use based on key hash
*/
public static Side determineSide(String key) {
int hash = Math.abs(key.hashCode());
return Side.fromIndex(hash % 6);
}
/**
* Put data into the appropriate side
*/
public void put(String key, byte[] value) {
Side side = determineSide(key);
sides[side.getIndex()].put(key, value);
}
/**
* Get data from the appropriate side
*/
public byte[] get(String key) {
Side side = determineSide(key);
return sides[side.getIndex()].get(key);
}
/**
* Check if key exists on any side
*/
public boolean containsKey(String key) {
Side side = determineSide(key);
return sides[side.getIndex()].containsKey(key);
}
/**
* Remove data from the appropriate side
*/
public boolean remove(String key) {
Side side = determineSide(key);
return sides[side.getIndex()].remove(key);
}
/**
* Get a specific side
*/
public CubeSide getSide(Side side) {
return sides[side.getIndex()];
}
/**
* Get total size across all sides
*/
public int getTotalSize() {
int total = 0;
for (CubeSide side : sides) {
total += side.size();
}
return total;
}
/**
* Get all keys across all sides
*/
public Set<String> getAllKeys() {
Set<String> allKeys = new HashSet<>();
for (CubeSide side : sides) {
allKeys.addAll(side.keys());
}
return allKeys;
}
/**
* Get statistics for this node
*/
public Map<String, Object> getStats() {
Map<String, Object> stats = new LinkedHashMap<>();
stats.put("level", level);
stats.put("indexValue", indexValue);
stats.put("totalKeys", getTotalSize());
Map<String, Integer> sideStats = new LinkedHashMap<>();
for (Side side : Side.values()) {
sideStats.put(side.name(), sides[side.getIndex()].size());
}
stats.put("sideDistribution", sideStats);
return stats;
}
public int getLevel() {
return level;
}
public long getIndexValue() {
return indexValue;
}
@Override
public String toString() {
return String.format("CubicNode[L=%d, Index=%d (=%d³×6), Keys=%d]",
level, indexValue, level, getTotalSize());
}
}