// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.resource.are.viewer;
import java.util.ArrayList;
import java.util.List;
import org.infinity.datatype.SectionCount;
import org.infinity.datatype.SectionOffset;
import org.infinity.gui.layeritem.AbstractLayerItem;
import org.infinity.resource.StructEntry;
import org.infinity.resource.are.Ambient;
import org.infinity.resource.are.AreResource;
/**
* Manages ambient sound layer objects (including global and local ambient sounds).
*/
public class LayerAmbient extends BasicLayer<LayerObjectAmbient>
{
private static final String[] AvailableFmt = {"Global ambient sounds: %1$d",
"Local ambient sound: %1$d",
"Ambient sounds: %1$d"};
// stores ambient sound objects with local radius
private final List<LayerObjectAmbient> listGlobalSounds = new ArrayList<LayerObjectAmbient>();
private final List<LayerObjectAmbient> listLocalSounds = new ArrayList<LayerObjectAmbient>();
private boolean iconEnabled, rangeEnabled;
public LayerAmbient(AreResource are, AreaViewer viewer)
{
super(are, ViewerConstants.LayerType.AMBIENT, viewer);
iconEnabled = true;
rangeEnabled = false;
loadLayer(false);
}
@Override
public int loadLayer(boolean forced)
{
if (forced || !isInitialized()) {
listGlobalSounds.clear();
listLocalSounds.clear();
close();
List<LayerObjectAmbient> list = getLayerObjects();
if (hasAre()) {
AreResource are = getAre();
SectionOffset so = (SectionOffset)are.getAttribute(AreResource.ARE_OFFSET_AMBIENTS);
SectionCount sc = (SectionCount)are.getAttribute(AreResource.ARE_NUM_AMBIENTS);
if (so != null && sc != null) {
int ofs = so.getValue();
int count = sc.getValue();
List<StructEntry> listStruct = getStructures(ofs, count, Ambient.class);
for (int i = 0, size = listStruct.size(); i < size; i++) {
LayerObjectAmbient obj = new LayerObjectAmbient(are, (Ambient)listStruct.get(i));
setListeners(obj);
list.add(obj);
// putting global/local sounds into separate lists for faster access
if (obj.isLocal()) {
listLocalSounds.add(obj);
} else {
listGlobalSounds.add(obj);
}
}
setInitialized(true);
}
}
return list.size();
}
return 0;
}
/**
* Sets the visibility state of all items in the layer. Takes enabled states of the different
* item types into account.
*/
public void setLayerVisible(boolean visible)
{
setVisibilityState(visible);
List<LayerObjectAmbient> list = getLayerObjects();
boolean state;
if (list != null) {
for (int i = 0, size = list.size(); i < size; i++) {
LayerObjectAmbient obj = list.get(i);
state = isLayerVisible(ViewerConstants.AMBIENT_ITEM_ICON) && (!isScheduleEnabled() || (isScheduleEnabled() && isScheduled(i)));
AbstractLayerItem item = obj.getLayerItem(ViewerConstants.AMBIENT_ITEM_ICON);
if (item != null) {
item.setVisible(state && iconEnabled);
}
state = isLayerVisible(ViewerConstants.AMBIENT_ITEM_RANGE) && (!isScheduleEnabled() || (isScheduleEnabled() && isScheduled(i)));
item = obj.getLayerItem(ViewerConstants.AMBIENT_ITEM_RANGE);
if (item != null) {
item.setVisible(state && rangeEnabled);
}
}
}
}
/**
* Returns whether the specific layer item type is visible.
* @param itemType One of {@code ViewerConstants.AMBIENT_ITEM_ICON} and {@code ViewerConstants.AMBIENT_ITEM_RANGE}.
* @return Whether items of the specified state are visible.
*/
public boolean isLayerVisible(int itemType)
{
if (itemType == ViewerConstants.AMBIENT_ITEM_ICON) {
return isLayerVisible() && iconEnabled;
} else if (itemType == ViewerConstants.AMBIENT_ITEM_RANGE) {
return isLayerVisible() && rangeEnabled;
} else {
return false;
}
}
/**
* Returns whether the items of specified type have been enabled (i.e. will be shown when visibility state
* is set to {@code true}).
* @param itemType One of {@code ViewerConstants.AMBIENT_ITEM_ICON} and {@code ViewerConstants.AMBIENT_ITEM_RANGE}.
* @return The activation state of the item type.
*/
public boolean isItemTypeEnabled(int itemType)
{
if (itemType == ViewerConstants.AMBIENT_ITEM_ICON) {
return iconEnabled;
} else if (itemType == ViewerConstants.AMBIENT_ITEM_RANGE) {
return rangeEnabled;
} else {
return false;
}
}
/**
* Sets the enabled state of the specified item type.
* @param itemType One of {@code ViewerConstants.AMBIENT_ITEM_ICON} and {@code ViewerConstants.AMBIENT_ITEM_RANGE}.
* @param enable Whether the item type will be considered when setting the visibility state of the layer items.
*/
public void setItemTypeEnabled(int itemType, boolean enable)
{
boolean hasChanged = false;
if (itemType == ViewerConstants.AMBIENT_ITEM_ICON) {
if (enable != iconEnabled) {
iconEnabled = enable;
hasChanged = true;
}
} else if (itemType == ViewerConstants.AMBIENT_ITEM_RANGE) {
if (enable != rangeEnabled) {
rangeEnabled = enable;
hasChanged = true;
}
}
if (hasChanged) {
setLayerVisible(isLayerVisible());
}
}
/**
* Returns the number of layer objects of the specified type.
* @param ambientType The ambient sound type (either ViewerConstants.AMBIENT_TYPE_GLOBAL,
* ViewerConstants.AMBIENT_TYPE_LOCAL or ViewerConstants.AMBIENT_TYPE_ALL).
* @return Number of layer objects.
*/
public int getLayerObjectCount(int ambientType)
{
int count = 0;
if ((ambientType & ViewerConstants.AMBIENT_TYPE_ALL) == ViewerConstants.AMBIENT_TYPE_LOCAL) {
count += listLocalSounds.size();
}
if ((ambientType & ViewerConstants.AMBIENT_TYPE_ALL) == ViewerConstants.AMBIENT_TYPE_GLOBAL) {
count += listGlobalSounds.size();
}
return count;
}
/**
* Returns the layer object at the specified index of the desired sound type.
* @param ambientType The ambient sound type (either ViewerConstants.AMBIENT_TYPE_GLOBAL,
* ViewerConstants.AMBIENT_TYPE_LOCAL or ViewerConstants.AMBIENT_TYPE_ALL).
* @param index The index of the layer object.
* @return The layer object, of {@code null} if not available.
*/
public LayerObjectAmbient getLayerObject(int ambientType, int index)
{
index = Math.min(Math.max(index, 0), getLayerObjectCount(ambientType));
if ((ambientType & ViewerConstants.AMBIENT_TYPE_ALL) == ViewerConstants.AMBIENT_TYPE_LOCAL) {
return listLocalSounds.get(index);
} else if ((ambientType & ViewerConstants.AMBIENT_TYPE_ALL) == ViewerConstants.AMBIENT_TYPE_GLOBAL) {
return listGlobalSounds.get(index);
} else if ((ambientType & ViewerConstants.AMBIENT_TYPE_ALL) == ViewerConstants.AMBIENT_TYPE_ALL) {
return getLayerObject(index);
} else {
return null;
}
}
/**
* Returns the list of layer objects of the specified type for direct manipulation.
* @param ambientType The ambient sound type (either ViewerConstants.AMBIENT_TYPE_GLOBAL,
* ViewerConstants.AMBIENT_TYPE_LOCAL or ViewerConstants.AMBIENT_TYPE_ALL).
* @return List of layer objects.
*/
public List<LayerObjectAmbient> getLayerObjects(int ambientType)
{
if ((ambientType & ViewerConstants.AMBIENT_TYPE_ALL) == ViewerConstants.AMBIENT_TYPE_LOCAL) {
return listLocalSounds;
} else if ((ambientType & ViewerConstants.AMBIENT_TYPE_ALL) == ViewerConstants.AMBIENT_TYPE_GLOBAL) {
return listGlobalSounds;
} else if ((ambientType & ViewerConstants.AMBIENT_TYPE_ALL) == ViewerConstants.AMBIENT_TYPE_ALL) {
return getLayerObjects();
} else {
return new ArrayList<LayerObjectAmbient>();
}
}
@Override
public String getAvailability()
{
int cnt = getLayerObjectCount();
return getAvailabilityString(ViewerConstants.AMBIENT_TYPE_ALL, cnt);
}
/**
* Returns the number of objects in this layer for the specified type as a formatted string.
* @param ambientType The ambient sound type (either ViewerConstants.AMBIENT_TYPE_GLOBAL,
* ViewerConstants.AMBIENT_TYPE_LOCAL or ViewerConstants.AMBIENT_TYPE_ALL).
* @return A formatted string telling about the number of objects in this layer.
*/
public String getAvailability(int ambientType)
{
ambientType &= ViewerConstants.AMBIENT_TYPE_ALL;
int cnt = 0;
if ((ambientType & ViewerConstants.AMBIENT_TYPE_LOCAL) != 0) {
cnt += getLayerObjectCount(ViewerConstants.AMBIENT_TYPE_LOCAL);
}
if ((ambientType & ViewerConstants.AMBIENT_TYPE_GLOBAL) != 0) {
cnt += getLayerObjectCount(ViewerConstants.AMBIENT_TYPE_GLOBAL);
}
return getAvailabilityString(ambientType, cnt);
}
// Returns the availability string based on ambient sound type and count
private String getAvailabilityString(int ambientType, int count)
{
ambientType &= ViewerConstants.AMBIENT_TYPE_ALL;
int idx = 0;
switch (ambientType) {
case ViewerConstants.AMBIENT_TYPE_ALL:
idx++;
case ViewerConstants.AMBIENT_TYPE_LOCAL:
idx++;
case ViewerConstants.AMBIENT_TYPE_GLOBAL:
return String.format(AvailableFmt[idx], count);
default:
return "";
}
}
}