/*
* Copyright 2013 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.world.block;
import com.google.common.base.Objects;
import org.terasology.assets.ResourceUrn;
import org.terasology.assets.exceptions.InvalidUrnException;
import org.terasology.engine.Uri;
import org.terasology.naming.Name;
import java.util.Optional;
/**
* Identifier for both blocks and block families. It is a combination of the ResourceUrn of a block family definition, the id of a block, and optionally the
* ResourceUrn of a shape.
* The final pattern is
* [package]:[blockFamily]:[shapePackage]:[shapeName].[blockIdentifier]
* the third and forth parts are only used for blocks that don't use the engine:cube shape, and which
* are generated from a multi-shape block.
* The blockIdentifier is only used for blocks withing a block family that contains multiple blocks
* e.g.
* engine:brickstair.left for left-aligned stairs
* engine:stone:engine:stair for the family of stone stairs generated from a multishape block definition
*
*/
public class BlockUri implements Uri, Comparable<BlockUri> {
public static final String IDENTIFIER_SEPARATOR = ".";
public static final String IDENTIFIER_SEPARATOR_REGEX = "\\.";
private final ResourceUrn blockFamilyDefinition;
private final Optional<ResourceUrn> shape;
private final Name blockName;
public BlockUri(String uri) throws BlockUriParseException {
try {
String[] split = uri.split(MODULE_SEPARATOR, 4);
if (split.length <= 1) {
throw new BlockUriParseException("Could not parse block uri: '" + uri + "'");
}
Name blockFamilyDefModule = new Name(split[0]);
if (split.length == 4) {
blockFamilyDefinition = new ResourceUrn(blockFamilyDefModule, new Name(split[1]));
Name shapeModuleName = new Name(split[2]);
split = split[3].split(IDENTIFIER_SEPARATOR_REGEX, 2);
shape = Optional.of(new ResourceUrn(shapeModuleName, new Name(split[0])));
if (split.length > 1) {
blockName = new Name(split[1]);
} else {
blockName = Name.EMPTY;
}
} else {
shape = Optional.empty();
split = split[1].split(IDENTIFIER_SEPARATOR_REGEX, 2);
blockFamilyDefinition = new ResourceUrn(blockFamilyDefModule, new Name(split[0]));
if (split.length > 1) {
blockName = new Name(split[1]);
} else {
blockName = Name.EMPTY;
}
}
} catch (InvalidUrnException e) {
throw new BlockUriParseException("Could not parse block uri: '" + uri + "'", e);
}
}
public BlockUri(ResourceUrn blockFamilyDefinition) {
this(blockFamilyDefinition, Optional.empty(), Name.EMPTY);
}
public BlockUri(ResourceUrn blockFamilyDefinition, ResourceUrn shape) {
this(blockFamilyDefinition, Optional.of(shape), Name.EMPTY);
}
public BlockUri(ResourceUrn blockFamilyDefinition, Name blockName) {
this(blockFamilyDefinition, Optional.empty(), blockName);
}
public BlockUri(ResourceUrn blockFamilyDefinition, ResourceUrn shape, Name blockName) {
this(blockFamilyDefinition, Optional.of(shape), blockName);
}
public BlockUri(BlockUri parentUri, Name blockName) {
this(parentUri.getBlockFamilyDefinitionUrn(), parentUri.getShapeUrn(), blockName);
}
private BlockUri(ResourceUrn blockFamilyDefinition, Optional<ResourceUrn> shape, Name blockName) {
this.blockFamilyDefinition = blockFamilyDefinition;
this.shape = shape;
this.blockName = blockName;
}
@Override
public Name getModuleName() {
return blockFamilyDefinition.getModuleName();
}
@Override
public boolean isValid() {
return true;
}
public ResourceUrn getBlockFamilyDefinitionUrn() {
return blockFamilyDefinition;
}
public Optional<ResourceUrn> getShapeUrn() {
return shape;
}
public Name getIdentifier() {
return blockName;
}
/**
* @return The uri of the block's family, including shape
*/
public BlockUri getFamilyUri() {
if (!blockName.isEmpty()) {
return new BlockUri(blockFamilyDefinition, shape, Name.EMPTY);
} else {
return this;
}
}
/**
* @return The uri of the block's family, excluding shape
*/
public BlockUri getRootFamilyUri() {
if (!blockName.isEmpty() || shape.isPresent()) {
return new BlockUri(blockFamilyDefinition);
} else {
return this;
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(blockFamilyDefinition.toString());
if (shape.isPresent()) {
builder.append(MODULE_SEPARATOR);
builder.append(shape.get().toString());
}
if (!blockName.isEmpty()) {
builder.append(IDENTIFIER_SEPARATOR);
builder.append(blockName.toString());
}
return builder.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof BlockUri) {
BlockUri other = (BlockUri) obj;
return Objects.equal(other.blockFamilyDefinition, blockFamilyDefinition)
&& Objects.equal(other.blockName, blockName)
&& Objects.equal(other.shape, shape);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(blockFamilyDefinition, shape, blockName);
}
@Override
public int compareTo(BlockUri o) {
int result = blockFamilyDefinition.compareTo(o.blockFamilyDefinition);
if (result == 0) {
if (shape.isPresent()) {
if (o.shape.isPresent()) {
result = shape.get().compareTo(o.shape.get());
} else {
return 1;
}
} else {
if (o.shape.isPresent()) {
return -1;
}
}
}
if (result == 0) {
if (!blockName.isEmpty()) {
if (!o.blockName.isEmpty()) {
result = blockName.compareTo(o.blockName);
} else {
return 1;
}
} else {
if (!o.blockName.isEmpty()) {
return -1;
}
}
}
return result;
}
public BlockUri getShapelessUri() {
if (!getIdentifier().isEmpty()) {
return new BlockUri(blockFamilyDefinition, getIdentifier());
} else {
return new BlockUri(blockFamilyDefinition);
}
}
}