Package net.aufdemrand.denizen.objects

Source Code of net.aufdemrand.denizen.objects.dList

package net.aufdemrand.denizen.objects;

import net.aufdemrand.denizen.BukkitScriptEntryData;
import net.aufdemrand.denizen.flags.FlagManager;
import net.aufdemrand.denizen.objects.properties.Property;
import net.aufdemrand.denizen.objects.properties.PropertyParser;
import net.aufdemrand.denizen.scripts.ScriptBuilder;
import net.aufdemrand.denizen.scripts.ScriptEntry;
import net.aufdemrand.denizen.scripts.ScriptRegistry;
import net.aufdemrand.denizen.scripts.commands.core.DetermineCommand;
import net.aufdemrand.denizen.scripts.containers.core.ProcedureScriptContainer;
import net.aufdemrand.denizen.scripts.queues.ScriptQueue;
import net.aufdemrand.denizen.scripts.queues.core.InstantQueue;
import net.aufdemrand.denizen.tags.Attribute;
import net.aufdemrand.denizen.tags.core.EscapeTags;
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.utilities.NaturalOrderComparator;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizen.utilities.depends.Depends;
import net.aufdemrand.denizencore.utilities.CoreUtilities;
import org.bukkit.ChatColor;

import java.util.*;
import java.util.regex.Pattern;

public class dList extends ArrayList<String> implements dObject {

    public final static char internal_escape_char = (char)0x05;
    public final static String internal_escape = String.valueOf(internal_escape_char);

    @Fetchable("li, fl")
    public static dList valueOf(String string) {
        if (string == null) return null;

        ///////
        // Match @object format

        if (string.startsWith("fl")) {
            FlagManager flag_manager = DenizenAPI.getCurrentInstance().flagManager();
            if (string.indexOf('[') == 2) {
                int cb = string.indexOf(']');
                if (cb > 4 && string.indexOf('@') == (cb + 1)) {
                    String owner = string.substring(3, cb);
                    String flag = string.substring(cb + 2);
                    if (dPlayer.matches(owner)) {
                        dPlayer player = dPlayer.valueOf(owner);
                        if (FlagManager.playerHasFlag(player, flag))
                            return new dList(flag_manager.getPlayerFlag(player, flag));
                        else
                            dB.echoError("Player '" + owner + "' flag '" + flag + "' not found.");
                    }
                    else if (Depends.citizens != null && dNPC.matches(owner)) {
                        dNPC npc = dNPC.valueOf(owner);
                        if (FlagManager.npcHasFlag(npc, flag))
                            return new dList(flag_manager.getNPCFlag(npc.getId(), flag));
                        else
                            dB.echoError("NPC '" + owner + "' flag '" + flag + "' not found.");
                    }
                }
                else
                    dB.echoError("Invalid dFlag format: " + string);
            }
            else if (string.indexOf('@') == 2) {
                String flag = string.substring(3);
                if (FlagManager.serverHasFlag(flag))
                    return new dList(flag_manager.getGlobalFlag(flag));
                else
                    dB.echoError("Global flag '" + flag + "' not found.");
            }
            return null;
        }

        // Use value of string, which will separate values by the use of a pipe '|'
        return new dList(string.startsWith("li@") ? string.substring(3) : string);
    }


    public static boolean matches(String arg) {

        boolean flag = false;

        if (arg.startsWith("fl")) {
            if (arg.indexOf('[') == 2) {
                int cb = arg.indexOf(']');
                if (cb > 4 && arg.indexOf('@') == (cb + 1)) {
                    String owner = arg.substring(3, cb);
                    flag = arg.substring(cb + 2).length() > 0 && (dPlayer.matches(owner)
                            || (Depends.citizens != null && dNPC.matches(owner)));
                }
            }
            else if (arg.indexOf('@') == 2) {
                flag = arg.substring(3).length() > 0;
            }
        }

        return flag || arg.contains("|") || arg.contains(internal_escape) || arg.startsWith("li@");
    }


    /////////////
    //   Constructors
    //////////

    // A list of dObjects
    public dList(Collection<? extends dObject> dObjectList) {
        for (dObject obj : dObjectList)
            add(obj.identify());
    }

    // Empty dList
    public dList() { }

    // A string of items, split by '|'
    public dList(String items) {
        if (items != null && items.length() > 0) {
            // Count brackets
            int brackets = 0;
            // Record start position
            int start = 0;
            // Loop through characters
            for (int i = 0; i < items.length(); i++) {
                char chr = items.charAt(i);
                // Count brackets
                if (chr == '[') {
                    brackets++;
                }
                else if (chr == ']') {
                    if (brackets > 0) brackets--;
                }
                // Separate if an un-bracketed pipe is found
                else if ((brackets == 0) && (chr == '|' || chr == internal_escape_char)) {
                    add(items.substring(start, i));
                    start = i + 1;
                }
            }
            // If there is an item waiting, add it too
            if (start < items.length()) {
                add(items.substring(start, items.length()));
            }
        }
    }

    // A List<String> of items
    public dList(List<String> items) {
        if (items != null) addAll(items);
    }

    // A Set<String> of items
    public dList(Set<String> items) {
        if (items != null) addAll(items);
    }

    // A List<String> of items, with a prefix
    public dList(List<String> items, String prefix) {
        for (String element : items) {
            add(prefix + element);
        }
    }

    // A Flag
    public dList(FlagManager.Flag flag) {
        this.flag = flag;
        addAll(flag.values());
    }


    /////////////
    //   Instance Fields/Methods
    //////////

    private FlagManager.Flag flag = null;


    /**
     * Adds a list of dObjects to a dList by forcing each to 'identify()'.
     *
     * @param dObjects the List of dObjects
     * @return a dList
     */
    public dList addObjects(List<dObject> dObjects) {
        for (dObject obj : dObjects) {
            add(obj.identify());
        }

        return this;
    }

    /**
     * Fetches a String Array copy of the dList,
     * with the same size as the dList.
     *
     * @return the array copy
     */
    public String[] toArray() {
        return toArray(size());
    }

    /**
     * Fetches a String Array copy of the dList.
     *
     * @param arraySize the size of the new array
     * @return the array copy
     */
    public String[] toArray(int arraySize) {
        List<String> list = new ArrayList<String>();

        for (String string : this) {
            list.add(string);
        }

        return list.toArray(new String[arraySize]);
    }


    // Returns if the list contains objects from the specified dClass
    // by using the matches() method.
    public boolean containsObjectsFrom(Class<? extends dObject> dClass) {

        // Iterate through elements until one matches() the dClass
        for (String element : this)
            if (ObjectFetcher.checkMatch(dClass, element))
                return true;

        return false;
    }


    /**
     *  Return a new list that includes only strings that match the values of an Enum array
     *
     * @param values  the Enum's value
     * @return  a filtered list
     */
    public List<String> filter(Enum[] values) {
        List<String> list = new ArrayList<String>();

        for (String string : this) {
            for (Enum value : values)
                if (value.name().equalsIgnoreCase(string))
                    list.add(string);
        }

        if (!list.isEmpty())
            return list;
        else return null;
    }


    // Return a list that includes only elements belonging to a certain class
    public <T extends dObject> List<T> filter(Class<T> dClass) {
        return filter(dClass, null);
    }


    public <T extends dObject> List<T> filter(Class<T> dClass, ScriptEntry entry) {
        List<T> results = new ArrayList<T>();

        for (String element : this) {

            try {
                if (ObjectFetcher.checkMatch(dClass, element)) {

                    T object = ObjectFetcher.getObjectFrom(dClass, element,
                            (entry != null ? ((BukkitScriptEntryData)entry.entryData).getPlayer(): null),
                            (entry != null ? ((BukkitScriptEntryData)entry.entryData).getNPC(): null));

                    // Only add the object if it is not null, thus filtering useless
                    // list items

                    if (object != null) {
                        results.add(object);
                    }
                }
            } catch (Exception e) {
                dB.echoError(e);
            }
        }

        return results;
    }


    @Override
    public String toString() {
        return identify();
    }


    //////////////////////////////
    //    DSCRIPT ARGUMENT METHODS
    /////////////////////////


    private String prefix = "List";

    @Override
    public String getPrefix() {
        return prefix;
    }

    @Override
    public dList setPrefix(String prefix) {
        this.prefix = prefix;
        return this;
    }

    @Override
    public String debug() {
        return "<G>" + prefix + "='<Y>" + identify() + "<G>'  ";
    }

    @Override
    public boolean isUnique() {
        return flag != null;
    }

    @Override
    public String getObjectType() {
        return "List";
    }

    @Override
    public String identify() {
        if (flag != null)
            return flag.toString();

        if (isEmpty()) return "li@";

        StringBuilder dScriptArg = new StringBuilder();
        dScriptArg.append("li@");
        for (String item : this) {
            dScriptArg.append(item);
            // Items are separated by the | character in dLists
            dScriptArg.append('|');
        }

        return dScriptArg.toString().substring(0, dScriptArg.length() - 1);
    }


    @Override
    public String identifySimple() {
        return identify();
    }


    @Override
    public String getAttribute(Attribute attribute) {

        if (attribute == null) return null;

        // <--[tag]
        // @attribute <li@list.get_sub_items[<#>]>
        // @returns dList
        // @description
        // returns a list of the specified sub items in the list, as split by the
        // forward-slash character (/).
        // EG, .get_sub_items[1] on a list of "one/alpha|two/beta" will return "one|two".
        // -->

        if (attribute.startsWith("get_sub_items")) {
            int index = -1;
            if (aH.matchesInteger(attribute.getContext(1)))
                index = attribute.getIntContext(1) - 1;
            attribute.fulfill(1);


            // <--[tag]
            // @attribute <li@list.get_sub_items[<#>].split_by[<element>]>
            // @returns dList
            // @description
            // returns a list of the specified sub item in the list, allowing you to specify a
            // character in which to split the sub items by. WARNING: When setting your own split
            // character, make note that it is CASE SENSITIVE.
            // EG, .get_sub_items[1].split_by[-] on a list of "one-alpha|two-beta" will return "one|two".
            // -->

            String split = "/";
            if (attribute.startsWith("split_by")) {
                if (attribute.hasContext(1) && attribute.getContext(1).length() > 0)
                    split = attribute.getContext(1);
                attribute.fulfill(1);
            }

            if (index < 0)
                return null;

            dList sub_list = new dList();

            for (String item : this) {
                String[] strings = item.split(Pattern.quote(split));
                if (strings.length > index)
                    sub_list.add(strings[index]);
                else sub_list.add("null");
            }

            return sub_list.getAttribute(attribute);
        }

        // <--[tag]
        // @attribute <li@list.map_get[<element>]>
        // @returns dList
        // @description
        // Returns the sub-list split by the / symbol's
        // value for the matching input element.
        // TODO: Clarify
        // EG: li@one/a|two/b.map_get[one] returns a.
        // -->

        if (attribute.startsWith("map_get")
                && attribute.hasContext(1)) {
            String input = attribute.getContext(1);
            attribute.fulfill(1);


            // <--[tag]
            // @attribute <li@list.map_get[<element>].split_by[<element>]>
            // @returns dList
            // @description
            // Returns the sub-list split by the given symbol's
            // value for the matching input element.
            // TODO: Clarify
            // EG: li@one/a|two/b.map_get[one] returns a.
            // -->

            String split = "/";
            if (attribute.startsWith("split_by")) {
                if (attribute.hasContext(1) && attribute.getContext(1).length() > 0)
                    split = attribute.getContext(1);
                attribute.fulfill(1);
            }

            for (String item : this) {
                String[] strings = item.split(Pattern.quote(split), 2);
                if (strings.length > 1 && strings[0].equalsIgnoreCase(input)) {
                    return new Element(strings[1]).getAttribute(attribute);
                }
            }
        }

        // <--[tag]
        // @attribute <li@list.comma_separated>
        // @returns Element
        // @description
        // returns the list in a cleaner format, separated by commas.
        // EG, a list of "one|two|three" will return "one, two, three".
        // -->
        if (attribute.startsWith("comma_separated")
                || attribute.startsWith("ascslist")
                || attribute.startsWith("as_cslist")) {
            if (isEmpty()) return new Element("").getAttribute(attribute.fulfill(1));
            StringBuilder dScriptArg = new StringBuilder();
            for (String item : this) {
                dScriptArg.append(item);
                // Insert a comma and space after each item
                dScriptArg.append(", ");
            }
            return new Element(dScriptArg.toString().substring(0, dScriptArg.length() - 2))
                    .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.space_separated>
        // @returns Element
        // @description
        // returns the list in a cleaner format, separated by spaces.
        // EG, a list of "one|two|three" will return "one two three".
        // -->
        if (attribute.startsWith("space_separated")) {
            if (isEmpty()) return new Element("").getAttribute(attribute.fulfill(1));
            StringBuilder dScriptArg = new StringBuilder();
            for (String item : this) {
                dScriptArg.append(item);
                // Insert a space after each item
                dScriptArg.append(" ");
            }
            return new Element(dScriptArg.toString().substring(0, dScriptArg.length() - 1))
                    .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.unseparated>
        // @returns Element
        // @description
        // returns the list in a less clean format, separated by nothing.
        // EG, a list of "one|two|three" will return "onetwothree".
        // -->
        if (attribute.startsWith("unseparated")) {
            if (isEmpty()) return new Element("").getAttribute(attribute.fulfill(1));
            StringBuilder dScriptArg = new StringBuilder();
            for (String item : this) {
                dScriptArg.append(item);
            }
            return new Element(dScriptArg.toString())
                    .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.formatted>
        // @returns Element
        // @description
        // returns the list in a human-readable format.
        // EG, a list of "n@3|p@bob|potato" will return "GuardNPC, bob, and potato".
        // -->
        if (attribute.startsWith("formatted")) {
            if (isEmpty()) return new Element("").getAttribute(attribute.fulfill(1));
            StringBuilder dScriptArg = new StringBuilder();

            for (int n = 0; n < this.size(); n++) {
                if (get(n).startsWith("p@")) {
                    dPlayer gotten = dPlayer.valueOf(get(n));
                    if (gotten != null) {
                        dScriptArg.append(gotten.getName());
                    }
                    else {
                        dScriptArg.append(get(n).replaceAll("\\w+@", ""));
                    }
                }
                else if (get(n).startsWith("e@") || get(n).startsWith("n@")) {
                    dEntity gotten = dEntity.valueOf(get(n));
                    if (gotten != null) {
                        dScriptArg.append(gotten.getName());
                    }
                    else {
                        dScriptArg.append(get(n).replaceAll("\\w+@", ""));
                    }
                }
                else {
                    dScriptArg.append(get(n).replaceAll("\\w+@", ""));
                }

                if (n == this.size() - 2) {
                    dScriptArg.append(n == 0 ? " and ": ", and ");
                }
                else {
                    dScriptArg.append(", ");
                }
            }

            return new Element(dScriptArg.toString().substring(0, dScriptArg.length() - 2))
                    .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.size>
        // @returns Element(Number)
        // @description
        // returns the size of the list.
        // EG, a list of "one|two|three" will return "3".
        // -->
        if (attribute.startsWith("size"))
            return new Element(size()).getAttribute(attribute.fulfill(1));

        // <--[tag]
        // @attribute <li@list.is_empty>
        // @returns Element(Boolean)
        // @description
        // returns whether the list is empty.
        // -->
        if (attribute.startsWith("is_empty"))
            return new Element(isEmpty()).getAttribute(attribute.fulfill(1));

        // <--[tag]
        // @attribute <li@list.as_string>
        // @returns Element
        // @description
        // returns each item in the list as a single 'String'.
        // EG, a list of "one|two|three" will return "one two three".
        // -->
        if (attribute.startsWith("asstring")
                || attribute.startsWith("as_string")) {
            if (isEmpty()) return new Element("").getAttribute(attribute.fulfill(1));
            StringBuilder dScriptArg = new StringBuilder();
            for (String item : this) {
                dScriptArg.append(item);
                // Insert space between items.
                dScriptArg.append(' ');
            }
            return new Element(dScriptArg.toString().substring(0, dScriptArg.length() - 1))
                    .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.insert[...|...].at[<#>]>
        // @returns dList
        // @description
        // returns a new dList with the items specified inserted to the specified location.
        // EG, .insert[two|three].at[2] on a list of "one|four" will return "one|two|three|four".
        // -->
        if (attribute.startsWith("insert") &&
                attribute.hasContext(1)) {
            dList items = dList.valueOf(attribute.getContext(1));
            attribute = attribute.fulfill(1);
            if (attribute.startsWith("at")
                    && attribute.hasContext(1)) {
                dList result = new dList(this);
                int index = new Element(attribute.getContext(1)).asInt() - 1;
                if (index < 0)
                    index = 0;
                if (index > result.size())
                    index = result.size();
                for (int i = 0; i < items.size(); i++) {
                    result.add(index + i, items.get(i));
                }
                return result.getAttribute(attribute.fulfill(1));
            }
            else {
                dB.echoError("The tag li@list.insert[...] requires an at[#] tag follow it!");
                return null;
            }
        }

        // <--[tag]
        // @attribute <li@list.include[...|...]>
        // @returns dList
        // @description
        // returns a new dList including the items specified.
        // EG, .include[three|four] on a list of "one|two" will return "one|two|three|four".
        // -->
        if (attribute.startsWith("include") &&
                attribute.hasContext(1)) {
            dList list = new dList(this);
            list.addAll(dList.valueOf(attribute.getContext(1)));
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.exclude[...|...]>
        // @returns dList
        // @description
        // returns a new dList excluding the items specified.
        // EG, .exclude[two|four] on a list of "one|two|three|four" will return "one|three".
        // -->
        if (attribute.startsWith("exclude") &&
                attribute.hasContext(1)) {
            dList exclusions = dList.valueOf(attribute.getContext(1));
            // Create a new dList that will contain the exclusions
            dList list = new dList(this);
            // Iterate through
            for (String exclusion : exclusions) {
                for (int i = 0;i < list.size();i++) {
                    if (list.get(i).equalsIgnoreCase(exclusion)) {
                        list.remove(i--);
                    }
                }
            }

            // Return the modified list
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.remove[<#>|...]>
        // @returns dList
        // @description
        // returns a new dList excluding the items at the specified index.
        // EG, .remove[2] on a list of "one|two|three|four" will return "one|three|four".
        // -->
        if (attribute.startsWith("remove") &&
                attribute.hasContext(1)) {
            dList indices = dList.valueOf(attribute.getContext(1));
            dList list = new dList(this);
            for (String index: indices) {
                int remove = new Element(index).asInt() - 1;
                if (remove >= 0 && remove < list.size()) {
                    list.set(remove, "\0");
                }
            }
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).equals("\0"))
                    list.remove(i--);
            }
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.reverse>
        // @returns dList
        // @description
        // returns a copy of the list, with all items placed in opposite order.
        // EG, a list of "one|two|three" will become "three|two|one".
        // -->
        if (attribute.startsWith("reverse")) {
            dList list = new dList(this);
            Collections.reverse(list);
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.deduplicate>
        // @returns dList
        // @description
        // returns a copy of the list with any duplicate items removed.
        // EG, a list of "one|one|two|three" will become "one|two|three".
        // -->
        if (attribute.startsWith("deduplicate")) {
            dList list = new dList();
            int listSize = 0;
            int size = this.size();
            for (int i = 0; i < size; i++) {
                String entry = get(i);
                boolean duplicate = false;
                for (int x = 0; x < listSize; x++) {
                    if (get(x).equalsIgnoreCase(entry)) {
                        duplicate = true;
                        break;
                    }
                }
                if (!duplicate) {
                    list.add(entry);
                    listSize++;
                }
            }
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.get[<#>|...]>
        // @returns dObject
        // @description
        // returns an element of the value specified by the supplied context.
        // EG, .get[1] on a list of "one|two" will return "one", and .get[2] will return "two"
        // Specify more than one index to get a list of results.
        // -->
        if (attribute.startsWith("get") &&
                attribute.hasContext(1)) {
            if (isEmpty()) return null;
            dList indices = dList.valueOf(attribute.getContext(1));
            if (indices.size() > 1) {
                dList results = new dList();
                for (String index: indices) {
                    int ind = aH.getIntegerFrom(index);
                    if (ind > 0 && ind <= size())
                        results.add(get(ind - 1));
                }
                return results.getAttribute(attribute.fulfill(1));
            }
            if (indices.size() > 0) {
                int index = aH.getIntegerFrom(indices.get(0));
                if (index > size()) return null;
                if (index < 1) index = 1;
                attribute = attribute.fulfill(1);

                // <--[tag]
                // @attribute <li@list.get[<#>].to[<#>]>
                // @returns dList
                // @description
                // returns all elements in the range from the first index to the second.
                // EG, .get[1].to[3] on a list of "one|two|three|four" will return "one|two|three"
                // -->
                if (attribute.startsWith("to") &&
                        attribute.hasContext(1)) {
                    int index2 = attribute.getIntContext(1);
                    if (index2 > size()) index2 = size();
                    if (index2 < 1) index2 = 1;
                    String item = "";
                    for (int i = index; i <= index2; i++) {
                        item += get(i - 1) + (i < index2 ? "|": "");
                    }
                    return new dList(item).getAttribute(attribute.fulfill(1));
                }
                else {
                    String item;
                    item = get(index - 1);
                    return ObjectFetcher.pickObjectFor(item).getAttribute(attribute);
                }
            }
        }

        // <--[tag]
        // @attribute <li@list.find_all_partial[<element>]>
        // @returns dList(Element(Number))
        // @description
        // returns all the numbered locations of elements within a list,
        // or an empty list if the list does not contain that item.
        // EG, .find[two] on a list of "one|two|three|two" will return "2|4".
        // TODO: Take multiple inputs? Or a regex?
        // -->
        if (attribute.startsWith("find_all_partial") &&
                attribute.hasContext(1)) {
            dList positions = new dList();
            for (int i = 0; i < size(); i++) {
                if (get(i).toUpperCase().contains(attribute.getContext(1).toUpperCase()))
                    positions.add(String.valueOf(i + 1));
            }
            return positions.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.find_all[<element>]>
        // @returns dList(Element(Number))
        // @description
        // returns all the numbered locations of elements within a list,
        // or an empty list if the list does not contain that item.
        // EG, .find[two] on a list of "one|two|three|two" will return "2|4".
        // TODO: Take multiple inputs? Or a regex?
        // -->
        if (attribute.startsWith("find_all") &&
                attribute.hasContext(1)) {
            dList positions = new dList();
            for (int i = 0; i < size(); i++) {
                if (get(i).equalsIgnoreCase(attribute.getContext(1)))
                    positions.add(String.valueOf(i + 1));
            }
            return positions.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.find_partial[<element>]>
        // @returns Element(Number)
        // @description
        // returns the numbered location of the first partially matching element within a list,
        // or -1 if the list does not contain that item.
        // EG, .find[two] on a list of "one|two|three" will return "2".
        // TODO: Take multiple inputs? Or a regex?
        // -->
        if (attribute.startsWith("find_partial") &&
                attribute.hasContext(1)) {
            for (int i = 0; i < size(); i++) {
                if (get(i).toUpperCase().contains(attribute.getContext(1).toUpperCase()))
                    return new Element(i + 1).getAttribute(attribute.fulfill(1));
            }
            return new Element(-1).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.find[<element>]>
        // @returns Element(Number)
        // @description
        // returns the numbered location of an element within a list,
        // or -1 if the list does not contain that item.
        // EG, .find[two] on a list of "one|two|three" will return "2".
        // TODO: Take multiple inputs? Or a regex?
        // -->
        if (attribute.startsWith("find") &&
                attribute.hasContext(1)) {
            for (int i = 0; i < size(); i++) {
                if (get(i).equalsIgnoreCase(attribute.getContext(1)))
                    return new Element(i + 1).getAttribute(attribute.fulfill(1));
            }
            // TODO: This should be find_partial or something
            /*
            for (int i = 0; i < size(); i++) {
                if (get(i).toUpperCase().contains(attribute.getContext(1).toUpperCase()))
                    return new Element(i + 1).getAttribute(attribute.fulfill(1));
            }
            */
            return new Element(-1).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.count[<element>]>
        // @returns Element(Number)
        // @description
        // returns how many times in the sub-list occurs.
        // EG, a list of "one|two|two|three" .count[two] returns 2.
        // -->
        if (attribute.startsWith("count") &&
                attribute.hasContext(1)) {
            String element = attribute.getContext(1);
            int count = 0;
            for (int i = 0; i < size(); i++) {
                if (get(i).equalsIgnoreCase(element))
                    count++;
            }
            return new Element(count).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.first>
        // @returns Element
        // @description
        // returns the first element in the list.
        // If the list is empty, returns null instead.
        // EG, a list of "one|two|three" will return "one".
        // Effectively equivalent to .get[1]
        // -->
        if (attribute.startsWith("first")) {
            if (size() == 0)
                return null;
            else
                return new Element(get(0)).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.last>
        // @returns Element
        // @description
        // returns the last element in the list.
        // If the list is empty, returns null instead.
        // EG, a list of "one|two|three" will return "three".
        // Effectively equivalent to .get[999999]
        // -->
        if (attribute.startsWith("last")) {
            if (size() == 0)
                return null;
            else
                return new Element(get(size() - 1)).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.numerical>
        // @returns Element
        // @description
        // returns the list sorted to be in numerical order.
        // EG, a list of "3|2|1|10" will return "1|2|3|10".
        // -->
        if (attribute.startsWith("numerical")) {
            dList list = new dList(this);
            Collections.sort(list, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    double value = new Element(o1).asDouble() - new Element(o2).asDouble();
                    if (value == 0)
                        return 0;
                    else if (value > 0)
                        return 1;
                    else
                        return -1;
                }
            });
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.alphanumeric>
        // @returns Element
        // @description
        // returns the list sorted to be in alphabetical/numerical order.
        // EG, a list of "b|c|a10|a1" will return "a1|a10|b|c".
        // -->
        if (attribute.startsWith("alphanumeric")) {
            dList list = new dList(this);
            Collections.sort(list, new NaturalOrderComparator());
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.alphabetical>
        // @returns Element
        // @description
        // returns the list sorted to be in alphabetical order.
        // EG, a list of "c|d|q|a|g" will return "a|c|d|g|q".
        // -->
        if (attribute.startsWith("alphabetical")) {
            dList list = new dList(this);
            Collections.sort(list, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o1.compareToIgnoreCase(o2);
                }
            });
            return list.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.sort[<procedure>]>
        // @returns Element
        // @description
        // returns a list sorted according to the return values of a procedure.
        // The <procedure> should link a procedure script that takes two definitions
        // each of which will be an item in the list, and returns -1, 0, or 1 based on
        // whether the second item should be added. EG, if a procedure with definitions
        // "one" and "two" returned 1, it would place "two" after "one". Note that this
        // uses some complex internal sorting code that could potentially throw errors
        // if the procedure does not return consistently - EG, if "one" and "two" returned
        // 1, but "two" and "one" returned 1 as well - obviously, "two" can not be both
        // before AND after "one"!
        // Note that the script should ALWAYS return -1, 0, or 1, or glitches will happen!
        // Note that if two inputs are exactly equal, the procedure should always return 0.
        // -->
        if (attribute.startsWith("sort")
                && attribute.hasContext(1)) {
            final ProcedureScriptContainer script = ScriptRegistry.getScriptContainer(attribute.getContext(1));
            if (script == null) {
                dB.echoError("'" + attribute.getContext(1) + "' is not a valid procedure script!");
                return getAttribute(attribute.fulfill(1));
            }
            final ScriptEntry entry = attribute.getScriptEntry();
            List<String> list = new ArrayList<String>(this);
            try {
                Collections.sort(list, new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        List<ScriptEntry> entries = script.getBaseEntries(entry.entryData.clone());
                        if (entries.isEmpty()) {
                            return 0;
                        }
                        long id = DetermineCommand.getNewId();
                        ScriptBuilder.addObjectToEntries(entries, "ReqId", id);
                        InstantQueue queue = InstantQueue.getQueue(ScriptQueue.getNextId("DLIST_SORT"));
                        queue.addEntries(entries);
                        queue.setReqId(id);
                        int x = 1;
                        dList definitions = new dList();
                        definitions.add(o1);
                        definitions.add(o2);
                        String[] definition_names = null;
                        try { definition_names = script.getString("definitions").split("\\|"); } catch (Exception e) { /* IGNORE */ }
                        for (String definition : definitions) {
                            String name = definition_names != null && definition_names.length >= x ?
                                    definition_names[x - 1].trim() : String.valueOf(x);
                            queue.addDefinition(name, definition);
                            dB.echoDebug(entry, "Adding definition %" + name + "% as " + definition);
                            x++;
                        }
                        queue.start();
                        int res = 0;
                        if (DetermineCommand.hasOutcome(id))
                            res = new Element(DetermineCommand.getOutcome(id)).asInt();
                        if (res < 0)
                            return -1;
                        else if (res > 0)
                            return 1;
                        else
                            return 0;
                    }
                });
            }
            catch (Exception e) {
                dB.echoError("list.sort[...] tag failed - procedure returned unreasonable valid - internal error: " + e.getMessage());
            }
            return new dList(list).getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.filter[<tag>]>
        // @returns dList
        // @description
        // returns a copy of the list with all its contents parsed through the given tag and only including ones that returned 'true'.
        // For example, a list of '1|2|3|4|5' .filter[is[or_more].than[3]] returns a list of '3|4|5'.
        // -->
        if (attribute.startsWith("filter")
                && attribute.hasContext(1)) {
            dList newlist = new dList();
            try {
                for (String str: this) {
                    if (ObjectFetcher.pickObjectFor(str).getAttribute(new Attribute(attribute.getContext(1),
                            attribute.getScriptEntry())).equalsIgnoreCase("true")) {
                        newlist.add(str);
                    }
                }
            }
            catch (Exception ex) {
                dB.echoError(ex);
            }
            return newlist.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.parse[<tag>]>
        // @returns dList
        // @description
        // returns a copy of the list with all its contents parsed through the given tag.
        // For example, a list of 'one|two' .parse[to_uppercase] returns a list of 'ONE|TWO'.
        // -->
        if (attribute.startsWith("parse")
                && attribute.hasContext(1)) {
            dList newlist = new dList();
            try {
                for (String str: this) {
                    newlist.add(ObjectFetcher.pickObjectFor(str).getAttribute(new Attribute(attribute.getContext(1),
                            attribute.getScriptEntry())));
                }
            }
            catch (Exception ex) {
                dB.echoError(ex);
            }
            return newlist.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.escape_contents>
        // @returns dList
        // @description
        // returns a copy of the list with all its contents escaped.
        // Inverts <@link tag li@list.unescape_contents>
        // See <@link language property escaping>
        // -->
        if (attribute.startsWith("escape_contents")) {
            dList escaped = new dList();
            for (String entry: this) {
                escaped.add(EscapeTags.Escape(entry));
            }
            return escaped.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.unescape_contents>
        // @returns dList
        // @description
        // returns a copy of the list with all its contents unescaped.
        // Inverts <@link tag li@list.escape_contents>
        // See <@link language property escaping>
        // -->
        if (attribute.startsWith("unescape_contents")) {
            dList escaped = new dList();
            for (String entry: this) {
                escaped.add(EscapeTags.unEscape(entry));
            }
            return escaped.getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.contains_any_case_sensitive[<element>|...]>
        // @returns Element(Boolean)
        // @description
        // returns whether the list contains any of a list of given elements, case-sensitive.
        // -->
        if (attribute.matches("contains_any_case_sensitive")) {
            if (attribute.hasContext(1)) {
                dList list = dList.valueOf(attribute.getContext(1));
                boolean state = false;

                full_set:
                for (String element : this) {
                    for (String sub_element: list) {
                        if (element.equals(sub_element)) {
                            state = true;
                            break full_set;
                        }
                    }
                }

                return new Element(state).getAttribute(attribute.fulfill(1));
            }
        }

        // <--[tag]
        // @attribute <li@list.contains_any[<element>|...]>
        // @returns Element(Boolean)
        // @description
        // returns whether the list contains any of a list of given elements.
        // -->
        if (attribute.matches("contains_any")) {
            if (attribute.hasContext(1)) {
                dList list = dList.valueOf(attribute.getContext(1));
                boolean state = false;

                full_set:
                for (String element : this) {
                    for (String sub_element: list) {
                        if (element.equalsIgnoreCase(sub_element)) {
                            state = true;
                            break full_set;
                        }
                    }
                }

                return new Element(state).getAttribute(attribute.fulfill(1));
            }
        }

        // <--[tag]
        // @attribute <li@list.contains_case_sensitive[<element>]>
        // @returns Element(Boolean)
        // @description
        // returns whether the list contains a given element, case-sensitive.
        // -->
        if (attribute.matches("contains_case_sensitive")) {
            if (attribute.hasContext(1)) {
                boolean state = false;

                for (String element : this) {
                    if (element.equals(attribute.getContext(1))) {
                        state = true;
                        break;
                    }
                }

                return new Element(state).getAttribute(attribute.fulfill(1));
            }
        }

        // <--[tag]
        // @attribute <li@list.contains[<element>|...]>
        // @returns Element(Boolean)
        // @description
        // returns whether the list contains all of the given elements.
        // -->
        if (attribute.matches("contains")
                && attribute.hasContext(1)) {
            dList needed = dList.valueOf(attribute.getContext(1));
            int gotten = 0;

            for (String check: needed) {
                for (String element : this) {
                    if (element.equalsIgnoreCase(check)) {
                        gotten++;
                        break;
                    }
                }
            }

            return new Element(gotten == needed.size()).getAttribute(attribute.fulfill(1));
        }

        if (attribute.startsWith("prefix"))
            return new Element(prefix)
                    .getAttribute(attribute.fulfill(1));

        if (attribute.startsWith("debug.log")) {
            dB.log(debug());
            return new Element(Boolean.TRUE.toString())
                    .getAttribute(attribute.fulfill(2));
        }

        if (attribute.startsWith("debug.no_color")) {
            return new Element(ChatColor.stripColor(debug()))
                    .getAttribute(attribute.fulfill(2));
        }

        if (attribute.startsWith("debug")) {
            return new Element(debug())
                    .getAttribute(attribute.fulfill(1));
        }

        if (attribute.startsWith("identify")) { // TODO: ???
            return new Element(identify())
                    .getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.type>
        // @returns Element
        // @description
        // Always returns 'List' for dList objects. All objects fetchable by the Object Fetcher will return the
        // type of object that is fulfilling this attribute.
        // -->
        if (attribute.startsWith("type")) {
            return new Element("List").getAttribute(attribute.fulfill(1));
        }

        // <--[tag]
        // @attribute <li@list.random[<#>]>
        // @returns Element
        // @description
        // Gets a random item in the list and returns it as an Element.
        // Optionally, add [<#>] to get a list of multiple randomly chosen elements.
        // EG, .random on a list of "one|two" could return EITHER "one" or "two" - different each time!
        // EG, .random[2] on a list of "one|two|three" could return "one|two", "two|three", OR "one|three" - different each time!
        // EG, .random[9999] on a list of "one|two|three" could return "one|two|three", "one|three|two", "two|one|three",
        // "two|three|one", "three|two|one", OR "three|one|two" - different each time!
        // -->
        if (attribute.startsWith("random")) {
            if (!this.isEmpty()) {
                if (attribute.hasContext(1)) {
                    int count = Integer.valueOf(attribute.getContext(1));
                    int times = 0;
                    ArrayList<String> available = new ArrayList<String>();
                    available.addAll(this);
                    dList toReturn = new dList();
                    while (!available.isEmpty() && times < count) {
                        int random = CoreUtilities.getRandom().nextInt(available.size());
                        toReturn.add(available.get(random));
                        available.remove(random);
                        times++;
                    }
                    return toReturn.getAttribute(attribute.fulfill(1));
                }
                else {
                    return ObjectFetcher.pickObjectFor(this.get(CoreUtilities.getRandom().nextInt(this.size())))
                            .getAttribute(attribute.fulfill(1));
                }
            }
        }

        // FLAG Specific Attributes

        // Note: is_expired attribute is handled in player/npc/server
        // since expired flags return 'null'

        // <--[tag]
        // @attribute <fl@flag_name.is_expired>
        // @returns Element(Boolean)
        // @description
        // returns true of the flag is expired or does not exist, false if it
        // is not yet expired, or has no expiration.
        // -->
        // NOTE: Defined in UtilTags.java

        // <--[tag]
        // @attribute <fl@flag_name.expiration>
        // @returns Duration
        // @description
        // returns a Duration of the time remaining on the flag, if it
        // has an expiration.
        // -->
        if (flag != null && attribute.startsWith("expiration")) {
            return flag.expiration()
                    .getAttribute(attribute.fulfill(1));
        }

        // Need this attribute (for flags) since they return the last
        // element of the list, unless '.as_list' is specified.

        // <--[tag]
        // @attribute <fl@flag_name.as_list>
        // @returns dList
        // @description
        // returns a dList containing the items in the flag.
        // -->
        if (flag != null && (attribute.startsWith("as_list")
                || attribute.startsWith("aslist")))
            return new dList(this).getAttribute(attribute.fulfill(1));


        // If this is a flag, return the last element (this is how it has always worked...)
        // Use as_list to return a list representation of the flag.
        // If this is NOT a flag, but instead a normal dList, return an element
        // with dList's identify() value.

        // Iterate through this object's properties' attributes
        for (Property property : PropertyParser.getProperties(this)) {
            String returned = property.getAttribute(attribute);
            if (returned != null) return returned;
        }

        return (flag != null
                ? new Element(flag.getLast().asString()).getAttribute(attribute)
                : new Element(identify()).getAttribute(attribute));
    }
}
TOP

Related Classes of net.aufdemrand.denizen.objects.dList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.