001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.sitemap.shared;
029
030import org.opencms.ade.detailpage.CmsDetailPageInfo;
031import org.opencms.util.CmsUUID;
032
033import java.io.Serializable;
034import java.util.ArrayList;
035import java.util.Collection;
036import java.util.HashMap;
037import java.util.List;
038import java.util.Map;
039
040import com.google.common.collect.ArrayListMultimap;
041
042/**
043 * A data structure for managing the detail page ordering for different types in a given sitemap.<p>
044 *
045 * @since 8.0.0
046 */
047public class CmsDetailPageTable implements Cloneable, Serializable {
048
049    /** A type indicating the status of a page. */
050    public static enum Status {
051        /** default detail page. */
052        firstDetailPage, /** no detail page. */
053        noDetailPage, /** non-default detail page. */
054        otherDetailPage
055    }
056
057    /** ID for serialization. */
058    private static final long serialVersionUID = -4561142050519767250L;
059
060    /** The detail page info beans indexed by id. */
061    private Map<CmsUUID, CmsDetailPageInfo> m_infoById = new HashMap<CmsUUID, CmsDetailPageInfo>();
062
063    /** The detail page info beans, indexed by type. */
064    private ArrayListMultimap<String, CmsDetailPageInfo> m_map = ArrayListMultimap.create();
065
066    /**
067     * Creates a detail page table from a list of detail page info bean.<p>
068     *
069     * @param infos the detail page info beans
070     */
071    public CmsDetailPageTable(List<CmsDetailPageInfo> infos) {
072
073        for (CmsDetailPageInfo info : infos) {
074            m_map.put(info.getType(), info);
075            m_infoById.put(info.getId(), info);
076        }
077    }
078
079    /**
080     * Empty default constructor for serialization.<p>
081     */
082    protected CmsDetailPageTable() {
083
084        // for serialization
085    }
086
087    /**
088     * Adds a new detail page information bean to the detail page table.<p>
089     *
090     * @param info the detail page info to add
091     */
092    public void add(CmsDetailPageInfo info) {
093
094        m_map.put(info.getType(), info);
095        m_infoById.put(info.getId(), info);
096    }
097
098    /**
099     * Moves the detail page information for a given page to the front of the detail pages for the same type.<p>
100     *
101     * @param id a page id
102     *
103     * @return the original position of the detail page entry in the list for the same type
104     */
105    public int bump(CmsUUID id) {
106
107        CmsDetailPageInfo info = m_infoById.get(id);
108        if (info == null) {
109            throw new IllegalArgumentException();
110        }
111        String type = info.getType();
112        List<CmsDetailPageInfo> infos = m_map.get(type);
113        int oldPos = infos.indexOf(info);
114        infos.remove(oldPos);
115        infos.add(0, info);
116        return oldPos;
117    }
118
119    /**
120     * Returns true if the detail page table contains a page with a given id.<p>
121     *
122     * @param id the page id
123     * @return true if the detail page table contains the page with the given id
124     */
125    public boolean contains(CmsUUID id) {
126
127        return m_infoById.containsKey(id);
128    }
129
130    /**
131     * Copies the detail page table.<p>
132     *
133     * @return the copy of the detail page table
134     */
135    public CmsDetailPageTable copy() {
136
137        List<CmsDetailPageInfo> infos = toList();
138        CmsDetailPageTable result = new CmsDetailPageTable();
139        for (CmsDetailPageInfo info : infos) {
140            result.add(info);
141        }
142        return result;
143    }
144
145    /**
146     * Returns the detail page info for a given page id.<p>
147     *
148     * @param id a page id
149     * @return the detail page info for the given page id
150     */
151    public CmsDetailPageInfo get(CmsUUID id) {
152
153        return m_infoById.get(id);
154    }
155
156    /**
157     * Returns the page ids of all detail pages. <p>
158     *
159     * @return the page ids of all detail pages
160     */
161    public Collection<CmsUUID> getAllIds() {
162
163        return m_infoById.keySet();
164    }
165
166    /**
167     * Returns the detail page which is in front of the detail page list for the given type.<p>
168     *
169     * @param type a resource type
170     * @return a detail page information bean
171     */
172    public CmsDetailPageInfo getBestDetailPage(String type) {
173
174        List<CmsDetailPageInfo> infos = m_map.get(type);
175        if ((infos == null) || infos.isEmpty()) {
176            return null;
177        }
178        return infos.get(0);
179    }
180
181    /**
182     * Returns a list which contains the best detail page for each type.<p>
183     *
184     * @return the list of best detail pages for each type
185     */
186    public List<CmsDetailPageInfo> getBestDetailPages() {
187
188        List<CmsDetailPageInfo> result = new ArrayList<CmsDetailPageInfo>();
189        for (String key : m_map.keySet()) {
190            List<CmsDetailPageInfo> vals = m_map.get(key);
191            if (!vals.isEmpty()) {
192                result.add(vals.get(0));
193            }
194        }
195        return result;
196
197    }
198
199    /**
200     * Returns the list of detail page info beans for a given type.<p>
201     *
202     * @param type the type for which the detail page beans should be retrieved
203     *
204     * @return the detail page beans for that type
205     */
206    public List<CmsDetailPageInfo> getInfosForType(String type) {
207
208        return new ArrayList<CmsDetailPageInfo>(m_map.get(type));
209    }
210
211    /**
212     * Returns the page status for the page with the given id.<p>
213     *
214     * @param id the id for which the page status should be checked
215     *
216     * @return the status of the page with the given id
217     */
218    public Status getStatus(CmsUUID id) {
219
220        CmsDetailPageInfo info = m_infoById.get(id);
221        if (info == null) {
222            return Status.noDetailPage;
223        }
224        String type = info.getType();
225        int index = m_map.get(type).indexOf(info);
226        if (index == 0) {
227            return Status.firstDetailPage;
228        }
229        return Status.otherDetailPage;
230    }
231
232    /**
233     * Returns true if the page with the given id is the default detail page for its type.<p>
234     *
235     * @param id a page id
236     *
237     * @return true if the detail page for the page id is the default detail page
238     */
239    public boolean isDefaultDetailPage(CmsUUID id) {
240
241        CmsDetailPageInfo info = m_infoById.get(id);
242        if (info == null) {
243            return false;
244        }
245        return m_map.get(info.getType()).get(0).getId().equals(id);
246    }
247
248    /**
249     * Changes the position of a detail page in the list of detail pages for its type.<p>
250     *
251     * @param id the page id
252     * @param newPos the position which the page should be moved to
253     *
254     * @return the original position of the detail page
255     */
256    public int move(CmsUUID id, int newPos) {
257
258        CmsDetailPageInfo info = m_infoById.get(id);
259        if (info == null) {
260            throw new IllegalArgumentException();
261        }
262        String type = info.getType();
263        List<CmsDetailPageInfo> infos = m_map.get(type);
264        int oldPos = infos.indexOf(info);
265        infos.remove(oldPos);
266        infos.add(newPos, info);
267        return oldPos;
268    }
269
270    /**
271     * Removes the detail page with the given id.<p>
272     *
273     * @param id the id of the detail page to remove
274     *
275     * @return the original position of the detail page in the list for its type
276     */
277    public int remove(CmsUUID id) {
278
279        CmsDetailPageInfo info = m_infoById.get(id);
280        if (info == null) {
281            throw new IllegalArgumentException();
282        }
283        String type = info.getType();
284        List<CmsDetailPageInfo> infos = m_map.get(type);
285        int pos = infos.indexOf(info);
286        infos.remove(pos);
287        m_infoById.remove(id);
288        return pos;
289
290    }
291
292    /**
293     * The number of configured detail pages.<p>
294     *
295     * @return the number of detail pages
296     */
297    public int size() {
298
299        return m_infoById.size();
300    }
301
302    /**
303     * Returns a flat list containing all detail pages for all types which preserves the order of detail pages from each type list.<p>
304     *
305     * @return a list of all detail page info beans
306     */
307    public List<CmsDetailPageInfo> toList() {
308
309        List<CmsDetailPageInfo> result = new ArrayList<CmsDetailPageInfo>();
310        for (String key : m_map.keySet()) {
311            for (CmsDetailPageInfo info : m_map.get(key)) {
312                result.add(info);
313            }
314        }
315        return result;
316    }
317
318}