001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     tdelprat
018 *
019 */
020
021package org.nuxeo.wizard.download;
022
023import java.util.ArrayList;
024import java.util.List;
025
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028
029/**
030 * @author Tiry (tdelprat@nuxeo.com)
031 * @since 5.5
032 */
033public class DownloadablePackageOptions {
034
035    protected List<DownloadablePackageOption> pkgOptions = new ArrayList<>();
036
037    protected List<DownloadPackage> pkg4Install = new ArrayList<>();
038
039    protected List<DownloadPackage> commonPackages = new ArrayList<>();
040
041    protected List<DownloadPackage> allPackages = new ArrayList<>();
042
043    protected List<Preset> presets = new ArrayList<>();
044
045    protected static final Log log = LogFactory.getLog(DownloadablePackageOptions.class);
046
047    public List<DownloadablePackageOption> getOptions() {
048        return pkgOptions;
049    }
050
051    public void addOptions(DownloadablePackageOption pkgOption) {
052        pkgOptions.add(pkgOption);
053    }
054
055    public void addCommonPackage(DownloadPackage pkg) {
056        commonPackages.add(pkg);
057    }
058
059    public int size() {
060        return getOptions().size();
061    }
062
063    public DownloadablePackageOption get(int idx) {
064        return getOptions().get(idx);
065    }
066
067    public void resetSelection() {
068        pkg4Install = new ArrayList<>();
069        for (DownloadablePackageOption option : pkgOptions) {
070            resetSelection(option);
071        }
072    }
073
074    protected void resetSelection(DownloadablePackageOption option) {
075        option.setSelected(false);
076        for (DownloadablePackageOption child : option.getChildrenPackages()) {
077            resetSelection(child);
078        }
079    }
080
081    public List<String> checkSelectionValid(List<String> ids) {
082        for (String id : ids) {
083            DownloadablePackageOption option = findById(id, pkgOptions);
084            if (option == null) {
085                List<String> newIds = new ArrayList<>();
086                newIds.addAll(ids);
087                newIds.remove(id);
088                return checkSelectionValid(newIds);
089            }
090            // force selection of parents
091            if (option.getParent() != null && !ids.contains(option.getParent().getId())) {
092                List<String> newIds = new ArrayList<>();
093                newIds.addAll(ids);
094                newIds.add(0, option.getParent().getId());
095                return checkSelectionValid(newIds);
096            }
097            // force selection of implies
098            if (option.getPackage() != null && option.getPackage().getImpliedDeps() != null) {
099                List<String> newIds = new ArrayList<>();
100                newIds.addAll(ids);
101                boolean needRecheck = false;
102                for (String implied : option.getPackage().getImpliedDeps()) {
103                    if (!ids.contains(implied)) {
104                        if (findById(id, pkgOptions) != null) {
105                            if (option.isExclusive() && option.getSiblingPackages().stream().anyMatch(
106                                    sib -> sib.getId().equals(implied))) {
107                                log.error(String.format(
108                                        "Option %s cannot be exclusive and imply one of its sibling packages", id));
109                                continue;
110                            }
111                            newIds.add(implied);
112                            needRecheck = true;
113                        }
114                    }
115                }
116                if (needRecheck) {
117                    return checkSelectionValid(newIds);
118                }
119            }
120            // check constraints
121            if (option.isExclusive()) {
122                for (DownloadablePackageOption sib : option.getSiblingPackages()) {
123                    if (ids.contains(sib.getId())) {
124                        ids.remove(option.getId());
125                        log.warn("Unsatisfied constraints in selection ... fixing");
126                        return checkSelectionValid(ids);
127                    }
128                }
129            } else {
130                for (DownloadablePackageOption sib : option.getSiblingPackages()) {
131                    if (ids.contains(sib.getId()) && sib.isExclusive()) {
132                        ids.remove(sib.getId());
133                        log.warn("Unsatisfied constraints in selection ... fixing");
134                        return checkSelectionValid(ids);
135                    }
136                }
137            }
138        }
139        return ids;
140    }
141
142    protected void markForDownload(String pkgId) {
143        for (DownloadPackage pkg : allPackages) {
144            if (pkg.getId().equals(pkgId)) {
145                markForDownload(pkg);
146                break;
147            }
148        }
149    }
150
151    protected void markForDownload(DownloadPackage pkg) {
152        if (!pkg4Install.contains(pkg)) {
153            if (pkg.getFilename() != null && !"".equals(pkg.getFilename())) {
154                for (String dep : pkg.getImpliedDeps()) {
155                    markForDownload(dep);
156                }
157            }
158            pkg4Install.add(pkg);
159        }
160    }
161
162    public void select(List<String> ids) {
163        resetSelection();
164        ids = checkSelectionValid(ids);
165        for (String id : ids) {
166            DownloadablePackageOption option = findById(id, pkgOptions);
167            option.setSelected(true);
168            DownloadPackage pkg = option.getPackage();
169            if (pkg != null) {
170                markForDownload(pkg);
171            }
172        }
173    }
174
175    protected DownloadablePackageOption findById(String id, List<DownloadablePackageOption> options) {
176        for (DownloadablePackageOption option : options) {
177            if (option.getId().equals(id)) {
178                return option;
179            }
180            DownloadablePackageOption childOption = findById(id, option.getChildrenPackages());
181            if (childOption != null) {
182                return childOption;
183            }
184        }
185        return null;
186    }
187
188    public List<DownloadPackage> getPkg4Install() {
189        List<DownloadPackage> pkgs = new ArrayList<>(commonPackages);
190        pkgs.addAll(pkg4Install);
191        return pkgs;
192    }
193
194    protected void asJson(DownloadablePackageOption option, StringBuffer sb) {
195        sb.append("{");
196        sb.append("\"id\":\"" + option.id + "\",");
197        sb.append("\"package\":\"" + option.getPackage().getId() + "\",");
198        sb.append("\"color\":\"" + option.getColor() + "\",");
199        sb.append("\"textcolor\":\"" + option.getTextColor() + "\",");
200        sb.append("\"label\":\"" + option.getLabel() + "\",");
201        sb.append("\"shortlabel\":\"" + option.getShortLabel() + "\",");
202        sb.append("\"selected\":\"" + option.selected + "\",");
203        sb.append("\"exclusive\":\"" + option.exclusive + "\",");
204        sb.append("\"description\":\"" + option.getDescription() + "\",");
205        sb.append("\"virtual\":\"" + option.isVirtual() + "\",");
206        sb.append("\"implies\": [");
207        for (int i = 0; i < option.getPackage().getImpliedDeps().size(); i++) {
208            sb.append("\"" + option.getPackage().getImpliedDeps().get(i).trim() + "\"");
209            if (i < option.getPackage().getImpliedDeps().size() - 1) {
210                sb.append(", ");
211            }
212        }
213        sb.append("],");
214        sb.append("\"children\": [");
215        List<DownloadablePackageOption> children = option.getChildrenPackages();
216        for (int i = 0; i < children.size(); i++) {
217            if (i > 0) {
218                sb.append(",");
219            }
220            asJson(children.get(i), sb);
221        }
222        sb.append("] }");
223    }
224
225    protected DownloadablePackageOption getSelectedRoot() {
226        for (DownloadablePackageOption option : pkgOptions) {
227            if (option.isSelected()) {
228                return option;
229            }
230        }
231        return pkgOptions.get(0);
232    }
233
234    public String asJson() {
235        StringBuffer sb = new StringBuffer();
236        asJson(getSelectedRoot(), sb);
237        return sb.toString();
238    }
239
240    void addPreset(String id, String label, String[] pkgIds) {
241        presets.add(new Preset(id, label, pkgIds));
242    }
243
244    public List<Preset> getPresets() {
245        return presets;
246    }
247
248    public List<DownloadPackage> getAllPackages() {
249        return allPackages;
250    }
251
252    public void setAllPackages(List<DownloadPackage> allPackages) {
253        this.allPackages = allPackages;
254    }
255
256}