package org.wikipedia.page; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.wikipedia.gallery.GalleryCollection; import org.wikipedia.settings.RbSwitch; import java.util.ArrayList; import java.util.List; /** * Represents a particular page along with its full contents. */ public class Page { @VisibleForTesting static final int MEDIAWIKI_ORIGIN = 0; @VisibleForTesting static final int RESTBASE_ORIGIN = 1; @NonNull private final PageTitle title; @NonNull private final List<Section> sections; @NonNull private final PageProperties pageProperties; /** * The media gallery collection associated with this page. * This will be populated by the Gallery activity when necessary, and will be kept in * the page cache because the page itself is cached. Subsequent instances of the Gallery * activity will then be able to retrieve the page's gallery collection from cache. */ @Nullable private GalleryCollection galleryCollection; /** * An indicator what payload version the page content was originally retrieved from. * If it's set to RESTBASE_ORIGIN the it came from the Mobile Content Service * (via RESTBase). This is esp. useful for saved pages, so that an older saved page will get the * correct kind of DOM transformations applied. */ private int version = MEDIAWIKI_ORIGIN; @Nullable public GalleryCollection getGalleryCollection() { return galleryCollection; } public void setGalleryCollection(@Nullable GalleryCollection collection) { galleryCollection = collection; } /** Regular constructor */ public Page(@NonNull PageTitle title, @NonNull List<Section> sections, @NonNull PageProperties pageProperties) { if (RbSwitch.INSTANCE.isRestBaseEnabled(title.getWikiSite())) { this.version = RESTBASE_ORIGIN; } this.title = title; this.sections = sections; this.pageProperties = pageProperties; } @VisibleForTesting Page(@NonNull PageTitle title, @NonNull List<Section> sections, @NonNull PageProperties pageProperties, int version) { this.version = version; this.title = title; this.sections = sections; this.pageProperties = pageProperties; } /** * This could also be called getVersion but since there are only two different versions * I like to call it isFromRestBase to make it clearer. */ public boolean isFromRestBase() { return version == RESTBASE_ORIGIN; } @NonNull public PageTitle getTitle() { return title; } @NonNull public List<Section> getSections() { return sections; } public String getDisplayTitle() { return pageProperties.getDisplayTitle(); } @Nullable public String getTitlePronunciationUrl() { return getPageProperties().getTitlePronunciationUrl(); } @NonNull public PageProperties getPageProperties() { return pageProperties; } public boolean couldHaveReadMoreSection() { return getTitle().namespace() == Namespace.MAIN; } @Override public boolean equals(Object o) { if (!(o instanceof Page)) { return false; } Page other = (Page) o; return title.equals(other.title) && sections.equals(other.sections) && pageProperties.equals(other.pageProperties); } @Override public int hashCode() { int result = title.hashCode(); result = 31 * result + sections.hashCode(); result = 31 * result + pageProperties.hashCode(); return result; } @Override public String toString() { return "Page{" + "title=" + title + ", sections=" + sections + ", pageProperties=" + pageProperties + ", version=" + version + '}'; } public boolean isFilePage() { return title.isFilePage(); } public boolean isMainPage() { return pageProperties.isMainPage(); } public boolean isArticle() { return !isMainPage() && getTitle().namespace() == Namespace.MAIN; } @VisibleForTesting JSONObject toJSON() { JSONObject json = new JSONObject(); try { json.putOpt("version", version); json.putOpt("title", getTitle().toJSON()); JSONArray sectionsJSON = new JSONArray(); for (Section section : getSections()) { sectionsJSON.put(section.toJSON()); } json.putOpt("sections", sectionsJSON); json.putOpt("properties", pageProperties.toJSON()); if (galleryCollection != null) { json.put("gallery", galleryCollection.toJSON()); } return json; } catch (JSONException e) { throw new RuntimeException(e); } } public Page(JSONObject json) { version = json.optInt("version"); title = new PageTitle(json.optJSONObject("title")); JSONArray sectionsJSON = json.optJSONArray("sections"); sections = new ArrayList<>(sectionsJSON.length()); for (int i = 0; i < sectionsJSON.length(); i++) { sections.add(Section.fromJson(sectionsJSON.optJSONObject(i))); } pageProperties = new PageProperties(json.optJSONObject("properties")); if (json.has("gallery")) { galleryCollection = new GalleryCollection(json.optJSONObject("gallery")); } } /** For old PHP API */ public void addRemainingSections(List<Section> remainingSections) { sections.addAll(remainingSections); } /** For new RESTBase API */ public void augmentRemainingSections(List<Section> remainingSections) { // TODO: Use Parsoid to request the same revision ID, so that there's no race condition // that can lead to a mismatched number of sections. Section leadSection = sections.get(0); sections.clear(); sections.add(leadSection); sections.addAll(remainingSections); } public boolean isProtected() { return !getPageProperties().canEdit(); } }