package CH.ifa.draw.util;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import de.renew.draw.ui.api.ApplicationApi;


/**
 * This helper class contains static functions which
 * can be queried for a default behaviour of some GUI
 * elements.
 * <p>
 * GUIProperties.java
 * Created: Wed Mar  7  2001
 * @author Michael Duvigneau
 * @deprecated This method is only for internal usage and will later be made private.
 */
@Deprecated
public class GUIProperties {
    /**
     * Logger for the class GUIProperties.
     * Only a single logger instance exists at any given time. If a logger for GUIProperties
     * already exists it is returned or else a new instance is created.
     */
    public static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(GUIProperties.class);
    private static Properties _properties = new Properties();
    private static final Map<String, Boolean> LAST_BOOL_RESULTS = new HashMap<>();

    /** This class cannot be instantiated. **/
    private GUIProperties() {}

    /**
     * Sets behavior of a set of GUI elements via their properties.
     *
     * @param props the properties to set the gui to
     * @deprecated This method is not to be used externally. Please use the method {@link de.renew.draw.ui.api.ApplicationApi#setDrawProperties(Properties)} instead.
     */
    @Deprecated
    public static void setProperties(Properties props) {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("setting GUI properties:" + props, new Throwable("StackTrace"));
        }
        _properties = props;
    }

    /**
     * Gets the properties of the GUI.
     *
     * @return the current properties of the GUI
     * @deprecated This method is only for internal usage and will later be made private.
     */
    @Deprecated
    public static Properties getProperties() {
        return _properties;
    }

    /**
     * Retrieves the value of the given property and converts its value to boolean.
     * If the property is not found in this class' properties, attempts to retrieve it from
     * the system properties and if found adds them to the list of properties held by this class.
     *
     * @param property the of the property to retrieve
     * @param setMessage message to log before the value of the property is returned
     * @return the value of the property converted to boolean
     */
    protected static boolean returnBool(String property, String setMessage) {
        String propName = "de.renew." + property;
        String result = _properties.getProperty(propName);
        if (result == null) {
            result = System.getProperty(propName);
            if (result != null) {
                _properties.setProperty(property, result);
            }
        }
        if (result == null) {
            result = "false";
            _properties.setProperty(property, result);
        } else if (result.isEmpty()) {
            result = "true";
            _properties.setProperty(property, result);
        }
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("evaluated GUI property: " + propName + "=" + result);
        }
        boolean value = Boolean.parseBoolean(result);
        printOptionalSetMessage(propName, value, setMessage);
        return value;
    }

    /**
     * Logs information about a property, with its name and value as well as a custom message.
     *
     * @param propName the name of the property
     * @param newValue the value of the property
     * @param setMessage the message, which will be logged
     */
    protected static void printOptionalSetMessage(
        String propName, Boolean newValue, String setMessage)
    {
        Boolean prevValue = LAST_BOOL_RESULTS.get(propName);
        if (prevValue == null) {
            prevValue = Boolean.FALSE;
        }
        LAST_BOOL_RESULTS.put(propName, newValue);
        if (!prevValue && newValue && setMessage != null) {
            LOGGER.debug(setMessage + " activated.");
        } else if (prevValue && !newValue && setMessage != null) {
            LOGGER.debug(setMessage + " deactivated.");
        }
    }

    /**
     * Gets the value as int of the specified property.
     *
     * @param property the property name to retrieve
     * @return the value as int of the property,<br>
     *         <code>-1</code> if no value to the corresponding property was found
     */
    protected static int returnInt(String property) {
        return returnInt(property, -1);
    }

    /**
     * Gets the value as int of the specified property. A default value has to be
     * given in case the value corresponding to the property wasn't found.
     *
     * @param property the property name to retrieve
     * @param default_ the default value if no corresponding value to property was found
     * @return the value as int of the property or the default value if property wasn't found
     */
    protected static int returnInt(String property, int default_) {
        String value = returnString(property);
        int result = default_;

        if (!value.equals("none")) {
            result = Integer.parseInt(value);
        }
        return result;
    }

    /**
     * Gets the value as String of the specified property. If the property is not found
     * in Renew's properties, attempts to retrieve it from the system properties and if
     * found adds them to the list of properties held by this class.
     *
     * @param property the property name to retrieve
     * @return the string value of the property or<br>
     *         <code>"none"</code> if not found
     */
    protected static String returnString(String property) {
        String propName = "de.renew." + property;
        String result = _properties.getProperty(propName);

        if (result == null) {
            result = System.getProperty(propName);
            if (result != null) {
                _properties.setProperty(property, result);
            }
        }

        if (result == null) {
            result = "none";
        }
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("evaluated GUI property: " + propName + "=" + result);
        }
        return result;
    }

    /**
     * Interprets the value of a system property to determine
     * if frames may be positioned or sized. This function should
     * be queried before each call to <code>setSize()</code>,
     * <code>setLocation()</code> or <code>setBounds()</code> of an
     * instance of <code>java.awt.Window</code>. Subsequent calls to
     * <code>pack()</code> or <code>setVisible(true)</code> should
     * also be avoided, if this function returns <code>true</code>.
     * <DL>
     * <DT><b>System property:</b></DT>
     * <DD><code>de.renew.avoidFrameReshape</code>
     * </DD>
     * <DT><b>Influences:</b></DT>
     * <DD>Program-controlled positioning and sizing of AWT windows.
     * </DD>
     * <DT><b>Valid values:</b></DT>
     * <DD><DL><DT><code>false</code> (default):</DT>
     *     <DD>All windows will be positioned and sized at our needs.
     *     </DD>
     *     <DT><code>true</code>:</DT>
     *     <DD>Sacrifices the comfort of perfectly positioned windows
     *         to get windows that display their contents correctly.
     *         <br>
     *         This may be needed if under some circumstances (JDK1.3
     *         and twm, for example) the default behaviour will lead to
     *         "jumping" windows or windows with hidden areas.
     *     </DD></DL>
     * </DD></DL>
     *
     * @return <code>true</code> if frames may be positioned and resized by user
     *  @deprecated This method is not to be used externally. Please use the method {@link ApplicationApi#isAvoidFrameReshape()} instead.
     **/
    @Deprecated
    public static boolean avoidFrameReshape() {
        return returnBool("avoidFrameReshape", "Frame reshaping");
    }

    /**
     * Interprets the value of a system property to determine
     * if a drawing load server should be started.
     * This function returns a positive integer value that
     * specifies the port, if the property is set.
     * It returns <code>-1</code>, if no load server should
     * be started.
     * <DL>
     * <DT><b>System property:</b></DT>
     * <DD><code>de.renew.loadServerPort</code>
     * </DD>
     * <DT><b>Influences:</b></DT>
     * <DD>Setup of a drawing load server.
     * </DD>
     * <DT><b>Valid values:</b></DT>
     * <DD><DL><DT>&lt;not set&gt;:</DT>
     *     <DD>A drawing load server will be started at port 65111
     *     </DD>
     *     <DT>-1:</DT>
     *     <DD>No drawing load server will be started.
     *     </DD>
     *     <DT>positive integer:</DT>
     *     <DD>A drawing load server will be started.
     *         The integer value is interpreted as the port number
     *         where the server will listen for requests.
     *     </DD></DL>
     * </DD></DL>
     *
     * @return <code>-1</code> if no drawing load server should be started or a<br>
     *         <code>positive integer</code>, which will be interpreted as the port number
     * @deprecated This method is only for internal usage and will later be made private.
     **/
    @Deprecated
    public static int loadServerPort() {
        return returnInt("loadServerPort", 65111);
    }

    /**
     * Interprets the value of a system property to determine
     * the font size for the application menus.
     * This function returns a positive integer value that
     * specifies the font size, if the property is set.
     * It returns <code>-1</code>, if the default size should
     * be used.
     * <DL>
     * <DT><b>System property:</b></DT>
     * <DD><code>de.renew.menuFontSize</code>
     * </DD>
     * <DT><b>Influences:</b></DT>
     * <DD>Application menu font size.
     * </DD>
     * <DT><b>Valid values:</b></DT>
     * <DD><DL><DT>&lt;not set&gt; (default):</DT>
     *     <DD>The AWT-default font size will be used.
     *     </DD>
     *     <DT>positive integer:</DT>
     *     <DD>The integer value is interpreted as a font size
     *         to be used for menus.
     *     </DD></DL>
     * </DD></DL>
     *
     * @return <code>-1</code> if property is not set. AWT (abstract tool window) font size will be used
     *         as default. Or a positive <code>int</code> if property is set.
     * @deprecated This method is currently not used and will be removed in a later version.
     **/
    @Deprecated
    public static int menuFontSize() {
        return returnInt("menuFontSize");
    }

    /**
     * Interprets the value of a system property to determine
     * if the main menu frame should be resizable.
     * <p>
     * <b>This property is no longer in use!</b>
     * The menu frame is resizable on all platforms since the
     * toolbars can be rearranged to fit the frame.
     * </p>
     * <DL>
     * <DT><b>System property:</b></DT>
     * <DD><code>de.renew.windowResizable</code>
     * </DD>
     * <DT><b>Influences:</b></DT>
     * <DD>Resizability of the menu frame.
     * </DD>
     * <DT><b>Valid values:</b></DT>
     * <DD><DL><DT><code>true</code> (default on platform Windows):</DT>
     *     <DD>The menu frame will be resizable.
     *         This is needed on the Windows platform because the size
     *         of the menu frame does not match the size of its contents.
     *     </DD>
     *     <DT><code>false</code> (default on other platforms):</DT>
     *     <DD>The menu frame has a fixed size.
     *     </DD></DL>
     * </DD></DL>
     *
     * @return <code>true</code> if menu frame is resizable
     * @deprecated This method is currently not used and will be removed in a later version.
     **/
    @Deprecated
    public static boolean windowResizable() {
        String result = _properties.getProperty("de.renew.windowResizable");
        if (result == null) {
            result = System.getProperty("de.renew.windowResizable");
            if (result != null) {
                _properties.setProperty("de.renew.windowResizable", result);
            }
        }
        if (result == null) {
            // If no parameter is given, the window is
            // resizable on Windows-Systems only.
            if (System.getProperty("os.name").contains("Win")) {
                result = "true";
                _properties.setProperty("de.renew.windowResizable", result);
            }
        } else if (result.isEmpty()) {
            result = "true";
            _properties.setProperty("de.renew.windowResizable", result);
        }
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("evaluated GUI property: de.renew.windowResizable=" + result);
        }
        boolean value = Boolean.parseBoolean(result);
        printOptionalSetMessage("de.renew.windowResizable", value, "Menu frame resizability");
        return value;
    }

    /**
     * Interprets the value of a system property to determine
     * the font size for new text figures.
     * This function returns a positive integer value that
     * specifies the font size, if the property is set.
     * It returns <code>-1</code>, if the default size should
     * be used.
     * <DL>
     * <DT><b>System property:</b></DT>
     * <DD><code>de.renew.defaultFontSize</code>
     * </DD>
     * <DT><b>Influences:</b></DT>
     * <DD>Default font size for new text figures.
     * </DD>
     * <DT><b>Valid values:</b></DT>
     * <DD><DL><DT>&lt;not set&gt; (default):</DT>
     *     <DD>The AWT-default font size will be used..
     *     </DD>
     *     <DT>positive integer:</DT>
     *     <DD>The integer value is interpreted as a font size
     *         to be used for new text figures.
     *     </DD></DL>
     * </DD></DL>
     *
     * @return the default fontsize
     * @deprecated This method is only for internal usage and will later be made private.
     **/
    @Deprecated
    public static int defaultFontSize() {
        return returnInt("defaultFontSize");
    }

    /**
     * Interprets the value of a system property to determine if toolbar
     * buttons should be painted with self-made shadow borders. If the
     * property is set to false (default), default Swing borders are used.
     * <DL>
     * <DT><b>System property:</b></DT>
     * <DD><code>de.renew.customToolBorders</code>
     * </DD>
     * <DT><b>Influences:</b></DT>
     * <DD>Appearance of toolbar buttons.
     * </DD>
     * <DT><b>Valid values:</b></DT>
     * <DD><DL><DT><code>false</code> (default):</DT>
     *     <DD>Default Swing borders around each button.
     *     </DD>
     *     <DT><code>true</code>:</DT>
     *     <DD>Shadow borders that mimic the old Renew tool button style.
     *     </DD></DL>
     * </DD></DL>
     *
     * @return <code>true</code> if the borders of buttons mimic the old Renew button style
     * @deprecated This method is currently not used and will be removed in a later version.
     **/
    @Deprecated
    public static boolean customToolBorders() {
        return returnBool("customToolBorders", "Drawing old-style Renew tool buttons.");
    }

    /**
     * Interprets the value of a system property to determine
     * whether graphics will be in use when loading a drawing.
     * <DL>
     * <DT><b>System property:</b></DT>
     * <DD><code>de.renew.noGraphics</code>
     * </DD>
     * <DT><b>Influences:</b></DT>
     * <DD>Graphics update when a drawing is loaded.
     * </DD>
     * <DT><b>Valid values:</b></DT>
     * <DD><DL><DT>&lt;not set&gt; (default):</DT>
     *     <DD>The display of figures will be updated on load.
     *     </DD>
     *     <DT>set:</DT>
     *     <DD>The display won't be actualized. This allows
     *         a programmer to load a drawing without starting
     *         the GUI. But it will cause exceptions if you
     *         try to draw the figures in this mode.
     *     </DD></DL>
     * </DD></DL>
     *
     * @return <code>true</code> if a drawing will be loaded without graphics
     *  @deprecated This method is not to be used externally. Please use the method {@link ApplicationApi#isNoGraphics()} instead.
     **/
    @Deprecated
    public static boolean noGraphics() {
        return returnBool("noGraphics", null);
    }

    /**
     * Returns the default font-name.
     *
     * @return the default name of the font but if there is no default name
     * <code>"SansSerif"</code> is returned
     * @deprecated This method is only for internal usage and will later be made private.
     */
    @Deprecated
    public static String defaultFontName() {
        String result = returnString("defaultFontName");
        if (result.equals("none")) {
            result = "SansSerif";
        }
        return result;
    }
}