001/*
002 * JGrapes Event Driven Framework
003 * Copyright (C) 2017-2018 Michael N. Lipp
004 * 
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Affero General Public License as published by 
007 * the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 * 
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
013 * for more details.
014 * 
015 * You should have received a copy of the GNU Affero General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jgrapes.portal.base.events;
020
021import java.io.IOException;
022import java.io.Writer;
023import java.net.URI;
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.List;
027
028import org.jdrupes.json.JsonArray;
029import org.jgrapes.portal.base.Portlet.RenderMode;
030import org.jgrapes.portal.base.RenderSupport;
031import org.jgrapes.portal.base.events.AddPageResources.ScriptResource;
032
033/**
034 * Adds a portlet type with its global resources (JavaScript and/or CSS) 
035 * to the portal page. Specifying global resources result in the respective
036 * `<link .../>` or `<script ...></script>` nodes
037 * being added to the page's `<head>` node.
038 * 
039 * This in turn causes the browser to issue `GET` requests that
040 * (usually) refer to the portlet's resources. These requests are
041 * converted to {@link PortletResourceRequest}s by the portal and
042 * sent to the portlets, which must respond to the requests.
043 * 
044 * The sequence of events is shown in the diagram.
045 * 
046 * ![Portal Ready Event Sequence](AddPortletTypeSeq.svg)
047 * 
048 * See {@link ResourceRequest} for details about the processing
049 * of the {@link PortletResourceRequest}.
050 * 
051 * A portelt's JavaScript may (and probably must) make use of
052 * the functions provided by the portal page. See the 
053 * <a href="../../../../../jsdoc/JGPortal.html">JavaScript
054 * documentation of these functions</a> for details.
055 * 
056 * @startuml AddPortletTypeSeq.svg
057 * hide footbox
058 * 
059 * activate Browser
060 * Browser -> Portal: "portalReady"
061 * deactivate Browser
062 * activate Portal
063 * Portal -> PortletX: PortalReady 
064 * deactivate Portal
065 * activate PortletX
066 * PortletX -> Portal: AddPortletType 
067 * deactivate PortletX
068 * activate Portal
069 * Portal -> Browser: "addPortletType"
070 * activate Browser
071 * deactivate Portal
072 * Browser -> Portal: "GET <portlet resource URI>"
073 * activate Portal
074 * Portal -> PortletX: PortletResourceRequest
075 * deactivate Browser
076 * activate PortletX
077 * deactivate PortletX
078 * 
079 * @enduml
080 */
081public class AddPortletType extends PortalCommand {
082
083    private final String portletType;
084    private String displayName = "";
085    private final List<URI> cssUris = new ArrayList<>();
086    private final List<ScriptResource> scriptResources = new ArrayList<>();
087    private final List<RenderMode> renderModes = new ArrayList<>();
088
089    /**
090     * Create a new event for the given portlet type.
091     * 
092     * @param portletType a unique id for the portklet type (usually
093     * the class name)
094     */
095    public AddPortletType(String portletType) {
096        this.portletType = portletType;
097    }
098
099    /**
100     * Return the portlet type.
101     * 
102     * @return the portlet type
103     */
104    public String portletType() {
105        return portletType;
106    }
107
108    /**
109     * Sets the display name.
110     * 
111     * @param displayName the display name
112     * @return the event for easy chaining
113     */
114    public AddPortletType setDisplayName(String displayName) {
115        this.displayName = displayName;
116        return this;
117    }
118
119    /**
120     * Return the display name.
121     * 
122     * @return the displayName
123     */
124    public String displayName() {
125        return displayName;
126    }
127
128    /**
129     * Add a render mode. The render mode determines how the portlet
130     * is initially rendered (i.e. when added). Several modes may be
131     * added in order of preference. The default mode (i.e. none 
132     * specified) is {@link RenderMode#Preview}.
133     *
134     * @param mode the mode
135     * @return the event for easy chaining
136     */
137    public AddPortletType addRenderMode(RenderMode mode) {
138        renderModes.add(mode);
139        return this;
140    }
141
142    /**
143     * Return the render modes.
144     * 
145     * @return the result
146     */
147    public List<RenderMode> renderModes() {
148        return renderModes;
149    }
150
151    /**
152     * Add a script resource to be requested by the browser.
153     * 
154     * @param scriptResource the script resource
155     * @return the event for easy chaining
156     */
157    public AddPortletType addScript(ScriptResource scriptResource) {
158        scriptResources.add(scriptResource);
159        return this;
160    }
161
162    /**
163     * Add the URI of a CSS resource that is to be added to the
164     * header section of the portal page.
165     *
166     * @param renderSupport the render support for mapping the `uri`
167     * @param uri the URI
168     * @return the event for easy chaining
169     */
170    public AddPortletType addCss(RenderSupport renderSupport, URI uri) {
171        cssUris.add(renderSupport.portletResource(portletType(), uri));
172        return this;
173    }
174
175    /**
176     * Return all script resources.
177     * 
178     * @return the result
179     */
180    public ScriptResource[] scriptResources() {
181        return scriptResources.toArray(new ScriptResource[0]);
182    }
183
184    /**
185     * Return all CSS URIs.
186     * 
187     * @return the result
188     */
189    public URI[] cssUris() {
190        return cssUris.toArray(new URI[0]);
191    }
192
193    @Override
194    public void toJson(Writer writer) throws IOException {
195        JsonArray strArray = JsonArray.create();
196        for (ScriptResource scriptResource : scriptResources()) {
197            strArray.append(scriptResource.toJsonValue());
198        }
199        toJson(writer, "addPortletType", portletType(), displayName(),
200            Arrays.stream(cssUris()).map(
201                uri -> uri.toString()).toArray(String[]::new),
202            strArray, renderModes().stream().map(RenderMode::name)
203                .toArray(size -> new String[size]));
204    }
205}