/* * Copyright 2011 Tyler Blair. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''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 AUTHOR 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. * * The views and conclusions contained in the software and documentation are those of the * authors and contributors and should not be interpreted as representing official policies, * either expressed or implied, of anybody else. */ package com.griefcraft.model; import com.griefcraft.lwc.LWC; import com.griefcraft.util.StringUtil; import java.util.Arrays; import java.util.List; public class History { /** * The history type defines what this History object is for, such as TRANSACTION. * <p/> * Ordering <b>must</b> remain constant as internally, the ordinal is used and * if ordering is changed, LWC will experience undefined behaviour. */ public enum Type { /** * Designates that this history object is for a transaction - e.g when a protection is removed */ TRANSACTION } /** * The status of this History object; most often ACTIVE or INACTIVE. * <p/> * As with {@link Type}, the ordering <b>must</b> remain constant and not change. */ public enum Status { /** * This type is still active */ ACTIVE, /** * For some reason the type is now inactive. Most likely the * protection was removed by the player */ INACTIVE } /** * History id in the database */ private int id; /** * Affected protection id */ private int protectionId; /** * The protection known for this history object */ private Protection protection; /** * The player that caused the history action to be created */ private String player; /** * The x coordinate of the history item */ private int x; /** * The y coordinate of the history item */ private int y; /** * The z coordinate of the history item */ private int z; /** * The history type, e.g TRANSACTION */ private Type type = Type.TRANSACTION; /** * The status (ACTIVE or INACTIVE normally) */ private Status status = Status.INACTIVE; /** * Metadata about the transaction. An example of one entry would be * for iConomy prices to be pushed in here. Any module can modify the * meta data and add their own data about the transaction. */ private String[] metadata; /** * The seconds (since linux epoch) this History object was created */ private long timestamp; /** * If the history val exists in the database */ private boolean exists = false; /** * If the history object was modified */ private boolean modified = false; /** * If the History object is waiting to be flushed to the database */ private boolean saving = false; public History() { // set some defaults to account for stupidness status = Status.INACTIVE; metadata = new String[0]; } /** * @return true if the history object should be synced to the database */ public boolean wasModified() { return modified; } /** * @return the Protection this history value is associated with */ public Protection getProtection() { // attempt to load the protection if it hasn't been loaded yet if (protection == null) { this.protection = LWC.getInstance().getPhysicalDatabase().loadProtection(protectionId); } return protection; } /** * Add a string of data to the stored metadata * * @param data */ public void addMetaData(String data) { String[] temp = new String[metadata.length + 1]; System.arraycopy(metadata, 0, temp, 0, metadata.length); // push the data to the end of the temporary array // array.length doesn't start at 0, so we can be sure this is valid temp[metadata.length] = data; // we're okey this.metadata = temp; this.modified = true; } /** * Check if the metadata contains a given key * * @param key * @return */ public boolean hasKey(String key) { return getMetaDataStartsWith(key + "=") != null; } /** * Get a boolean value from the metadata using the key (key=value) * * @param key * @return */ public boolean getBoolean(String key) { String metadata = getMetaDataStartsWith(key + "="); return metadata != null && Boolean.parseBoolean(metadata.substring((key + "=").length())); } /** * Get a String value from the metadata using the key (key=value) * * @param key * @return */ public String getString(String key) { String metadata = getMetaDataStartsWith(key + "="); if (metadata == null) { return ""; } return metadata.substring((key + "=").length()); } /** * Get an integer value from the metadata using the key (key=value) * * @param key * @return */ public int getInteger(String key) { String metadata = getMetaDataStartsWith(key + "="); if (metadata == null) { return 0; } return Integer.parseInt(metadata.substring((key + "=").length())); } /** * Get a double value from the metadata using the key (key=value) * * @param key * @return */ public double getDouble(String key) { String metadata = getMetaDataStartsWith(key + "="); if (metadata == null) { return 0; } return Double.parseDouble(metadata.substring((key + "=").length())); } /** * Get a metadata that starts with a specific string * * @param startsWith * @return the full metadata if a match is found, otherwise NULL */ public String getMetaDataStartsWith(String startsWith) { for (String temp : metadata) { if (temp.startsWith(startsWith)) { return temp; } } return null; } /** * Remove a string of known data from the stored metadata * * @param data * @return true if the given metadata was successfully removed */ public boolean removeMetaData(String data) { // sorry List<String> temp = Arrays.asList(metadata); int expected = metadata.length - 1; temp.remove(data); // that went better than expected this.metadata = temp.toArray(new String[temp.size()]); this.modified = true; return metadata.length == expected; } /** * Set the cached protection this History object belongs to save a query or two later on * * @param protection */ public void setProtection(Protection protection) { if (protection == null) { return; } this.protection = protection; this.protectionId = protection.getId(); } /** * @return true if this History object exists in the database */ public boolean doesExist() { return exists; } /** * Set if the History object exists in the database * * @param exists */ public void setExists(boolean exists) { this.exists = exists; this.modified = true; } /** * @return a STRING representation of the metadata for use in the database */ public String getSafeMetaData() { return StringUtil.join(metadata, 0, ","); } /** * Sync this history object to the database when possible */ public void save() { // if it was not modified, no point in saving it :-) if (!modified || saving) { return; } LWC lwc = LWC.getInstance(); // find the protection the history object is attached to Protection protection = getProtection(); // no protection? weird, just sync anyway if (protection == null) { saveNow(); return; } // wait! this.saving = true; // ensure the protection knows about us protection.checkHistory(this); // save it when possible protection.save(); } /** * Force the history object to be saved immediately */ public void saveNow() { LWC.getInstance().getPhysicalDatabase().saveHistory(this); this.modified = false; this.saving = false; } /** * Alias for {@see save} */ public void sync() { save(); } /** * Remove this history object from the database * TODO: broadcast an event */ public void remove() { LWC.getInstance().getPhysicalDatabase().removeHistory(id); this.modified = false; } public int getId() { return id; } public int getProtectionId() { return protectionId; } public String getPlayer() { return player; } public int getX() { return x; } public int getY() { return y; } public int getZ() { return z; } public Type getType() { return type; } public Status getStatus() { return status; } public String[] getMetaData() { return metadata; } public long getTimestamp() { return timestamp; } public void setId(int id) { this.id = id; this.exists = true; this.modified = true; } public void setProtectionId(int protectionId) { this.protectionId = protectionId; this.modified = true; } public void setPlayer(String player) { this.player = player; this.modified = true; } public void setX(int x) { this.x = x; this.modified = true; } public void setY(int y) { this.y = y; this.modified = true; } public void setZ(int z) { this.z = z; this.modified = true; } public void setType(Type type) { this.type = type; this.modified = true; } public void setStatus(Status status) { this.status = status; this.modified = true; } public void setMetaData(String[] metadata) { this.metadata = metadata; this.modified = true; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; this.modified = true; } }