001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2023
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028package edu.wisc.ssec.mcidasv.startupmanager.options;
029
030import static edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.EMPTY_STRING;
031import static edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.QUOTE_CHAR;
032import static edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.SET_PREFIX;
033
034import javax.swing.JCheckBox;
035import javax.swing.JComponent;
036import javax.swing.JTextField;
037
038import edu.wisc.ssec.mcidasv.startupmanager.Platform;
039import edu.wisc.ssec.mcidasv.startupmanager.StartupManager;
040import edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.OptionPlatform;
041import edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.Type;
042import edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.Visibility;
043
044public abstract class AbstractOption implements Option {
045
046    /**
047     * A unique identifier for an option. Should be the same as the 
048     * startup variable name found in the startup preference file.
049     */
050    private final String optionId;
051
052    /** 
053     * Brief description of the option. It will appear as the option's 
054     * label in the GUI.
055     */
056    private final String label;
057
058    /** @see Type */
059    private final Type optionType;
060
061    /** @see OptionPlatform */
062    private final OptionPlatform optionPlatform;
063
064    /** @see Visibility */
065    private final Visibility optionVisibility;
066
067    /**
068     * Creates an option that can hold a specified sort of data and that
069     * applies to a given platform.
070     * 
071     * @param id ID used to refer to this option.
072     * @param label Text that'll be used as the GUI label for this option
073     * @param optionType Type of data this option will represent.
074     * @param optionPlatform Platform(s) where this option is applicable.
075     * @param optionVisibility Visibility behavior of this option.
076     */
077    public AbstractOption(final String id, final String label, 
078        final Type optionType, final OptionPlatform optionPlatform, 
079        final Visibility optionVisibility) 
080    {
081        this.optionId = id;
082        this.label = label;
083        this.optionType = optionType;
084        this.optionPlatform = optionPlatform;
085        this.optionVisibility = optionVisibility;
086    }
087
088    /**
089     * Determines if the option applies to the current platform.
090     * 
091     * @return {@code true} if this option is applicable, {@code false} 
092     * otherwise.
093     */
094    protected boolean onValidPlatform() {
095        OptionPlatform platform = getOptionPlatform();
096        if (platform == OptionPlatform.ALL) {
097            return true;
098        }
099        if (platform == OptionMaster.getInstance().convertToOptionPlatform()) {
100            return true;
101        }
102        return false;
103    }
104
105    /**
106     * Tests the specified string to see if it's valid for the current 
107     * platform. Currently strings that contain {@literal "SET "} 
108     * <b>[ note the space ]</b> are considered to be Windows-only, while 
109     * strings lacking {@literal "SET "} are considered Unix-like.
110     * 
111     * @param text The string to test.
112     * 
113     * @return Whether or not the string is valid.
114     */
115    protected boolean isValidPrefFormat(final String text) {
116        assert text != null;
117        boolean hasSet = text.contains(SET_PREFIX);
118        boolean isWin = StartupManager.getInstance().getPlatform() == Platform.WINDOWS;
119        return isWin == hasSet;
120    }
121
122    /**
123     * Returns this option's type.
124     * 
125     * @return Option's type.
126     * 
127     * @see Type
128     */
129    public Type getOptionType() {
130        return optionType;
131    }
132
133    /**
134     * Returns the platform(s) to which this option applies.
135     * 
136     * @return Option's platform.
137     * 
138     * @see OptionPlatform
139     */
140    public OptionPlatform getOptionPlatform() {
141        return optionPlatform;
142    }
143
144    /**
145     * Returns whether or not this option represents a visible UI element.
146     * 
147     * @return The option's visibility.
148     * 
149     * @see Visibility
150     */
151    public Visibility getOptionVisibility() {
152        return optionVisibility;
153    }
154
155    /**
156     * Returns the ID used when referring to this option.
157     * 
158     * @return Option's ID.
159     */
160    public String getOptionId() {
161        return optionId;
162    }
163
164    /**
165     * Returns a brief description of this option. Mostly useful for 
166     * providing a GUI label.
167     * 
168     * @return Option's label.
169     */
170    public String getLabel() {
171        return label;
172    }
173
174    /**
175     * Initializes the current option using a relevant variable from the 
176     * startup script.
177     * 
178     * @param text Line from the startup script that represents the current
179     * option.
180     * 
181     * @throws IllegalArgumentException if {@code text} is not in the proper
182     * format for the current platform.
183     */
184    public void fromPrefsFormat(final String text) {
185        if (!isValidPrefFormat(text)) {
186            throw new IllegalArgumentException("Incorrect syntax for this platform: " + text);
187        }
188        String copy = new String(text);
189        if (StartupManager.getInstance().getPlatform() == Platform.WINDOWS) {
190            copy = copy.replace(SET_PREFIX, EMPTY_STRING);
191        }
192        String[] chunks = copy.split("=");
193        if (chunks.length == 2 && chunks[0].equals(optionId)) {
194            setValue(chunks[1]);
195        } else {
196            setValue(EMPTY_STRING);
197        }
198    }
199
200    /**
201     * Returns a string representation of the current option that is suitable 
202     * for use in the startup script.
203     * 
204     * @return Current value of this option as a startup script variable. The 
205     * formatting changes slightly between {@literal "Unix-like"} platforms 
206     * and Windows.
207     * 
208     * @see #isValidPrefFormat(String)
209     */
210    public String toPrefsFormat() {
211        Platform platform = StartupManager.getInstance().getPlatform();
212        StringBuilder str = new StringBuilder(optionId);
213        String value = getValue();
214        if (platform == Platform.WINDOWS) {
215            str.insert(0, SET_PREFIX);
216        }
217        str.append('=');
218        if ((platform != Platform.WINDOWS) && value.contains(" ")) {
219            str.append(QUOTE_CHAR).append(value).append(QUOTE_CHAR);
220        } else {
221            str.append(value);
222        }
223        return str.toString();
224    }
225
226    /**
227     * Returns the GUI component that represents the option. 
228     * {@link BooleanOption BooleanOptions} are represented by a
229     * {@link JCheckBox}, while {@link TextOption TextOptions} appear as a
230     * {@link JTextField}.
231     * 
232     * @return The GUI representation of this option.
233     */
234    public abstract JComponent getComponent();
235
236    /**
237     * Returns the value of the option. Note that
238     * {@link BooleanOption BooleanOptions} return either {@literal "0"} or
239     * {@literal "1"}.
240     * 
241     * @return The current value of the option.
242     */
243    public abstract String getValue();
244
245    /**
246     * Forces the value of the option to the data specified. Note that 
247     * {@link BooleanOption BooleanOptions} accept either {@literal "0"}, or
248     * {@literal "1"}.
249     * 
250     * @param value New value to use.
251     */
252    public abstract void setValue(final String value);
253
254    /**
255     * Friendly string representation of the option.
256     * 
257     * @return {@code String} containing relevant info about the option.
258     * 
259     * @see TextOption#toString()
260     * @see BooleanOption#toString()
261     */
262    public abstract String toString();
263}