1    /*
2     * Copyright 2007 :torweg free software group
3     * 
4     * This program is free software: you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation, either version 3 of the License, or
7     * (at your option) any later version.
8     * 
9     * This program is distributed in the hope that it will be useful,
10    * but WITHOUT ANY WARRANTY; without even the implied warranty of
11    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    * GNU General Public License for more details.
13    * 
14    * You should have received a copy of the GNU General Public License
15    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16    *
17    */
18   package org.torweg.pulse.component.core.site.map;
19   
20   import java.util.List;
21   
22   import org.hibernate.LazyInitializationException;
23   import org.jdom.Element;
24   import org.torweg.pulse.bundle.Result;
25   import org.torweg.pulse.service.request.ServiceRequest;
26   import org.torweg.pulse.site.map.SitemapNode;
27   import org.torweg.pulse.util.entity.Node;
28   
29   /**
30    * builds a menu for the website.
31    * 
32    * @see SitemapMenuController
33    * @author Thomas Weber
34    * @version $Revision: 1631 $
35    */
36   public class MenuResult implements Result {
37   
38       /**
39        * the base node.
40        */
41       private final SitemapNode baseNode;
42   
43       /**
44        * the current request.
45        */
46       private final ServiceRequest request;
47   
48       /**
49        * a flag indicating, whether the selected node is the root node.
50        */
51       private Boolean rootSelected;
52   
53       /**
54        * the root node.
55        */
56       private SitemapNode rootNode;
57   
58       /**
59        * base for three level menu.
60        */
61       private SitemapNode threeLevelBase;
62   
63       /**
64        * the bread crumb.
65        */
66       private final List<SitemapNode> breadCrumb;
67   
68       /**
69        * builds a new {@code MenuResult}.
70        * 
71        * @param base
72        *            the base node of the menu#
73        * @param bc
74        *            the bread crumb
75        * @param req
76        *            the current request
77        */
78       public MenuResult(final SitemapNode base, final List<SitemapNode> bc,
79               final ServiceRequest req) {
80           this.baseNode = base;
81           this.request = req;
82           this.breadCrumb = bc;
83       }
84   
85       /**
86        * deserialises the menu to a JDOM representation.
87        * 
88        * @return the menu as a JDOM representation
89        * @see org.torweg.pulse.bundle.JDOMable#deserializeToJDOM()
90        */
91       public Element deserializeToJDOM() {
92           Element jdom = new Element("result").setAttribute("class", this
93                   .getClass().getCanonicalName());
94           if ((this.rootSelected != null) && this.rootSelected) {
95               jdom.setAttribute("isRootSelected", "true");
96           }
97           if (this.rootNode != null) {
98               jdom.addContent(new Element("root-node").addContent(processNode(
99                       this.rootNode, 0)));
100          }
101          recurseThroughNodes(this.baseNode, jdom, 0);
102          if (this.threeLevelBase != null) {
103              Element menuBase = new Element("menu-base");
104              recurseThroughNodes(this.threeLevelBase, menuBase, 0);
105              jdom.addContent(menuBase);
106          }
107          if (this.breadCrumb != null) {
108              jdom.addContent(buildBreadCrumb());
109          }
110          return jdom;
111      }
112  
113      /**
114       * builds a list of all {@code SitemapNode}s from the selected node up to
115       * the root node.
116       * 
117       * @return an Element containing a list of all {@code SitemapNode}s from the
118       *         selected node up to the root node
119       */
120      private Element buildBreadCrumb() {
121          Element bc = new Element("bread-crumb");
122          int c = 0;
123          for (SitemapNode n : this.breadCrumb) {
124              bc.addContent(processNode(n, c++));
125          }
126          return bc;
127      }
128  
129      /**
130       * builds the JDOM result recursively.
131       * 
132       * @param node
133       *            the current node to be processed
134       * @param jdom
135       *            the last processed node of the JDOM result
136       * @param level
137       *            the depth of the current node (starting at 0)
138       * @return the JDOM result
139       */
140      private Element recurseThroughNodes(final SitemapNode node,
141              final Element jdom, final int level) {
142  
143          /*
144           * if either the node is null, invisible or requires roles which cannot
145           * be satisfied by the current user
146           */
147          if ((node == null) || (!node.isVisible())
148                  || (!this.request.getUser().hasAllowanceFor(node))) {
149              return jdom;
150          }
151  
152          /* add all visible nodes */
153          Element menuitem = processNode(node, level);
154          jdom.addContent(menuitem);
155  
156          for (Node n : node.getChildren()) {
157              try {
158                  recurseThroughNodes((SitemapNode) n, menuitem, level + 1);
159              } catch (LazyInitializationException e) {
160                  continue;
161              }
162          }
163          return jdom;
164      }
165  
166      /**
167       * processes a {@code SitemapNode} to a menuitem {@code Element}.
168       * 
169       * @param node
170       *            the node
171       * @param level
172       *            the level
173       * @return the menuitem {@code Element}
174       */
175      private Element processNode(final SitemapNode node, final int level) {
176  
177          String url;
178          if ((node.getView() != null)) {
179              url = node.getView().getCommand(
180                      this.request.getCommand().createCopy(false)).setSitemapID(
181                      node.getId()).toCommandURL(this.request);
182          } else {
183              url = this.request.getCommand().createCopy(false).setSitemapID(
184                      node.getId()).toCommandURL(this.request);
185          }
186  
187          Element menuitem = new Element("menuitem").setAttribute("name",
188                  node.getName()).setAttribute("level", Integer.toString(level))
189                  .setAttribute("id", Long.toString(node.getId())).setAttribute(
190                          "visible", Boolean.toString(node.isVisible())).setText(
191                          url);
192          if (node.getSectionTag() != null) {
193              menuitem
194                      .setAttribute("section-tag", node.getSectionTag().getName());
195              menuitem.setAttribute("section-tag-id", node.getSectionTag()
196                      .getId().toString());
197          }
198          return menuitem;
199      }
200  
201      /**
202       * sets the flag, which indicates whether the selected node is the root
203       * node.
204       * 
205       * @param flag
206       *            the flag
207       * @return this
208       */
209      public final MenuResult setRootSelected(final boolean flag) {
210          this.rootSelected = flag;
211          return this;
212      }
213  
214      /**
215       * adds the root node to the result.
216       * 
217       * @param root
218       *            the root node
219       * @return this
220       */
221      public final MenuResult setRootNode(final SitemapNode root) {
222          this.rootNode = root;
223          return this;
224      }
225  
226      /**
227       * initialised base of the first three menu levels.
228       * 
229       * @param root
230       *            the root node
231       * @return this instance
232       */
233      public final MenuResult setThreeLevelBase(final SitemapNode root) {
234          this.threeLevelBase = root;
235          return this;
236      }
237  
238  }
239