/*=============================================================================#
 # Copyright (c) 2009, 2018 Stephan Wahlbrink and others.
 # 
 # This program and the accompanying materials are made available under the
 # terms of the Eclipse Public License 2.0 which is available at
 # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
 # which is available at https://www.apache.org/licenses/LICENSE-2.0.
 # 
 # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
 # 
 # Contributors:
 #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
 #=============================================================================*/

package org.eclipse.statet.rj.server;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.statet.rj.server.gr.RjsGraphicManager;


/**
 * Interface from R to Java side of the RJ server
 */
public class RJ {
	
	
	private static RJ instance;
	
	protected byte currentSlot;
	
	private final Object clientPropertiesLock= new Object();
	private Map<String, Object>[] clientPropertiesMaps= new Map[2];
	
	
	public final static RJ getInstance() {
		return instance;
	}
	
	
	protected RJ() {
		if (instance != null) {
			throw new IllegalStateException();
		}
		instance= this;
	}
	
	
	public void onRExit() {
		instance= null;
	}
	
	public byte getCurrentSlot() {
		return this.currentSlot;
	}
	
	public RjsGraphicManager getGraphicManager() {
		return null;
	}
	
	protected void setClientProperty(final byte slot, final String key, final Object value) {
		Map<String, Object> map;
		synchronized (this.clientPropertiesLock) {
			if (slot >= this.clientPropertiesMaps.length) {
				final Map<String, Object>[] newMaps= new Map[this.clientPropertiesMaps.length];
				System.arraycopy(this.clientPropertiesMaps, 0, newMaps, 0, slot+1);
				this.clientPropertiesMaps= newMaps;
			}
			map= this.clientPropertiesMaps[slot];
			if (map == null) {
				this.clientPropertiesMaps[slot]= new HashMap<>();
			}
		}
		map.put(key, value);
	}
	
	protected void setClientProperties(final byte slot, final Map<String, ? extends Object> properties) {
		Map<String, Object> map;
		synchronized (this.clientPropertiesLock) {
			if (slot >= this.clientPropertiesMaps.length) {
				final Map<String, Object>[] newMaps= new Map[this.clientPropertiesMaps.length];
				System.arraycopy(this.clientPropertiesMaps, 0, newMaps, 0, slot+1);
				this.clientPropertiesMaps= newMaps;
			}
			map= this.clientPropertiesMaps[slot];
			if (map == null) {
				this.clientPropertiesMaps[slot]= map= new HashMap<>();
			}
		}
		for (final Entry<String, ? extends Object> entry : properties.entrySet()) {
			if (entry.getValue() != null) {
				map.put(entry.getKey(), entry.getValue());
			}
			else {
				map.remove(entry.getKey());
			}
		}
	}
	
	public Object getClientProperty(final byte slot, final String key) {
		final Map<String, Object>[] clients= this.clientPropertiesMaps;
		if (slot >= clients.length) {
			return null;
		}
		final Map<String, Object> map= clients[slot];
		if (map == null) {
			return null;
		}
		synchronized (map) {
			return map.get(key);
		}
	}
	
	public MainCmdItem sendMainCmd(final MainCmdItem cmd) {
		throw new UnsupportedOperationException();
	}
	
}
