All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.bliki.wiki.namespaces.Namespace Maven / Gradle / Ivy

The newest version!
package info.bliki.wiki.namespaces;

import info.bliki.Messages;
import info.bliki.wiki.filter.Encoder;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.TreeMap;

import static info.bliki.wiki.namespaces.INamespace.NamespaceCode.*;
import static java.lang.String.CASE_INSENSITIVE_ORDER;

/**
 * Mediawiki Namespaces.
 * @see  Mediawiki - Manual:Namespace
 */
public class Namespace implements INamespace {
    /**
     * Maps namespaces case-insensitively to their according
     * {@link NamespaceValue} objects.
     */
    private final Map TEXT_TO_NAMESPACE_MAP = new TreeMap<>(CASE_INSENSITIVE_ORDER);
    private final Map namespaceMap = new HashMap<>(NamespaceCode.values().length);

    /**
     * The "Media" namespace for the current language.
     */
    public final NamespaceValue MEDIA = new NamespaceValue(MEDIA_NAMESPACE_KEY, (NamespaceValue) null, "Media");
    /**
     * The "Special" namespace for the current language.
     */
    public final NamespaceValue SPECIAL = new NamespaceValue(SPECIAL_NAMESPACE_KEY, (NamespaceValue) null, "Special");
    /**
     * The "Talk" namespace for the current language.
     */
    public final NamespaceValue TALK = new NamespaceValue(TALK_NAMESPACE_KEY, "Talk");
    /**
     * The main namespace for the current language.
     */
    public final NamespaceValue MAIN = new NamespaceValue(MAIN_NAMESPACE_KEY, TALK, "");
    /**
     * The "User talk" namespace for the current language.
     */
    public final NamespaceValue USER_TALK = new NamespaceValue(USER_TALK_NAMESPACE_KEY, "User_talk");
    /**
     * The "User" namespace for the current language.
     */
    public final NamespaceValue USER = new NamespaceValue(USER_NAMESPACE_KEY, USER_TALK, "User");
    /**
     * The "Meta talk" namespace for the current language.
     */
    public final NamespaceValue PROJECT_TALK = new NamespaceValue(PROJECT_TALK_NAMESPACE_KEY, "Project_talk", "Meta_talk");
    /**
     * The "Meta" namespace for the current language.
     */
    public final NamespaceValue PROJECT = new NamespaceValue(PROJECT_NAMESPACE_KEY, PROJECT_TALK, "Project", "Meta");

    /**
     * NS_IMAGE and NS_IMAGE_TALK are the pre-v1.14 names for NS_FILE and
     * NS_FILE_TALK respectively, and are kept for compatibility.
     */
    public final NamespaceValue IMAGE_TALK = new NamespaceValue(FILE_TALK_NAMESPACE_KEY,  "File_talk", "Image_talk");
    public final NamespaceValue IMAGE = new NamespaceValue(FILE_NAMESPACE_KEY, IMAGE_TALK, "File", "Image");
    /**
     * The "MediaWiki talk" namespace for the current language.
     */
    public final NamespaceValue MEDIAWIKI_TALK = new NamespaceValue(MEDIAWIKI_TALK_NAMESPACE_KEY,  "MediaWiki_talk");
    /**
     * The "MediaWiki" namespace for the current language.
     */
    public final NamespaceValue MEDIAWIKI = new NamespaceValue(MEDIAWIKI_NAMESPACE_KEY, MEDIAWIKI_TALK, "MediaWiki");

    /**
     * The "Module talk" namespace for the current language.
     */
    public final NamespaceValue MODULE_TALK = new NamespaceValue(MODULE_TALK_NAMESPACE_KEY, "Module_talk");

    /**
     * The "Module" namespace for the current language.
     */
    public final NamespaceValue MODULE = new NamespaceValue(MODULE_NAMESPACE_KEY, MODULE_TALK, "Module");
    /**
     * The "Template talk" namespace for the current language.
     */
    public final NamespaceValue TEMPLATE_TALK = new NamespaceValue(TEMPLATE_TALK_NAMESPACE_KEY, "Template_talk");
    /**
     * The "Template" namespace for the current language.
     */
    public final NamespaceValue TEMPLATE = new NamespaceValue(TEMPLATE_NAMESPACE_KEY, TEMPLATE_TALK, "Template");

    /**
     * The "Help talk" namespace for the current language.
     */
    public final NamespaceValue HELP_TALK = new NamespaceValue(HELP_TALK_NAMESPACE_KEY,  "Help_talk");
    /**
     * The "Help" namespace for the current language.
     */
    public final NamespaceValue HELP = new NamespaceValue(HELP_NAMESPACE_KEY, HELP_TALK, "Help");
    /**
     * The "Category talk" namespace for the current language.
     */
    public final NamespaceValue CATEGORY_TALK = new NamespaceValue(CATEGORY_TALK_NAMESPACE_KEY, "Category_talk");
    /**
     * The "Category" namespace for the current language.
     */
    public final NamespaceValue CATEGORY = new NamespaceValue(CATEGORY_NAMESPACE_KEY, CATEGORY_TALK, "Category");
    /**
     * The "Portal talk" namespace for the current language.
     */
    public final NamespaceValue PORTAL_TALK = new NamespaceValue(PORTAL_TALK_NAMESPACE_KEY, "Portal_talk");
    /**
     * The "Portal" namespace for the current language.
     */
    public final NamespaceValue PORTAL = new NamespaceValue(PORTAL_NAMESPACE_KEY, PORTAL_TALK, "Portal");

    public final NamespaceValue BOOK_TALK = new NamespaceValue(BOOK_TALK_NAMESPACE_KEY, "Book_talk");
    public final NamespaceValue BOOK = new NamespaceValue(BOOK_NAMESPACE_KEY, BOOK_TALK, "Book");

    public final NamespaceValue DRAFT_TALK = new NamespaceValue(DRAFT_TALK_NAMESPACE_KEY, "Draft_talk");
    public final NamespaceValue DRAFT = new NamespaceValue(DRAFT_NAMESPACE_KEY, DRAFT_TALK, "Draft");

    public final NamespaceValue EP_TALK = new NamespaceValue(EP_TALK_NAMESPACE_KEY, "Education_Program_talk");
    public final NamespaceValue EP = new NamespaceValue(EP_NAMESPACE_KEY, EP_TALK, "Education_Program");

    public final NamespaceValue TIMEDTEXT_TALK = new NamespaceValue(TIMEDTEXT_TALK_NAMESPACE_KEY, "TimedText_talk");
    public final NamespaceValue TIMEDTEXT = new NamespaceValue(TIMEDTEXT_NAMESPACE_KEY, TIMEDTEXT_TALK, "TimedText");

    public final NamespaceValue TOPIC = new NamespaceValue(TOPIC_NAMESPACE_KEY, "Topic");

    protected ResourceBundle fResourceBundle, fResourceBundleEn;

    public Namespace() {
        this((ResourceBundle) null);
    }

    public Namespace(Locale locale) {
        this(Messages.getResourceBundle(locale));
    }

    public Namespace(ResourceBundle resourceBundle) {
        fResourceBundle = resourceBundle;
        fResourceBundleEn = Messages.getResourceBundle(Locale.ENGLISH);
        initializeNamespaces();
    }

    @Override
    public boolean isNamespace(String namespace, NamespaceCode code) {
        NamespaceValue nsVal = getNamespace(namespace);
        return nsVal != null && isNamespace(nsVal, code);
    }

    @Override
    public boolean isNamespace(INamespaceValue namespace, NamespaceCode code) {
        return namespace != null && namespace.getCode() == code;
    }

    @Override @Nullable
    public NamespaceValue getNamespace(String namespace) {
        return TEXT_TO_NAMESPACE_MAP.get(namespace);
    }

    @Override
    public NamespaceValue getNamespaceByNumber(NamespaceCode numberCode) {
        return getNamespaceByNumber(numberCode.code);
    }

    @Override @Nullable
    public NamespaceValue getNamespaceByNumber(int numberCode) {
        return namespaceMap.get(numberCode);
    }

    @Override
    public ResourceBundle getResourceBundle() {
        return fResourceBundle;
    }

    protected enum ExtractType {
        REPLACE_TEXTS, APPEND_AS_ALIASES
    }

    private void extractFromResource(ResourceBundle resourceBundle,
            String ns1Id, String ns2Id, NamespaceCode code, ExtractType cmd) {
        NamespaceValue namespace = getNamespaceByNumber(code);
        assert (namespace != null) : "undefined namespace code: " + code;
        String ns1 = Messages.getString(resourceBundle, ns1Id, null);
        if (ns1 != null) {
            String ns2 = Messages.getString(resourceBundle, ns2Id, null);
            switch (cmd) {
            case REPLACE_TEXTS:
                if (ns2 != null) {
                    namespace.setTexts(ns1, ns2);
                } else {
                    namespace.setTexts(ns1);
                }
            case APPEND_AS_ALIASES:
                namespace.addAlias(ns1);
                if (ns2 != null) {
                    namespace.addAlias(ns2);
                }
            }
        }
    }

    protected void extractFromResource(ResourceBundle resource, ExtractType cmd) {
        if (resource == null) {
            return;
        }
        extractFromResource(resource, Messages.WIKI_API_MEDIA1,         Messages.WIKI_API_MEDIA2, MEDIA_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_SPECIAL1,       Messages.WIKI_API_SPECIAL2, SPECIAL_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_TALK1,          Messages.WIKI_API_TALK2, TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_USER1,          Messages.WIKI_API_USER2, USER_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_USERTALK1,      Messages.WIKI_API_USERTALK2, USER_TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_META1,          Messages.WIKI_API_META2, PROJECT_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_METATALK1,      Messages.WIKI_API_METATALK2, PROJECT_TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_IMAGE1,         Messages.WIKI_API_IMAGE2, FILE_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_IMAGETALK1,     Messages.WIKI_API_IMAGETALK2, FILE_TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_MEDIAWIKI1,     Messages.WIKI_API_MEDIAWIKI2, MEDIAWIKI_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_MEDIAWIKITALK1, Messages.WIKI_API_MEDIAWIKITALK2, MEDIAWIKI_TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_TEMPLATE1,      Messages.WIKI_API_TEMPLATE2, TEMPLATE_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_TEMPLATETALK1,  Messages.WIKI_API_TEMPLATETALK2, TEMPLATE_TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_HELP1,          Messages.WIKI_API_HELP2, HELP_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_HELPTALK1,      Messages.WIKI_API_HELPTALK2, HELP_TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_CATEGORY1,      Messages.WIKI_API_CATEGORY2, CATEGORY_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_CATEGORYTALK1,  Messages.WIKI_API_CATEGORYTALK2, CATEGORY_TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_PORTAL1,        Messages.WIKI_API_PORTAL2, PORTAL_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_PORTALTALK1,    Messages.WIKI_API_PORTALTALK2, PORTAL_TALK_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_MODULE1,        Messages.WIKI_API_MODULE2, MODULE_NAMESPACE_KEY, cmd);
        extractFromResource(resource, Messages.WIKI_API_MODULETALK1,    Messages.WIKI_API_MODULETALK2, MODULE_TALK_NAMESPACE_KEY, cmd);
    }

    private void initializeNamespaces() {
        extractFromResource(fResourceBundle, ExtractType.REPLACE_TEXTS);
        extractFromResource(fResourceBundleEn, ExtractType.APPEND_AS_ALIASES);

        // Aliases as defined by
        // https://en.wikipedia.org/wiki/Wikipedia:Namespace#Aliases
        PROJECT.addAlias("WP");
        PROJECT.addAlias("Project");
        PROJECT_TALK.addAlias("WT");
        PROJECT_TALK.addAlias("Project_talk");
        // already in the English resource bundle:
        // IMAGE.addAlias("Image");
        // IMAGE_TALK.addAlias("Image_talk");
    }

    @Override
    public NamespaceValue getTalkspace(String namespace) {
        NamespaceValue nsVal = getNamespace(namespace);
        if (nsVal != null) {
            return nsVal.getTalkspace();
        }
        return null;
    }

    @Override
    public NamespaceValue getContentspace(String talkNamespace) {
        NamespaceValue nsVal = getNamespace(talkNamespace);
        if (nsVal != null) {
            return nsVal.getContentspace();
        }
        return null;
    }

    @Override
    public INamespaceValue getMedia() {
        return MEDIA;
    }

    @Override
    public INamespaceValue getSpecial() {
        return SPECIAL;
    }

    @Override
    public INamespaceValue getMain() {
        return MAIN;
    }

    @Override
    public INamespaceValue getTalk() {
        return TALK;
    }

    @Override
    public INamespaceValue getUser() {
        return USER;
    }

    @Override
    public INamespaceValue getUser_talk() {
        return USER_TALK;
    }

    @Override
    public INamespaceValue getProject() { return PROJECT; }

    @Override
    public INamespaceValue getProject_talk() {
        return PROJECT_TALK;
    }

    @Override
    public INamespaceValue getImage() {
        return IMAGE;
    }

    @Override
    public INamespaceValue getImage_talk() {
        return IMAGE_TALK;
    }

    @Override
    public INamespaceValue getMediaWiki() {
        return MEDIAWIKI;
    }

    @Override
    public INamespaceValue getMediaWiki_talk() {
        return MEDIAWIKI_TALK;
    }

    @Override
    public INamespaceValue getModule() {
        return MODULE;
    }

    @Override
    public INamespaceValue getTemplate() {
        return TEMPLATE;
    }

    @Override
    public INamespaceValue getTemplate_talk() {
        return TEMPLATE_TALK;
    }

    @Override
    public INamespaceValue getHelp() {
        return HELP;
    }

    @Override
    public INamespaceValue getHelp_talk() {
        return HELP_TALK;
    }

    @Override
    public INamespaceValue getCategory() {
        return CATEGORY;
    }

    @Override
    public INamespaceValue getCategory_talk() {
        return CATEGORY_TALK;
    }

    @Override
    public INamespaceValue getPortal() {
        return PORTAL;
    }

    @Override
    public INamespaceValue getPortal_talk() {
        return PORTAL_TALK;
    }

    @Override
    public String[] splitNsTitle(String fullTitle) {
        return splitNsTitle(fullTitle, true, ' ', true);
    }

    @Override
    public String[] splitNsTitle(String fullTitle,
            boolean underScoreIsWhitespace, char whiteSpaceChar,
            boolean firstCharacterAsUpperCase) {
        int colonIndex = fullTitle.indexOf(':');
        if (colonIndex != (-1)) {
            String maybeNs = Encoder.normaliseTitle(
                    fullTitle.substring(0, colonIndex), underScoreIsWhitespace,
                    whiteSpaceChar, firstCharacterAsUpperCase);
            if (getNamespace(maybeNs) != null) {
                // this is a real namespace
                return new String[] {
                        maybeNs,
                        Encoder.normaliseTitle(
                                fullTitle.substring(colonIndex + 1),
                                underScoreIsWhitespace, whiteSpaceChar,
                                firstCharacterAsUpperCase) };
            }
            // else: page belongs to the main namespace and only contains a
            // colon
        }
        return new String[] {
                "",
                Encoder.normaliseTitle(fullTitle, underScoreIsWhitespace,
                        whiteSpaceChar, firstCharacterAsUpperCase) };
    }

    /**
     * Base class for all namespace constants.
     *
     * @author Nico Kruber, [email protected]
     */
    public class NamespaceValue implements INamespaceValue {
        private final NamespaceCode code;
        private final String[] canonicalAliases;
        private List texts;
        private NamespaceValue talkspace;
        private NamespaceValue contentspace;

        /**
         * Constructor for talk namespaces.
         *
         * @param code    the (internal) integer code of this namespace
         * @param aliases all aliases identifying this namespace
         */
        private NamespaceValue(NamespaceCode code, String... aliases) {
            this.code = code;
            this.texts = new ArrayList<>(2);
            namespaceMap.put(code.code, this);
            // content space is set by the content NamespaceValue
            this.talkspace = this;
            this.canonicalAliases = aliases;
            setTexts(aliases);
        }

        /**
         * Constructor for content namespaces.
         *
         * @param code the (internal) integer code of this namespace
         * @param talkspace the associated talk namespace (must not be null)
         * @param aliases all aliases identifying this namespace
         */
        private NamespaceValue(NamespaceCode code, NamespaceValue talkspace, String... aliases) {
            this(code, aliases);
            // mapping of talkspace to content space is 1:1 if a talkspace exists
            if (talkspace != null) {
                assert (talkspace.contentspace == null);
                this.talkspace = talkspace;
                this.talkspace.contentspace = this;
            }
            this.contentspace = this;
        }

        @Override
        public NamespaceCode getCode() {
            return code;
        }

        @Override
        public void setTexts(String... aliases) {
            assert (aliases.length >= 1);
            // remove old texts:
            for (String text : this.texts) {
                TEXT_TO_NAMESPACE_MAP.remove(text);
                TEXT_TO_NAMESPACE_MAP.remove(text.replace(' ', '_'));
                TEXT_TO_NAMESPACE_MAP.remove(text.replace('_', ' '));
            }
            // note: don't assign the fixed-size list of Arrays.asList to texts!
            texts = new ArrayList<>(aliases.length);
            for (String alias : aliases) {
                assert (alias != null);
                addAlias(alias);
            }
        }

        @Override
        public void addAlias(String alias) {
            if (!TEXT_TO_NAMESPACE_MAP.containsKey(alias)) {
                texts.add(alias);
                TEXT_TO_NAMESPACE_MAP.put(alias, this);
                TEXT_TO_NAMESPACE_MAP.put(alias.replace(' ', '_'), this);
                TEXT_TO_NAMESPACE_MAP.put(alias.replace('_', ' '), this);
            }
        }

        @Override
        public String getPrimaryText() {
            return texts.isEmpty() ? null : texts.get(0);
        }

        @Override
        public String getCanonicalName() {
            return this.canonicalAliases[0];
        }

        @Override
        public List getTexts() {
            return texts;
        }

        @Override
        public NamespaceValue getTalkspace() {
            return talkspace;
        }

        @Override
        public NamespaceValue getContentspace() {
            return contentspace;
        }

        @Override
        public NamespaceValue getAssociatedspace() {
            if (isSubject()) {
                return getTalkspace();
            } else if (isTalk()) {
                return getContentspace();
            } else {
                return null;
            }
        }

        @Override
        public String makeFullPagename(String pageName) {
            String primaryText = getPrimaryText();
            if (primaryText.isEmpty()) {
                return pageName;
            } else {
                return primaryText + ":" + pageName;
            }
        }

        @Override
        public boolean isType(NamespaceCode code) {
            return this.code == code;
        }

        @Override
        public boolean hasSubpages() {
            return this.code.hasSubpages();
        }

        @Override
        public boolean hasGenderDistinction() {
            return this.code == USER_NAMESPACE_KEY || this.code == USER_TALK_NAMESPACE_KEY;
        }

        @Override
        public boolean isCapitalized() {
            return true;
        }

        @Override
        public boolean isContent() {
            return this.code == MAIN_NAMESPACE_KEY;
        }

        @Override
        public boolean isIncludable() {
            return true;
        }

        @Override
        public boolean isMovable() {
            return false;
        }

        @Override
        public boolean isSubject() {
            return this.talkspace != this;
        }

        @Override
        public boolean isTalk() {
            return this.talkspace == this;
        }

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy