/*
 * jNPad v0.3 - jNPad's an Simple Text Editor written in Java
 *
 * Copyright (C) 2014-2017  rgs
 *
 * Require JDK 1.6 (or later)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 *
 * Info, Questions, Suggestions & Bugs Report to rgsevero@gmail.com
 */

package jnpad.config;

import static jnpad.util.Utilities.COMMA_STRING;
import static jnpad.util.Utilities.DIR_SEPARATOR;
import static jnpad.util.Utilities.EMPTY_STRING;

import java.awt.Color;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;

import jnpad.GUIUtilities;
import jnpad.JNPad;
import jnpad.JNPadInput;
import jnpad.ui.Orientable;
import jnpad.ui.plaf.LAFUtils;
import jnpad.util.Platform;
import jnpad.util.Utilities;

/**
 * The Class Config.
 *
 * @version 0.3
 * @since   jNPad v0.1
 */
@SuppressWarnings("nls")
public final class Config {
  /** The Constant PROPERTIES_FILE_PATH. */
  public static final String              PROPERTIES_FILE_PATH                 = JNPad.PROPS_DIR + DIR_SEPARATOR + "jnpad.properties";

  /** The Constant DEFAULTS_FILE_PATH. */
  public static final String              DEFAULTS_FILE_PATH                   = JNPad.PROPS_DIR + DIR_SEPARATOR + "jnpad.defaults.properties";

  // --- search ---
  /** The Constant SEARCH_FILE_PATH. */
  public static final String              SEARCH_FILE_PATH                     = JNPad.PROPS_DIR + DIR_SEPARATOR + "search.properties";

  /** The find list. */
  private static List<String>             findList                             = new ArrayList<String>();

  /** The replace list. */
  private static List<String>             replaceList                          = new ArrayList<String>();
  // ---

  /** The Constant COLORSCHEMES_DIR. */
  public static final String              COLORSCHEMES_DIR                     = JNPad.PROPS_DIR + DIR_SEPARATOR + "colors";

  /** The Constant KEYMAP_DIR. */
  public static final String              KEYMAP_DIR                           = JNPad.PROPS_DIR + DIR_SEPARATOR + "keymaps";

  /** The locale. */
  private static Locale                   locale;

  /** The home dir. */
  private static String                   homeDir                              = System.getProperty("user.dir", EMPTY_STRING);

  /** The options. */
  private static Properties               options;

  /** The defaults. */
  private static Properties               defaults;

  /** The changes. */
  private static Properties               changes;

  /** The removes. */
  private static List<String>             removes                              = new ArrayList<String>();

  /** The Constant AUTO. */
  public static final String              AUTO                                 = "auto";

  // ===========================================================================
  /** The Constant JNPAD_X. */
  public static final IntProp             JNPAD_X                              = new IntProp("jnpad.x", Integer.MIN_VALUE);

  /** The Constant JNPAD_Y. */
  public static final IntProp             JNPAD_Y                              = new IntProp("jnpad.y", Integer.MIN_VALUE);

  /** The Constant JNPAD_WIDTH. */
  public static final IntProp             JNPAD_WIDTH                          = new IntProp("jnpad.width", 740); // [changed 0.3] prev. 700

  /** The Constant JNPAD_HEIGHT. */
  public static final IntProp             JNPAD_HEIGHT                         = new IntProp("jnpad.height", 576); // [changed 0.3] prev. 400

  /** The Constant JNPAD_MAXIMIZE. */
  public static final BooleanProp         JNPAD_MAXIMIZE                       = new BooleanProp("jnpad.maximize", false);

  /** The Constant JNPAD_COLORSCHEME. */
  public static final StringProp          JNPAD_COLORSCHEME                    = new StringProp("jnpad.colorscheme", "default");

  /** The Constant JNPAD_KEYMAP. */
  public static final StringProp          JNPAD_KEYMAP                         = new StringProp("jnpad.keymap", "jnpad-default");

  /** The Constant JNPAD_LAF. */
  public static final StringProp          JNPAD_LAF                            = new StringProp("jnpad.laf", LAFUtils.LAF_KEY_NATIVE);

  /** The Constant JNPAD_LAF_BOLD_METAL. */
  public static final BooleanProp         JNPAD_LAF_BOLD_METAL                 = new BooleanProp("jnpad.laf.boldMetal", false);

  /** The Constant JNPAD_LANG. */
  public static final StringProp          JNPAD_LANG                           = new StringProp("jnpad.lang", AUTO);

  /** The Constant JNPAD_MODE. */
  public static final ModeProp            JNPAD_MODE                           = new ModeProp("jnpad.mode", Mode.DEFAULT);

  /** The mode. */
  private static Mode                     mode;

  /** The mode_setting_flag. */
  private static boolean                  mode_setting_flag;

  /** The Constant JNPAD_ANTIALIAS. */
  public static final BooleanProp         JNPAD_ANTIALIAS                      = new BooleanProp2("jnpad.antialias", false);
  // ===========================================================================

  // ===========================================================================
  /** The Constant TOOLBARS_FILE_SELECTED. */
  public static final BooleanProp         TOOLBARS_FILE_SELECTED               = new BooleanProp("toolbars.file.selected", true);

  /** The Constant TOOLBARS_EDIT_RECANTATION_SELECTED. */
  public static final BooleanProp         TOOLBARS_EDIT_RECANTATION_SELECTED   = new BooleanProp("toolbars.edit.recantation.selected", true);

  /** The Constant TOOLBARS_EDIT_CLIPBOARD_SELECTED. */
  public static final BooleanProp         TOOLBARS_EDIT_CLIPBOARD_SELECTED     = new BooleanProp("toolbars.edit.clipboard.selected", true);

  /** The Constant TOOLBARS_EDIT_SELECTION_SELECTED. */
  public static final BooleanProp         TOOLBARS_EDIT_SELECTION_SELECTED     = new BooleanProp("toolbars.edit.selection.selected", true);

  /** The Constant TOOLBARS_EDIT_DELETION_SELECTED. */
  public static final BooleanProp         TOOLBARS_EDIT_DELETION_SELECTED      = new BooleanProp("toolbars.edit.deletion.selected", true);

  /** The Constant TOOLBARS_SEARCH_SELECTED. */
  public static final BooleanProp         TOOLBARS_SEARCH_SELECTED             = new BooleanProp("toolbars.search.selected", true);

  /** The Constant TOOLBARS_VIEW_SELECTED. */
  public static final BooleanProp         TOOLBARS_VIEW_SELECTED               = new BooleanProp("toolbars.view.selected", true);

  /** The Constant TOOLBARS_FORMAT_SELECTED. */
  public static final BooleanProp         TOOLBARS_FORMAT_SELECTED             = new BooleanProp("toolbars.format.selected", true);

  /** The Constant TOOLBARS_WINDOWS_SELECTED. */
  public static final BooleanProp         TOOLBARS_WINDOWS_SELECTED            = new BooleanProp("toolbars.window.selected", true);
  // ===========================================================================

  // ===========================================================================
  /** The Constant TITLED_LABEL_FONT. */
  public static final FontProp            TITLED_LABEL_FONT                    = new FontProp("titled.label.font", new Font("Dialog", Font.BOLD, 11));

  /** The Constant TITLED_LABEL_FOREGROUND. */
  public static final ColorProp           TITLED_LABEL_FOREGROUND              = new ColorProp("titled.label.foreground", Color.WHITE);

  /** The Constant TITLED_LABEL_GRADIENT1. */
  public static final ColorProp           TITLED_LABEL_GRADIENT1               = new ColorProp("titled.label.gradient1", new Color(0, 0, 205));

  /** The Constant TITLED_LABEL_GRADIENT2. */
  public static final ColorProp           TITLED_LABEL_GRADIENT2               = new ColorProp("titled.label.gradient2", Color.BLUE);

  /** The Constant TITLED_LABEL_ORIENTATION. */
  public static final IntProp             TITLED_LABEL_ORIENTATION             = new IntProp("titled.label.orientation", Orientable.ORIENTATION_HORIZONTAL);
  // ===========================================================================

  // ===========================================================================
  /** The Constant TEXT_FONT. */
  public static final FontProp            TEXT_FONT;

  /** The Constant TEXT_BACKGROUND. */
  public static final ColorProp           TEXT_BACKGROUND                      = new ColorProp("text.background", Color.WHITE);

  /** The Constant TEXT_FOREGROUND. */
  public static final ColorProp           TEXT_FOREGROUND                      = new ColorProp("text.foreground", Color.BLACK);

  /** The Constant TEXT_SELECTION_BACKGROUND. */
  public static final ColorProp           TEXT_SELECTION_BACKGROUND            = new ColorProp("text.selection.background", new Color(49, 106, 197));

  /** The Constant TEXT_SELECTION_FOREGROUND. */
  public static final ColorProp           TEXT_SELECTION_FOREGROUND            = new ColorProp("text.selection.foreground", Color.WHITE);

  /** The Constant TEXT_CARET_INS_COLOR. */
  public static final ColorProp           TEXT_CARET_INS_COLOR                 = new ColorProp("text.caret.ins.color", Color.BLACK);

  /** The Constant TEXT_CARET_OVR_COLOR. */
  public static final ColorProp           TEXT_CARET_OVR_COLOR                 = new ColorProp("text.caret.ovr.color", new Color(0, 0, 128));

  /** The Constant TEXT_TAB_SIZE. */
  public static final IntProp             TEXT_TAB_SIZE                        = new IntProp("text.tab.size", 4);

  /** The Constant TEXT_TAB_ENABLED. */
  public static final BooleanProp         TEXT_TAB_ENABLED                     = new BooleanProp("text.tab.enabled", true);

  /** The Constant TEXT_AUTO_INDENT. */
  public static final BooleanProp         TEXT_AUTO_INDENT                     = new BooleanProp("text.auto.indent", true);

  /** The Constant TEXT_AUTO_CLOSE_BRACKETS. */
  public static final BooleanProp         TEXT_AUTO_CLOSE_BRACKETS             = new BooleanProp("text.auto.close.brackets", true);

  /** The Constant TEXT_RIGHT_MARGIN_LINE_VISIBLE. */
  public static final BooleanProp         TEXT_RIGHT_MARGIN_LINE_VISIBLE       = new BooleanProp("text.right.margin.line.visible", false);

  /** The Constant TEXT_RIGHT_MARGIN_LINE_WIDTH. */
  public static final IntProp             TEXT_RIGHT_MARGIN_LINE_WIDTH         = new IntProp("text.right.margin.line.width", 80);

  /** The Constant TEXT_RIGHT_MARGIN_LINE_COLOR. */
  public static final ColorProp           TEXT_RIGHT_MARGIN_LINE_COLOR         = new ColorProp("text.right.margin.line.color", new Color(192, 192, 192, 100));

  /** The Constant TEXT_LINE_WRAP. */
  public static final BooleanProp         TEXT_LINE_WRAP                       = new BooleanProp("text.line.wrap", false);

  /** The Constant TEXT_AUTOCOMPLETION_ENABLED. */
  public static final BooleanProp         TEXT_AUTOCOMPLETION_ENABLED          = new BooleanProp("text.autocompletion.enabled", false);                                           //true;

  /** The Constant TEXT_AUTOCOMPLETION_ALL. */
  public static final BooleanProp         TEXT_AUTOCOMPLETION_ALL              = new BooleanProp("text.autocompletion.all", false);

  /** The Constant TEXT_AUTOCOMPLETION_TRIGGER. */
  public static final IntProp             TEXT_AUTOCOMPLETION_TRIGGER          = new IntProp("text.autocompletion.trigger", 4);

  /** The Constant TEXT_DELIMITERS. */
  public static final StringProp          TEXT_DELIMITERS                      = new StringProp("text.delimiters", "!@%^&*()-=+[]{};:'\",.<>/?");
  // ===========================================================================

  // ===========================================================================
  /** The Constant SYNTAX_CLASSIFY_ENABLED. */
  public static final BooleanProp         SYNTAX_CLASSIFY_ENABLED              = new BooleanProp("syntax.classify.enabled", true);

  /** The Constant SYNTAX_KNOWN_ENABLED. */
  public static final BooleanProp         SYNTAX_KNOWN_ENABLED                 = new BooleanProp("syntax.known.enabled", true);

  /** The Constant SYNTAX_COMMENT_COLOR. */
  public static final ColorProp           SYNTAX_COMMENT_COLOR                 = new ColorProp("syntax.comment.color", new Color(0, 128, 0));

  /** The Constant SYNTAX_COMMENT_STYLE. */
  public static final IntProp             SYNTAX_COMMENT_STYLE                 = new IntProp("syntax.comment.style", 2);

  /** The Constant SYNTAX_COMMENT1_COLOR. (ej. javadoc) */
  public static final ColorProp           SYNTAX_COMMENT1_COLOR                = new ColorProp("syntax.comment1.color", new Color(0, 128, 64));                               // [added v0.3]

  /** The Constant SYNTAX_COMMENT1_STYLE. (ej. javadoc) */
  public static final IntProp             SYNTAX_COMMENT1_STYLE                = new IntProp("syntax.comment1.style", 0);                                                     // [added v0.3]

  /** The Constant SYNTAX_COMMENT2_COLOR. (ej. javadoc tags) */
  public static final ColorProp           SYNTAX_COMMENT2_COLOR                = new ColorProp("syntax.comment2.color", new Color(0, 128, 64));

  /** The Constant SYNTAX_COMMENT2_STYLE. (ej. javadoc tags) */
  public static final IntProp             SYNTAX_COMMENT2_STYLE                = new IntProp("syntax.comment2.style", 1);

  /** The Constant SYNTAX_COMMENT3_COLOR. (ej. java annotation) */
  public static final ColorProp           SYNTAX_COMMENT3_COLOR                = new ColorProp("syntax.comment3.color", new Color(128, 128, 128));

  /** The Constant SYNTAX_COMMENT3_STYLE. (ej. java annotation) */
  public static final IntProp             SYNTAX_COMMENT3_STYLE                = new IntProp("syntax.comment3.style", 0);

  /** The Constant SYNTAX_COMMENT4_COLOR. (ej. javadoc param) */
  public static final ColorProp           SYNTAX_COMMENT4_COLOR                = new ColorProp("syntax.comment4.color", new Color(0, 128, 64));

  /** The Constant SYNTAX_COMMENT4_STYLE. (ej. javadoc param) */
  public static final IntProp             SYNTAX_COMMENT4_STYLE                = new IntProp("syntax.comment4.style", 2);

  /** The Constant SYNTAX_STRING_COLOR. */
  public static final ColorProp           SYNTAX_STRING_COLOR                  = new ColorProp("syntax.string.color", new Color(75, 0, 130));

  /** The Constant SYNTAX_STRING_STYLE. */
  public static final IntProp             SYNTAX_STRING_STYLE                  = new IntProp("syntax.string.style", 0);

  /** The Constant SYNTAX_NUMBER_COLOR. */
  public static final ColorProp           SYNTAX_NUMBER_COLOR                  = new ColorProp("syntax.number.color", new Color(51, 102, 255));

  /** The Constant SYNTAX_KEYWORD_COLOR. */
  public static final ColorProp           SYNTAX_KEYWORD_COLOR                 = new ColorProp("syntax.keyword.color", new Color(0, 0, 139));

  /** The Constant SYNTAX_KEYWORD_STYLE. */
  public static final IntProp             SYNTAX_KEYWORD_STYLE                 = new IntProp("syntax.keyword.style", 1);

  /** The Constant SYNTAX_KEYWORD2_COLOR. (ej. java modifier's keywords) */
  public static final ColorProp           SYNTAX_KEYWORD2_COLOR                = new ColorProp("syntax.keyword2.color", new Color(0, 0, 255));

  /** The Constant SYNTAX_KEYWORD2_STYLE. (ej. java modifier's keywords) */
  public static final IntProp             SYNTAX_KEYWORD2_STYLE                = new IntProp("syntax.keyword2.style", 1);

  /** The Constant SYNTAX_KEYWORD3_COLOR. (ej. java exception's keywords) */
  public static final ColorProp           SYNTAX_KEYWORD3_COLOR                = new ColorProp("syntax.keyword3.color", new Color(51, 102, 255));

  /** The Constant SYNTAX_KEYWORD3_STYLE. (ej. java exception's keywords) */
  public static final IntProp             SYNTAX_KEYWORD3_STYLE                = new IntProp("syntax.keyword3.style", 1);

  /** The Constant SYNTAX_KEYWORD4_COLOR. (ej. java flow control's keywords) */
  public static final ColorProp           SYNTAX_KEYWORD4_COLOR                = new ColorProp("syntax.keyword4.color", new Color(0, 0, 255));

  /** The Constant SYNTAX_KEYWORD4_STYLE. (ej. java flow control's keywords) */
  public static final IntProp             SYNTAX_KEYWORD4_STYLE                = new IntProp("syntax.keyword4.style", 0);

  /** The Constant SYNTAX_KEYWORD5_COLOR. (ej. java data type's keywords) */
  public static final ColorProp           SYNTAX_KEYWORD5_COLOR                = new ColorProp("syntax.keyword5.color", new Color(0, 0, 205));

  /** The Constant SYNTAX_KEYWORD5_STYLE. (ej. java data type's keywords) */
  public static final IntProp             SYNTAX_KEYWORD5_STYLE                = new IntProp("syntax.keyword5.style", 1);

  /** The Constant SYNTAX_KEYWORD6_COLOR. (ej. java data value's keywords) */
  public static final ColorProp           SYNTAX_KEYWORD6_COLOR                = new ColorProp("syntax.keyword6.color", new Color(0, 0, 205));

  /** The Constant SYNTAX_KEYWORD6_STYLE. (ej. java data value's keywords) */
  public static final IntProp             SYNTAX_KEYWORD6_STYLE                = new IntProp("syntax.keyword6.style", 0);

  /** The Constant SYNTAX_KEYWORD7_COLOR. (ej. java operator's keywords) */
  public static final ColorProp           SYNTAX_KEYWORD7_COLOR                = new ColorProp("syntax.keyword7.color", new Color(208, 0, 0));

  /** The Constant SYNTAX_KEYWORD7_STYLE. (ej. java operator's keywords) */
  public static final IntProp             SYNTAX_KEYWORD7_STYLE                = new IntProp("syntax.keyword7.style", 1);

  /** The Constant SYNTAX_KEYWORD8_COLOR. (ej. java popular classes) */
  public static final ColorProp           SYNTAX_KEYWORD8_COLOR                = new ColorProp("syntax.keyword8.color", new Color(0, 0, 128));

  /** The Constant SYNTAX_KEYWORD8_STYLE. (ej. java popular classes) */
  public static final IntProp             SYNTAX_KEYWORD8_STYLE                = new IntProp("syntax.keyword8.style", 0);

  /** The Constant SYNTAX_KEYWORD9_COLOR. (ej. reserved) */
  public static final ColorProp           SYNTAX_KEYWORD9_COLOR                = new ColorProp("syntax.keyword9.color", new Color(64, 64, 139));

  /** The Constant SYNTAX_KEYWORD9_STYLE. (ej. reserved) */
  public static final IntProp             SYNTAX_KEYWORD9_STYLE                = new IntProp("syntax.keyword9.style", 1);

  /** The Constant SYNTAX_CLASSIFY2_ENABLED. */
  public static final BooleanProp         SYNTAX_CLASSIFY2_ENABLED             = new BooleanProp("syntax.classify2.enabled", false);                                              // [v0.3]

  /** The Constant SYNTAX_KEYWORD10_COLOR. (ej. java classes) */
  public static final ColorProp           SYNTAX_KEYWORD10_COLOR               = new ColorProp("syntax.keyword10.color", new Color(0, 0, 128));                                   // [v0.3]

  /** The Constant SYNTAX_KEYWORD10_STYLE. (ej. java classes) */
  public static final IntProp             SYNTAX_KEYWORD10_STYLE               = new IntProp("syntax.keyword10.style", 0);                                                        // [v0.3]

  /** The Constant SYNTAX_KEYWORD11_COLOR. (ej. java constants) */
  public static final ColorProp           SYNTAX_KEYWORD11_COLOR               = new ColorProp("syntax.keyword11.color", new Color(0, 0, 128));                                   // [v0.3]

  /** The Constant SYNTAX_KEYWORD11_STYLE. (ej. java constants) */
  public static final IntProp             SYNTAX_KEYWORD11_STYLE               = new IntProp("syntax.keyword11.style", 0);                                                        // [v0.3]

  /** The Constant SYNTAX_OPERATOR_COLOR. */
  public static final ColorProp           SYNTAX_OPERATOR_COLOR                = new ColorProp("syntax.operator.color", new Color(208, 0, 0));

  /** The Constant SYNTAX_OPERATOR_STYLE. */
  public static final IntProp             SYNTAX_OPERATOR_STYLE                = new IntProp("syntax.operator.style", 0);

  /** The Constant SYNTAX_BRACKET_COLOR. */
  public static final ColorProp           SYNTAX_BRACKET_COLOR                 = new ColorProp("syntax.bracket.color", new Color(153, 17, 17));

  /** The Constant SYNTAX_BRACKET_STYLE. */
  public static final IntProp             SYNTAX_BRACKET_STYLE                 = new IntProp("syntax.bracket.style", 1);
  // ===========================================================================
  
  // ===========================================================================
  /** The Constant GUTTER_VISIBLE. */
  public static final BooleanProp         GUTTER_VISIBLE                       = new BooleanProp("gutter.visible", true);

  /** The Constant GUTTER_BACKGROUND. */
  public static final ColorProp           GUTTER_BACKGROUND                    = new ColorProp("gutter.background", new Color(239, 237, 226));

  /** The Constant GUTTER_FOREGROUND. */
  public static final ColorProp           GUTTER_FOREGROUND                    = new ColorProp("gutter.foreground", new Color(157, 156, 180));

  /** The Constant GUTTER_CURRENT_FOREGROUND. */
  public static final ColorProp           GUTTER_CURRENT_FOREGROUND            = new ColorProp("gutter.current.foreground", new Color(0, 0, 128));

  /** The Constant GUTTER_CURRENT_BACKGROUND. */
  public static final ColorProp           GUTTER_CURRENT_BACKGROUND            = new ColorProp("gutter.current.background", new Color(239, 237, 226));

  /** The Constant GUTTER_CURRENT_BACKGROUND_ENABLED. */
  public static final BooleanProp         GUTTER_CURRENT_BACKGROUND_ENABLED    = new BooleanProp("gutter.current.background.enabled", false);

  /** The Constant GUTTER_UPDATE_FONT. */
  public static final BooleanProp         GUTTER_UPDATE_FONT                   = new BooleanProp("gutter.update.font", true);

  /** The Constant GUTTER_BORDER_GAP. */
  public static final IntProp             GUTTER_BORDER_GAP                    = new IntProp("gutter.border.gap", 10);

  /** The Constant GUTTER_BORDER_WIDTH. */
  public static final IntProp             GUTTER_BORDER_WIDTH                  = new IntProp("gutter.border.width", 1);

  /** The Constant GUTTER_BORDER_VISIBLE. */
  public static final BooleanProp         GUTTER_BORDER_VISIBLE                = new BooleanProp("gutter.border.visible", true);

  /** The Constant GUTTER_BORDER_COLOR. */
  public static final ColorProp           GUTTER_BORDER_COLOR                  = new ColorProp("gutter.border.color", new Color(201,199,190));

  /** The Constant GUTTER_SELECTION_COLOR. */
  public static final ColorProp           GUTTER_SELECTION_COLOR               = new ColorProp("gutter.selection.color", new Color(255, 255, 156));

  /** The Constant GUTTER_SELECTION_BORDER_COLOR. */
  public static final ColorProp           GUTTER_SELECTION_BORDER_COLOR        = new ColorProp("gutter.selection.border.color", GUTTER_SELECTION_COLOR.getDefault().darker());

  /** The Constant GUTTER_SELECTION_WIDTH. */
  public static final IntProp             GUTTER_SELECTION_WIDTH               = new IntProp("gutter.selection.width", 3);

  /** The Constant GUTTER_SELECTION_BORDER. */
  public static final BooleanProp         GUTTER_SELECTION_BORDER              = new BooleanProp("gutter.selection.border", true);

  /** The Constant GUTTER_BOOKMARK_BACKGROUND. */
  public static final ColorProp           GUTTER_BOOKMARK_BACKGROUND           = new ColorProp("gutter.bookmark.background", new Color(224, 220, 199));

  /** The Constant GUTTER_BOOKMARK_COLOR. */
  public static final ColorProp           GUTTER_BOOKMARK_COLOR                = new ColorProp("gutter.bookmark.color", new Color(135, 188, 247));

  /** The Constant GUTTER_BOOKMARK_BORDER_COLOR. */
  public static final ColorProp           GUTTER_BOOKMARK_BORDER_COLOR         = new ColorProp("gutter.bookmark.border.color", new Color(14, 98, 164));

  /** The Constant GUTTER_BOOKMARK_WIDTH. */
  public static final IntProp             GUTTER_BOOKMARK_WIDTH                = new IntProp("gutter.bookmark.width", 7);

  /** The Constant GUTTER_BOOKMARK_GAP. */
  public static final IntProp             GUTTER_BOOKMARK_GAP                  = new IntProp("gutter.bookmark.gap", 2);

  /** The Constant GUTTER_BRACKET_SCOPE_VISIBLE. */
  public static final BooleanProp         GUTTER_BRACKET_SCOPE_VISIBLE         = new BooleanProp("gutter.bracket.scope.visible", true);

  /** The Constant GUTTER_BRACKET_SCOPE_COLOR. */
  public static final ColorProp           GUTTER_BRACKET_SCOPE_COLOR           = new ColorProp("gutter.bracket.scope.color", new Color(224, 220, 199));                       // [changed v0.3] prev. 227, 108, 10  
  // ===========================================================================

  /** The Constant USE_CUSTOM_SHORTCUTS. */
  public static final BooleanProp         USE_CUSTOM_SHORTCUTS                 = new BooleanProp2("shortcuts.custom", false);

  /** The Constant UNDO_LIMIT. */
  public static final IntProp             UNDO_LIMIT                           = new IntProp("undo.limit", 1000);

  /** The Constant ACTIVE_LINE_VISIBLE. */
  public static final BooleanProp         ACTIVE_LINE_VISIBLE                  = new BooleanProp("active.line.visible", true);

  /** The Constant ACTIVE_LINE_COLOR. */
  public static final ColorProp           ACTIVE_LINE_COLOR                    = new ColorProp("active.line.color", new Color(232, 232, 255));

  /** The Constant BOOKMARKING_ENABLED. */
  public static final BooleanProp         BOOKMARKING_ENABLED                  = new BooleanProp("bookmarking.enabled", true);

  /** The Constant OCCURRENCES_HIGHLIGHTER_VISIBLE. */
  public static final BooleanProp         OCCURRENCES_HIGHLIGHTER_VISIBLE      = new BooleanProp("occurrences.highlighter.visible", true);

  /** The Constant OCCURRENCES_HIGHLIGHTER_COLOR. */
  public static final ColorProp           OCCURRENCES_HIGHLIGHTER_COLOR        = new ColorProp("occurrences.highlighter.color", new Color(155, 255, 155, 200));

  /** The Constant OCCURRENCES_HIGHLIGHTER_BORDER_COLOR. */
  public static final ColorProp           OCCURRENCES_HIGHLIGHTER_BORDER_COLOR = new ColorProp("occurrences.highlighter.border.color", new Color(0, 128, 0, 200));

  /** The Constant OCCURRENCES_CIRCULAR_NAVIGATION. */
  public static final BooleanProp         OCCURRENCES_CIRCULAR_NAVIGATION      = new BooleanProp("occurrences.circular.navigation", true);

  /** The Constant BOOKMARKS_CIRCULAR_NAVIGATION. */
  public static final BooleanProp         BOOKMARKS_CIRCULAR_NAVIGATION        = new BooleanProp("bookmarks.circular.navigation", true);

  /** The Constant SEARCH_HIGHLIGHTER_COLOR. */
  public static final ColorProp           SEARCH_HIGHLIGHTER_COLOR             = new ColorProp("search.highlighter.color", new Color(255, 200, 0, 200));

  /** The Constant SEARCH_HIGHLIGHTER_BORDER_COLOR. */
  public static final ColorProp           SEARCH_HIGHLIGHTER_BORDER_COLOR      = new ColorProp("search.highlighter.border.color", new Color(255, 102, 0, 200));

  /** The Constant BRACKET_HIGHLIGHTER_VISIBLE. */
  public static final BooleanProp         BRACKET_HIGHLIGHTER_VISIBLE          = new BooleanProp("bracket.highlighter.visible", true);

  /** The Constant BRACKET_HIGHLIGHTER_COLOR. */
  public static final ColorProp           BRACKET_HIGHLIGHTER_COLOR            = new ColorProp("bracket.highlighter.color", new Color(255, 128, 128, 128));

  /** The Constant CHOOSER_FILE_DIRECTORY. */
  public static final StringProp          CHOOSER_FILE_DIRECTORY               = new StringProp("chooser.file.directory", System.getProperty("user.dir", EMPTY_STRING));

  /** The Constant FILES_RECENT_MAX. */
  public static final IntProp             FILES_RECENT_MAX                     = new IntProp("files.recent.max", 15);

  /** The Constant SECURE_SAVE. */
  public static final BooleanProp         SECURE_SAVE                          = new BooleanProp("secure.save", false);                                                           //true;

  /** The Constant FILE_ENCODING. */
  public static final StringProp          FILE_ENCODING;

  /** The Constant REMOVE_END_SPACES. */
  public static final BooleanProp         REMOVE_END_SPACES                    = new BooleanProp("remove.end.spaces", true);

  /** The Constant TOOLBAR_VISIBLE. */
  public static final BooleanProp         TOOLBAR_VISIBLE                      = new BooleanProp("toolbar.visible", true);

  /** The Constant STATUSBAR_VISIBLE. */
  public static final BooleanProp         STATUSBAR_VISIBLE                    = new BooleanProp("statusbar.visible", true);

  /** The Constant FINDRESULTS_VISIBLE. */
  public static final BooleanProp         FINDRESULTS_VISIBLE                  = new BooleanProp("findresults.visible", false);

  /** The Constant HEAP_MONITOR_VISIBLE. */
  public static final BooleanProp         HEAP_MONITOR_VISIBLE                 = new BooleanProp("heap.monitor.visible", true);

  /** The Constant TOOLBAR_ROWS. */
  public static final BooleanProp         TOOLBAR_ROWS                         = new BooleanProp("toolbar.rows", true);

  /** The Constant DATE_FORMAT. */
  public static final StringProp          DATE_FORMAT                          = new StringProp("date.format", "dd/MM/yyyy - HH:mm:ss");

  /** The Constant VIEW_ACTION_SCOPE. */
  public static final ViewActionScopeProp VIEW_ACTION_SCOPE                    = new ViewActionScopeProp("view.action.scope", ViewActionScope.BUFFER);

  /** The Constant TAB_LAYOUT_POLICY. */
  public static final IntProp             TAB_LAYOUT_POLICY                    = new IntProp("tab.layout.policy", JTabbedPane.WRAP_TAB_LAYOUT);

  /** The Constant TAB_PLACEMENT. */
  public static final IntProp             TAB_PLACEMENT                        = new IntProp("tab.placement", SwingConstants.TOP);

  /** The Constant TAB_FILE_EXTENSION. */
  public static final BooleanProp         TAB_FILE_EXTENSION                   = new BooleanProp("tab.file.extension", true);

  /** The Constant TAB_FILE_ICON. */
  public static final BooleanProp         TAB_FILE_ICON                        = new BooleanProp("tab.file.icon", true);

  /** The Constant TAB_CLOSE_BUTTON. */
  public static final BooleanProp         TAB_CLOSE_BUTTON                     = new BooleanProp("tab.close.button", true);

  /** The Constant TAB_ROUNDED. */
  public static final BooleanProp         TAB_ROUNDED                          = new BooleanProp("tab.rounded", true);

  /** The Constant TAB_TABBED. */
  public static final BooleanProp         TAB_TABBED                           = new BooleanProp("tab.tabbed", true);

  /** The Constant SPLIT_CONTINUOUS_LAYOUT. */
  public static final BooleanProp         SPLIT_CONTINUOUS_LAYOUT              = new BooleanProp("split.continuous.layout", true);

  /** The Constant SPLIT_DIVIDER_SIZE. */
  public static final IntProp             SPLIT_DIVIDER_SIZE                   = new IntProp("split.divider.size", 3);

  // ===========================================================================
  /** The Constant MARKER_VISIBLE. */
  public static final BooleanProp         MARKER_VISIBLE                       = new BooleanProp("marker.visible", true);

  /** The Constant MARKER_OCCURRENCE_COLOR. */
  public static final ColorProp           MARKER_OCCURRENCE_COLOR              = new ColorProp("marker.occurrence.color", new Color(155, 255, 155));

  /** The Constant MARKER_OCCURRENCE_BORDER_COLOR. */
  public static final ColorProp           MARKER_OCCURRENCE_BORDER_COLOR       = new ColorProp("marker.occurrence.border.color", new Color(0, 205, 0));

  /** The Constant MARKER_SEARCH_COLOR. */
  public static final ColorProp           MARKER_SEARCH_COLOR                  = new ColorProp("marker.search.color", SEARCH_HIGHLIGHTER_COLOR.getDefault());

  /** The Constant MARKER_SEARCH_BORDER_COLOR. */
  public static final ColorProp           MARKER_SEARCH_BORDER_COLOR           = new ColorProp("marker.search.border.color", SEARCH_HIGHLIGHTER_BORDER_COLOR.getDefault());

  /** The Constant MARKER_BOOKMARK_COLOR. */
  public static final ColorProp           MARKER_BOOKMARK_COLOR                = new ColorProp("marker.bookmark.color", GUTTER_BOOKMARK_COLOR.getDefault());

  /** The Constant MARKER_BOOKMARK_BORDER_COLOR. */
  public static final ColorProp           MARKER_BOOKMARK_BORDER_COLOR         = new ColorProp("marker.bookmark.border.color", GUTTER_BOOKMARK_BORDER_COLOR.getDefault());

  /** The Constant MARKER_CARET_COLOR. */
  public static final ColorProp           MARKER_CARET_COLOR                   = new ColorProp("marker.caret.color", TEXT_CARET_INS_COLOR.getDefault());

  /** The Constant MARKER_PREFERRED_WIDTH. */
  public static final IntProp             MARKER_PREFERRED_WIDTH               = new IntProp("marker.preferred.width", 14);
  // ===========================================================================

  // ===========================================================================
  /** The Constant BROWSER_NORMAL_FONT. */
  public static final FontProp            BROWSER_NORMAL_FONT                  = new FontProp("browser.normal.font", new Font("Courier", Font.PLAIN, 12));

  /** The Constant BROWSER_BOLD_FONT. */
  public static final FontProp            BROWSER_BOLD_FONT                    = new FontProp("browser.bold.font", new Font("Courier", Font.BOLD, 12));

  /** The Constant BROWSER_DEVICE_FONT. */
  public static final FontProp            BROWSER_DEVICE_FONT                  = new FontProp("browser.device.font", new Font("Courier", Font.BOLD | Font.ITALIC, 12));

  /** The Constant BROWSER_DIR_FOREGROUND. */
  public static final ColorProp           BROWSER_DIR_FOREGROUND               = new ColorProp("browser.dir.foreground", Color.BLUE);

  /** The Constant BROWSER_EXEC_FOREGROUND. */
  public static final ColorProp           BROWSER_EXEC_FOREGROUND              = new ColorProp("browser.exec.foreground", new Color(153, 204, 0));

  /** The Constant BROWSER_LINK_FOREGROUND. */
  public static final ColorProp           BROWSER_LINK_FOREGROUND              = new ColorProp("browser.link.foreground", new Color(0, 128, 128));

  /** The Constant BROWSER_COMP_FOREGROUND. */
  public static final ColorProp           BROWSER_COMP_FOREGROUND              = new ColorProp("browser.comp.foreground", Color.RED);

  /** The Constant BROWSER_IMAGE_FOREGROUND. */
  public static final ColorProp           BROWSER_IMAGE_FOREGROUND             = new ColorProp("browser.image.foreground", Color.MAGENTA);

  /** The Constant BROWSER_AUDIO_FOREGROUND. */
  public static final ColorProp           BROWSER_AUDIO_FOREGROUND             = new ColorProp("browser.audio.foreground", new Color(51, 204, 204));

  /** The Constant BROWSER_COLORS_ENABLED. */
  public static final BooleanProp         BROWSER_COLORS_ENABLED               = new BooleanProp("browser.colors.enabled", false);

  /** The Constant BROWSER_HUMAN_READABLE. */
  public static final BooleanProp         BROWSER_HUMAN_READABLE               = new BooleanProp("browser.human.readable", true);

  /** The Constant BROWSER_CLASSIFY. */
  public static final BooleanProp         BROWSER_CLASSIFY                     = new BooleanProp("browser.classify", true);

  /** The Constant BROWSER_INFO_VISIBLE. */
  public static final BooleanProp         BROWSER_INFO_VISIBLE                 = new BooleanProp("browser.info.visible", true);

  /** The Constant BROWSER_TRANSPARENCY. */
  public static final FloatProp           BROWSER_TRANSPARENCY                 = new FloatProp("browser.transparency", 1);

  /** The Constant BROWSER_LOCATION_HORIZONTAL. */
  public static final DoubleProp          BROWSER_LOCATION_HORIZONTAL          = new DoubleProp("browser.location.horizontal", 0.5);

  /** The Constant BROWSER_LOCATION_VERTICAL. */
  public static final DoubleProp          BROWSER_LOCATION_VERTICAL            = new DoubleProp("browser.location.vertical", 0.5);
  // ===========================================================================

  // ===========================================================================
  /** The Constant MINIMAP_VIEWRECT_VISIBLE. */
  public static final BooleanProp         MINIMAP_VIEWRECT_VISIBLE             = new BooleanProp("minimap.viewrect.visible", false);

  /** The Constant MINIMAP_VIEWRECT_COLOR. */
  public static final ColorProp           MINIMAP_VIEWRECT_COLOR               = new ColorProp("minimap.viewrect.color", new Color(255, 255, 128, 50));

  /** The Constant MINIMAP_VIEWRECT_BORDER_COLOR. */
  public static final ColorProp           MINIMAP_VIEWRECT_BORDER_COLOR        = new ColorProp("minimap.viewrect.border.color", new Color(128, 128, 0, 50));

  /** The Constant MINIMAP_FONT_SIZE. */
  public static final FloatProp           MINIMAP_FONT_SIZE                    = new FloatProp("minimap.font.size", 9f);
  // ===========================================================================
  
  // --- Perform action --------------------------------------------------------
  /** The Constant PERFORM_ACTION_TRANSPARENCY. */
  public static final FloatProp           PERFORM_ACTION_TRANSPARENCY          = new FloatProp("perform.action.transparency", 1);

  /** The Constant PERFORM_ACTION_LOCATION_HORIZONTAL. */
  public static final DoubleProp          PERFORM_ACTION_LOCATION_HORIZONTAL   = new DoubleProp("perform.action.location.horizontal", 0.5);

  /** The Constant PERFORM_ACTION_LOCATION_VERTICAL. */
  public static final DoubleProp          PERFORM_ACTION_LOCATION_VERTICAL     = new DoubleProp("perform.action.location.vertical", 0.5);

  /** The Constant PERFORM_ACTION_COLUMNS. */
  public static final IntProp             PERFORM_ACTION_COLUMNS               = new IntProp("perform.action.columns", 50);
  // ---------------------------------------------------------------------------

  // --- Find ------------------------------------------------------------------
  /** The Constant FIND_LOOKIN. */
  public static final IntProp             FIND_LOOKIN                          = new IntProp("find.lookin", -1);

  /** The Constant FIND_FROMCURSOR. */
  public static final BooleanProp         FIND_FROMCURSOR                      = new BooleanProp("find.fromcursor", false);

  /** The Constant FIND_MATCH_CASE. */
  public static final BooleanProp         FIND_MATCH_CASE                      = new BooleanProp("find.match.case", true);

  /** The Constant FIND_MATCH_WHOLEWORD. */
  public static final BooleanProp         FIND_MATCH_WHOLEWORD                 = new BooleanProp("find.match.wholeword", false);

  /** The Constant FIND_DIRECTION_DOWN. */
  public static final BooleanProp         FIND_DIRECTION_DOWN                  = new BooleanProp("find.direction.down", true);

  /** The Constant FIND_HIGHLIGHT_ALL. */
  public static final BooleanProp         FIND_HIGHLIGHT_ALL                   = new BooleanProp("find.highlightall", true);

  /** The Constant FIND_REGEX. */
  public static final BooleanProp         FIND_REGEX                           = new BooleanProp("find.regex", false);
  // ---------------------------------------------------------------------------

  // --- Replace ---------------------------------------------------------------
  /** The Constant REPLACE_LOOKIN. */
  public static final IntProp             REPLACE_LOOKIN                       = new IntProp("replace.lookin", -1);

  /** The Constant REPLACE_FROMCURSOR. */
  public static final BooleanProp         REPLACE_FROMCURSOR                   = new BooleanProp("replace.fromcursor", false);

  /** The Constant REPLACE_MATCH_CASE. */
  public static final BooleanProp         REPLACE_MATCH_CASE                   = new BooleanProp("replace.match.case", true);

  /** The Constant REPLACE_MATCH_WHOLEWORD. */
  public static final BooleanProp         REPLACE_MATCH_WHOLEWORD              = new BooleanProp("replace.match.wholeword", false);

  /** The Constant REPLACE_DIRECTION_DOWN. */
  public static final BooleanProp         REPLACE_DIRECTION_DOWN               = new BooleanProp("replace.direction.down", true);

  /** The Constant REPLACE_HIGHLIGHT_ALL. */
  public static final BooleanProp         REPLACE_HIGHLIGHT_ALL                = new BooleanProp("replace.highlightall", true);

  /** The Constant REPLACE_REGEX. */
  public static final BooleanProp         REPLACE_REGEX                        = new BooleanProp("replace.regex", false);
  // ---------------------------------------------------------------------------

  // --- Print -----------------------------------------------------------------
  /** The Constant PRINT_LINE_NUMBERS. */
  public static final BooleanProp         PRINT_LINE_NUMBERS                   = new BooleanProp("print.lineNumbers", true);

  /** The Constant PRINT_HEADER. */
  public static final BooleanProp         PRINT_HEADER                         = new BooleanProp("print.header", true);

  /** The Constant PRINT_WRAP_TEXT. */
  public static final BooleanProp         PRINT_WRAP_TEXT                      = new BooleanProp("print.wrapText", true);

  /** The Constant PRINT_FONT. */
  public static final FontProp            PRINT_FONT                           = new FontProp("print.font", new Font("Courier", Font.PLAIN, 10));
  // ---------------------------------------------------------------------------

  /** The is adjust post laf changed enabled. */
  private static boolean                  isAdjustPostLAFChangedEnabled;
  
  /** The is adjust post mode changed enabled. */
  private static boolean                  isAdjustPostModeChangedEnabled;

  /** Logger. */
  private static final Logger             LOGGER                               = Logger.getLogger(Config.class.getName());

  /** no instances */
  private Config() {
    super();
  }

  /**
   * Gets the home dir.
   *
   * @return String
   */
  public static String getHomeDir() {
    return homeDir;
  }
  
  /**
   * Gets the locale.
   *
   * @return Locale
   */
  public static Locale getLocale() {
    return locale;
  }
  
  /**
   * Inits the directories.
   */
  public static void initDirectories() {
    File file = new File(homeDir);

    if (!file.exists()) {
      homeDir = System.getProperty("user.dir", EMPTY_STRING); 
    }

    file = new File(COLORSCHEMES_DIR);
    if (!file.exists()) {
      @SuppressWarnings("unused")
      boolean bool = file.mkdir(); //Keep FindBugs happy
    }
    file = new File(KEYMAP_DIR);
    if (!file.exists()) {
      @SuppressWarnings("unused")
      boolean bool = file.mkdir(); //Keep FindBugs happy
    }
  }

  /**
   * Load search historial.
   */
  public static void loadSearchHistorial() {
    findList.clear();
    replaceList.clear();

    BufferedReader in = null;
    try {
      in = new BufferedReader(new FileReader(SEARCH_FILE_PATH));
      String line;
      while ((line = in.readLine()) != null) {
        if (!line.startsWith("#")) { 
          int i = line.indexOf('#');
          if (i != Utilities.INDEX_NOT_FOUND) {
            line = line.substring(0, i);
          }
          _interpret_(line);
        }
      }
    }
    catch (IOException ex) {
      // no pasa nada
    }
    finally {
      try {
        if (in != null) {
          in.close();
        }
      }
      catch (IOException ex) {
        LOGGER.log(Level.WARNING, ex.getMessage(), ex);
      }
    }
  }

  /**
   * Save search historial.
   */
  public static void saveSearchHistorial() {
    PrintWriter pw = null;
    try {
      pw = new PrintWriter(new BufferedWriter(new FileWriter(SEARCH_FILE_PATH)));
      for (String aFindList : findList) {
        pw.println("find.list=" + aFindList); 
      }
      for (String aReplaceList : replaceList) {
        pw.println("replace.list=" + aReplaceList); 
      }
    }
    catch (Exception ex) {
      LOGGER.log(Level.WARNING, ex.getMessage(), ex);
    }
    finally {
      if (pw != null) {
        try {
          pw.close();
        }
        catch (Exception ex) {
          LOGGER.log(Level.WARNING, ex.getMessage(), ex);
        }
      }
    }
  }

  /**
   * _is key_.
   *
   * @param line String
   * @param key String
   * @return boolean
   */
  private static boolean _isKey_(String line, String key) {
    int i = line.indexOf('=');
      return i > 0 && line.substring(0, i).trim().equalsIgnoreCase(key);
  }

  /**
   * _get value_.
   *
   * @param line String
   * @return String
   */
  private static String _getValue_(String line) {
    return line.substring(line.indexOf('=') + 1, line.length());
  }

  /**
   * _interpret_.
   *
   * @param s String
   */
  private static void _interpret_(String s) {
    try {
      if (_isKey_(s, "find.list")) { 
        findList.add(_getValue_(s));
      }
      else if (_isKey_(s, "replace.list")) { 
        replaceList.add(_getValue_(s));
      }
    }
    catch (Exception ex) {
      //ignored
    }
  }
  
  /**
   * 
   * @return List
   */
  public static List<String> getFindList() {
    return findList;
  }

  /**
   * 
   * @param find_list List
   */
  public static void setFindList(List<String> find_list) {
    findList = find_list;
  }
  
  /**
   * 
   * @return List
   */
  public static List<String> getReplaceList() {
    return replaceList;
  }

  /**
   * 
   * @param replace_list List
   */
  public static void setReplaceList(List<String> replace_list) {
    replaceList = replace_list;
  }
  
  /**
   * Load properties.
   */
  public static void loadProperties() {
    InputStream is = null;
    try {
      is = new FileInputStream(PROPERTIES_FILE_PATH);
      options.load(is);
    }
    catch (IOException ex) {
      // no pasa nada
    }
    finally {
      try {
        if (is != null) {
          is.close();
        }
      }
      catch (IOException ex) {
        LOGGER.log(Level.WARNING, ex.getMessage(), ex);
      }
    }
  }
  
  /**
   * Sets the adjust post mode changed enabled.
   *
   * @param b the new adjust post mode changed enabled
   */
  public static void setAdjustPostModeChangedEnabled(boolean b) {
    isAdjustPostModeChangedEnabled = b;
  }
  
  /**
   * Checks if is adjust post mode changed enabled.
   *
   * @return true, if is adjust post mode changed enabled
   */
  public static boolean isAdjustPostModeChangedEnabled() {
    return isAdjustPostModeChangedEnabled;
  }

  /**
   * Sets the adjust post laf changed enabled.
   *
   * @param b the new adjust post laf changed enabled
   */
  public static void setAdjustPostLAFChangedEnabled(boolean b) {
    isAdjustPostLAFChangedEnabled = b;
  }

  /**
   * Checks if is adjust post laf changed enabled.
   *
   * @return true, if is adjust post laf changed enabled
   */
  public static boolean isAdjustPostLAFChangedEnabled() {
    return isAdjustPostLAFChangedEnabled;
  }
  
  /**
   * Save properties.
   */
  public static void saveProperties() {
    if (isAdjustPostModeChangedEnabled()) adjustPostModeChanged();
    if (isAdjustPostLAFChangedEnabled())  adjustPostLAFChanged();
    
    // --- por si se modifica el archivo de propiedades manualmente 
    options.clear();
    loadProperties();
    options.putAll(changes);
    for(String key : removes)
      options.remove(key);
    // ---
    
    OutputStream os = null;
    try {
      os = new FileOutputStream(PROPERTIES_FILE_PATH);
      //options.store(os, JNPad.TITLE.concat(" Config"));

      // --- ordenar por claves ---
      Properties tmp = new Properties() {
        /** UID */
        private static final long serialVersionUID = 6975987883580014663L;

        @Override
        public synchronized Enumeration<Object> keys() {
          return Collections.enumeration(new TreeSet<Object>(super.keySet()));
        }
      };
      tmp.putAll(options);
      tmp.store(os, JNPad.TITLE.concat(" Config"));
      // ---
    }
    catch (IOException ex) {
      LOGGER.log(Level.WARNING, ex.getMessage(), ex);
    }
    finally {
      try {
        if (os != null) {
          os.close();
        }
      }
      catch (IOException ex) {
        LOGGER.log(Level.WARNING, ex.getMessage(), ex);
      }
    }
  }

  /**
   * Load default properties.
   */
  public static void loadDefaultProperties() {
    InputStream is = null;
    try {
      is = new FileInputStream(DEFAULTS_FILE_PATH);
      defaults.load(is);
    }
    catch (IOException ex) {
      // no pasa nada
    }
    finally {
      try {
        if (is != null) {
          is.close();
        }
      }
      catch (IOException ex) {
        LOGGER.log(Level.WARNING, ex.getMessage(), ex);
      }
    }
  }

  /**
   * Gets the property.
   *
   * @param key String
   * @return String
   */
  public static String getProperty(String key) {
    return options.getProperty(key);
  }

  /**
   * Gets the property.
   *
   * @param key String
   * @param def String
   * @return String
   */
  public static String getProperty(String key, String def) {
    return options.getProperty(key, def);
  }

  /**
   * Sets the property.
   *
   * @param key String
   * @param value String
   */
  public static void setProperty(String key, String value) {
    options.setProperty(key, value);
    changes.setProperty(key, value);
  }

  /**
   * Removes the.
   *
   * @param key String
   * @return Object
   */
  public static Object remove(String key) {
    Object o = options.remove(key);
    changes.remove(key);
    removes.add(key);
    return o;
  }
  
  /**
   * Put all.
   *
   * @param map the map
   */
  public static void putAll(Map<?, ?> map) {
    options.putAll(map);
    changes.putAll(map);
  }

  /**
   * Gets the string prop.
   *
   * @param id the id
   * @return the string prop
   */
  public static String getStringProp(StringProp id) {
    return getStringProp(id.getName(), id.getDefault());
  }
  
  /**
   * Gets the string prop.
   *
   * @param key the key
   * @param def the def
   * @return the string prop
   */
  public static String getStringProp(String key, String def) {
    String propVal = options.getProperty(key);
    return (propVal != null) ? propVal : defaults.getProperty(key, def);
  }

  /**
   * Sets the string prop.
   *
   * @param id the id
   * @param value the value
   */
  public static void setStringProp(StringProp id, String value) {
    setStringProp(id.getName(), value);
  }
  
  /**
   * Sets the string prop.
   *
   * @param key the key
   * @param value the value
   */
  public static void setStringProp(String key, String value) {
    setProperty(key, value);
  }

  /**
   * Sets the view action scope prop.
   *
   * @param id the id
   * @param scope the scope
   */
  public static void setViewActionScopeProp(ViewActionScopeProp id, ViewActionScope scope) {
    setViewActionScopeProp(id.getName(), scope);
  }
  
  /**
   * Sets the view action scope prop.
   *
   * @param key the key
   * @param scope the scope
   */
  public static void setViewActionScopeProp(String key, ViewActionScope scope) {
    setProperty(key, ViewActionScopeProp.format(scope));
  }

  /**
   * Gets the view action scope prop.
   *
   * @param id the id
   * @return the view action scope prop
   */
  public static ViewActionScope getViewActionScopeProp(ViewActionScopeProp id) {
    return getViewActionScopeProp(id.getName(), id.getDefault());
  }
  
  /**
   * Gets the view action scope prop.
   *
   * @param key the key
   * @param def the def
   * @return the view action scope prop
   */
  public static ViewActionScope getViewActionScopeProp(String key, ViewActionScope def) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      try {
        ViewActionScope scope = ViewActionScopeProp.parse(propval);
        return scope != null ? scope : def;
      }
      catch (NumberFormatException ex) {
        //ignored
      }
    }
    return def;
  }

  /**
   * Sets the mode prop.
   *
   * @param id the id
   * @param mode the mode
   */
  public static void setModeProp(ModeProp id, Mode mode) {
    setModeProp(id.getName(), mode);
  }
  
  /**
   * Sets the mode prop.
   *
   * @param key the key
   * @param mode the mode
   */
  public static void setModeProp(String key, Mode mode) {
    setProperty(key, ModeProp.format(mode));
  }

  /**
   * Gets the mode prop.
   *
   * @param id the id
   * @return the mode prop
   */
  public static Mode getModeProp(ModeProp id) {
    return getModeProp(id.getName(), id.getDefault());
  }
  
  /**
   * Gets the mode prop.
   *
   * @param key the key
   * @param def the def
   * @return the mode prop
   */
  public static Mode getModeProp(String key, Mode def) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      try {
        Mode mode = ModeProp.parse(propval);
        return mode != null ? mode : def;
      }
      catch (NumberFormatException ex) {
        //ignored
      }
    }
    return def;
  }

  /**
   * Gets the int prop.
   *
   * @param id the id
   * @return the int prop
   */
  public static int getIntProp(IntProp id) {
    return getIntProp(id.getName(), id.getDefault());
  }
  
  /**
   * Gets the int prop.
   *
   * @param key the key
   * @param def the def
   * @return the int prop
   */
  public static int getIntProp(String key, int def) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      try {
        return IntProp.parse(propval);
      }
      catch (NumberFormatException ex) {
        //ignored
      }
    }
    return def;
  }

  /**
   * Sets the int prop.
   *
   * @param id the id
   * @param i the i
   */
  public static void setIntProp(IntProp id, int i) {
    setIntProp(id.getName(), i);
  }

  /**
   * Sets the int prop.
   *
   * @param key the key
   * @param i the i
   */
  public static void setIntProp(String key, int i) {
    setProperty(key, IntProp.format(i));
  }

  /**
   * Gets the double prop.
   *
   * @param id the id
   * @return the double prop
   */
  public static double getDoubleProp(DoubleProp id) {
    return getDoubleProp(id.getName(), id.getDefault());
  }
  
  /**
   * Gets the double prop.
   *
   * @param key the key
   * @param def the def
   * @return the double prop
   */
  public static double getDoubleProp(String key, double def) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      try {
        return DoubleProp.parse(propval);
      }
      catch (NumberFormatException ex) {
        //ignored
      }
    }
    return def;
  }

  /**
   * Sets the double prop.
   *
   * @param id the id
   * @param doubl the doubl
   */
  public static void setDoubleProp(DoubleProp id, double doubl) {
    setDoubleProp(id.getName(), doubl);
  }

  /**
   * Sets the double prop.
   *
   * @param key the key
   * @param doubl the doubl
   */
  public static void setDoubleProp(String key, double doubl) {
    setProperty(key, DoubleProp.format(doubl));
  }

  /**
   * Gets the float prop.
   *
   * @param id the id
   * @return the float prop
   */
  public static float getFloatProp(FloatProp id) {
    return getFloatProp(id.getName(), id.getDefault());
  }

  /**
   * Gets the float prop.
   *
   * @param key the key
   * @param def the def
   * @return the float prop
   */
  public static float getFloatProp(String key, float def) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      try {
        return FloatProp.parse(propval);
      }
      catch (NumberFormatException ex) {
        //ignored
      }
    }
    return def;
  }

  /**
   * Sets the float prop.
   *
   * @param id the id
   * @param f the f
   */
  public static void setFloatProp(FloatProp id, float f) {
    setFloatProp(id.getName(), f);
  }
  
  /**
   * Sets the float prop.
   *
   * @param key the key
   * @param f the f
   */
  public static void setFloatProp(String key, float f) {
    setProperty(key, FloatProp.format(f));
  }

  /**
   * Gets the boolean prop.
   *
   * @param id the id
   * @return the boolean prop
   */
  public static boolean getBooleanProp(BooleanProp id) {
    return getBooleanProp(id.getName(), id.getDefault());
  }
  
  /**
   * Gets the boolean prop.
   *
   * @param key the key
   * @param def the def
   * @return the boolean prop
   */
  public static boolean getBooleanProp(String key, boolean def) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
      if (propval == null) {
        return def;
      }
    }
    return BooleanProp.parse(propval);
  }

  /**
   * Sets the boolean prop.
   *
   * @param id the id
   * @param bool the bool
   */
  public static void setBooleanProp(BooleanProp id, boolean bool) {
    setProperty(id.getName(), BooleanProp.format(bool));
  }
  
  /**
   * Sets the boolean prop.
   *
   * @param key the key
   * @param bool the bool
   */
  public static void setBooleanProp(String key, boolean bool) {
    setProperty(key, BooleanProp.format(bool));
  }

  /**
   * Gets the font prop.
   *
   * @param id the id
   * @return the font prop
   */
  public static Font getFontProp(FontProp id) {
    return getFontProp(id.getName(), id.getDefault());
  }
 
  /**
   * Gets the font prop.
   *
   * @param key the key
   * @param def the def
   * @return the font prop
   */
  public static Font getFontProp(String key, Font def) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      try {
        return FontProp.parse(propval);
      }
      catch (Exception ex) {
        //ignored
      }
    }
    return def;
  }

  /**
   * Sets the font prop.
   *
   * @param id the id
   * @param font the font
   */
  public static void setFontProp(FontProp id, Font font) {
    setFontProp(id.getName(), font);
  }

  /**
   * Sets the font prop.
   *
   * @param key the key
   * @param font the font
   */
  public static void setFontProp(String key, Font font) {
    setProperty(key, FontProp.format(font));
  }

  /**
   * Gets the line separator prop.
   *
   * @param key the key
   * @return the line separator prop
   */
  public static String getLineSeparatorProp(String key) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      StringBuilder sb = new StringBuilder();
      int j = 0;
      int i;
      while ( (i = propval.indexOf('\\', j)) != -1) {
        for (j = i + 1; j < propval.length() && propval.charAt(j) != '\\'; j++);
        sb.append( (char) IntProp.parse(propval.substring(i + 1, j)));
      }
      String s1 = sb.toString();
      if (Utilities.isEmptyString(s1)) {
        s1 = null;
      }
      return s1;
    }
    return null;
  }

  /**
   * Sets the line separator prop.
   *
   * @param key String
   * @param line_separator String que puede ser <code>"\n"</code>,
   * <code>"\r\n"</code>, <code>"\r"</code> o <code>null</code>
   */
  public static void setLineSeparatorProp(String key, String line_separator) {
    setProperty(key, writeLineSeparatorProp(line_separator));
  }

  /**
   * Gets the color prop.
   *
   * @param id the id
   * @return the color prop
   */
  public static Color getColorProp(ColorProp id) {
    return getColorProp(id.getName(), id.getDefault());
  }
  
  /**
   * Gets the color prop.
   *
   * @param key the key
   * @param def the def
   * @return the color prop
   */
  public static Color getColorProp(String key, Color def) {
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      try {
        return ColorProp.parse(propval);
      }
      catch (Exception ex) {
        //ignored
      }
    }
    return def;
  }

  /**
   * Sets the color prop.
   *
   * @param id the id
   * @param color the color
   */
  public static void setColorProp(ColorProp id, Color color) {
    setColorProp(id.getName(), color);
  }
  
  /**
   * Sets the color prop.
   *
   * @param key the key
   * @param color the color
   */
  public static void setColorProp(String key, Color color) {
    setProperty(key, ColorProp.format(color));
  }

  /**
   * Gets the list prop.
   *
   * @param key the key
   * @return the list prop
   */
  public static List<String> getListProp(String key) {
    List<String> list = new ArrayList<String>();
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      return getList(propval);
    }
    return list;
  }

  /**
   * Sets the list prop.
   *
   * @param key the key
   * @param list the list
   */
  public static void setListProp(String key, List<?> list) {
    setProperty(key, writeListProp(list));
  }

  /**
   * Gets the jNPad input list prop.
   *
   * @param key the key
   * @return the jN pad input list prop
   */
  public static List<JNPadInput> getJNPadInputListProp(String key) {
    List<JNPadInput> list = new ArrayList<JNPadInput>();
    String propval = options.getProperty(key);
    if (propval == null) {
      propval = defaults.getProperty(key);
    }
    if (propval != null) {
      List<String> l_values = getList(propval);
      for (String value : l_values) {
        try {
          list.add(parseJNPadInput(value));
        }
        catch (Exception ex) {
          LOGGER.warning("jNPad Input inválido: ".concat(value)); 
        }
      }
    }
    return list;
  }

  /**
   * Parses the jNPad input.
   *
   * @param s String
   * @return JNPadInput
   * @throws IllegalArgumentException the illegal argument exception
   */
  public static JNPadInput parseJNPadInput(String s) throws IllegalArgumentException {
    try {
      s = s.trim();
      StringTokenizer st = new StringTokenizer(s, COMMA_STRING);

      String  path     = st.nextToken().trim();
      int     position = st.hasMoreTokens() ? IntProp.parse(st.nextToken().trim()) : -1;
      boolean readOnly = st.hasMoreTokens() && BooleanProp.parse(st.nextToken().trim());
      boolean current  = st.hasMoreTokens() && BooleanProp.parse(st.nextToken().trim());
      boolean linewrap = st.hasMoreTokens() && BooleanProp.parse(st.nextToken().trim());
      String  splitCfg = st.hasMoreTokens() ? st.nextToken().trim() : EMPTY_STRING;

      return new JNPadInput(path, position, readOnly, current, splitCfg, linewrap);
    }
    catch (Exception ex) {
      throw new IllegalArgumentException("jNPad Input inválido: " + s); 
    }
  }

  /**
   * Sets the jNPad input list prop.
   *
   * @param key the key
   * @param list the list
   */
  public static void setJNPadInputListProp(String key, List<JNPadInput> list) {
    setProperty(key, writeJNPadInputListProp(list));
  }

  /**
   * Gets the list.
   *
   * @param value String
   * @return List
   */
  private static List<String> getList(String value) {
    List<String> list = new ArrayList<String>();
    StringTokenizer st = new StringTokenizer(value, ";"); 
    while (st.hasMoreTokens()) {
      list.add(st.nextToken().trim());
    }
    return list;
  }
  
  /**
   * Sets the mode.
   *
   * @param mode the new mode
   */
  public static void setMode(Mode mode) {
    if(mode_setting_flag) {
      return;
    }
    
    final Mode oldMode = getMode();
    
    if(oldMode == mode) {
      return;
    }
    
    JNPAD_MODE.setValue(mode); 
    Config.mode = mode;
    
    if (oldMode == Mode.MINIMALIST) {
      loadDefaultProperties();
    }
    else if (mode == Mode.MINIMALIST) {
      defaults.clear();
    }
    
    mode_setting_flag = true;
  }
  
  /**
   * Gets the mode.
   *
   * @return the mode
   */
  public static Mode getMode() {
    if (mode == null) {
      mode = JNPAD_MODE.getValue(); 
    }
    return mode;
  }
  
  /**
   * Checks if is mininalist mode.
   *
   * @return true, if is mininalist mode
   */
  public static boolean isMininalistMode() {
    return getMode() == Mode.MINIMALIST;
  }

  /**
   * Checks if is basic mode.
   *
   * @return true, if is basic mode
   */
  public static boolean isBasicMode() {
    return getMode() == Mode.BASIC;
  }

  /**
   * Checks if is default mode.
   *
   * @return true, if is default mode
   */
  public static boolean isDefaultMode() {
    return getMode() == Mode.DEFAULT;
  }
  
  /**
   * Checks if is distraction-free mode.
   *
   * @return true, if is distraction-free mode
   */
  public static boolean isDistractionFreeMode() {
    return getMode() == Mode.DISTRACTION_FREE;
  }
  
  /**
   * Adjust post mode changed.
   */
  private static void adjustPostModeChanged() {
    if (LOGGER.isLoggable(Level.CONFIG)) 
      LOGGER.config("-- adjustPostModeChanged --");
    Mode mode_ = JNPAD_MODE.getValue(); 
    if (mode != mode_) {
      switch (mode_) {
        case DISTRACTION_FREE:
          TAB_TABBED.setValue(false);
          STATUSBAR_VISIBLE.setValue(false);
          GUTTER_VISIBLE.setValue(false);
          MARKER_VISIBLE.setValue(false);
          setBooleanProp("jnpad.maximize", true);
          TEXT_LINE_WRAP.setValue(true);
          ACTIVE_LINE_VISIBLE.setValue(false);
          setColorScheme("dark");
          JNPAD_LAF.setValue(LAFUtils.LAF_KEY_JNPAD_DARK);
          break;
        default:
          TAB_TABBED.setToDefault();
          STATUSBAR_VISIBLE.setToDefault();
          GUTTER_VISIBLE.setToDefault();
          MARKER_VISIBLE.setToDefault();
          TEXT_LINE_WRAP.setToDefault();
          ACTIVE_LINE_VISIBLE.setToDefault();
          if (mode == Mode.DISTRACTION_FREE) {
            setColorScheme(getColorSchemeByLAF(Config.JNPAD_LAF.getValue()));
            JNPAD_LAF.setToDefault();
          }
          break;
      }
    }
  }

  /**
   * Adjust post laf changed.
   */
  private static void adjustPostLAFChanged() {
    if (LOGGER.isLoggable(Level.CONFIG)) 
      LOGGER.config("-- adjustPostLAFChanged --");
    String lafKey = LAFUtils.getCurrentLAFKey();
    String laf = Config.JNPAD_LAF.getValue();
    if (!lafKey.equals(laf)) {
      setColorScheme(getColorSchemeByLAF(laf));
    }
  }
  
  /**
   * Gets the color scheme by laf.
   *
   * @param lafKey the laf key
   * @return the color scheme by laf
   */
  private static String getColorSchemeByLAF(String lafKey) {
    String colorscheme;

    if (LAFUtils.LAF_KEY_JNPAD_LIGHT.equals(lafKey)) {
      colorscheme = "jnpad";
    }
    else if (LAFUtils.LAF_KEY_JNPAD_DARK.equals(lafKey)) {
      switch (JNPAD_MODE.getValue()) {
        case DISTRACTION_FREE:
          colorscheme = "black";
          break;
        default:
          colorscheme = "dark";
          break;
      }
    }
    else if (LAFUtils.LAF_KEY_STEEL.equals(lafKey)) {
      colorscheme = "gray";
    }
    else if (LAFUtils.LAF_KEY_NATIVE.equals(lafKey)) {
      if (Platform.isWindows)
        colorscheme = "default";
      else if (Platform.isMac)
        colorscheme = "light";
      else
        colorscheme = "jnpad";
    }
    else if (LAFUtils.LAF_KEY_JAVA.equals(lafKey) ||
             LAFUtils.METAL_LAF_CLASS_NAME.equals(lafKey) ||
             LAFUtils.LAF_KEY_OCEAN2.equals(lafKey)) {
      colorscheme = "light";
    }
    else if (LAFUtils.WINDOWS_LAF_CLASS_NAME.equals(lafKey) ||
             LAFUtils.WINDOWS_CLASSIC_LAF_CLASS_NAME.equals(lafKey)) {
      colorscheme = "default";
    }
    else if (LAFUtils.NIMBUS_LAF_CLASS_NAME.equals(lafKey)) {
      colorscheme = "cobalt";
    }
    else if (LAFUtils.MOTIF_LAF_CLASS_NAME.equals(lafKey)) {
      colorscheme = "plastic";
    }
    else if (LAFUtils.GTK_LAF_CLASS_NAME.equals(lafKey)) {
      colorscheme = "jnpad";
    }
    else if (LAFUtils.MAC_LAF_CLASS_NAME.equals(lafKey) ||
             LAFUtils.AQUA_LAF_CLASS_NAME.equals(lafKey) ||
             LAFUtils.AQUA_LAF_CLASS_NAME_6.equals(lafKey)) {
      colorscheme = "light";
    }
    else {
      colorscheme = "default";
    }
    
    return colorscheme;
  }
  
  /**
   * Sets the color scheme.
   *
   * @param colorscheme the new color scheme
   */
  private static void setColorScheme(String colorscheme) {
    final String path = COLORSCHEMES_DIR + DIR_SEPARATOR + colorscheme + ".properties";
    
    Properties prop = new Properties();
    BufferedReader in = null;
    try {
      in = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
      prop.load(in);
    }
    catch (IOException ex) {
      LOGGER.log(Level.WARNING, ex.getMessage(), ex);
      return;
    }
    finally {
      try {
        if (in != null) {
          in.close();
        }
      }
      catch (IOException ex) {
        LOGGER.log(Level.WARNING, ex.getMessage(), ex);
      }
    }
    putAll(prop);
    JNPAD_COLORSCHEME.setValue(colorscheme);
  }
  
  /**
   * Checks if is using custom shortcuts.
   *
   * @return true, if is using custom shortcuts
   */
  public static boolean isUsingCustomShortcuts() {
    return USE_CUSTOM_SHORTCUTS.getValue();
  }

  /**
   * Write line separator prop.
   *
   * @param line_separator the line_separator
   * @return the string
   */
  public static String writeLineSeparatorProp(String line_separator) {
    if (line_separator == null)
      return AUTO;
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < line_separator.length(); i++) {
      sb.append("\\".concat(Integer.toString(line_separator.charAt(i)))); 
    }
    return sb.toString();
  }

  /**
   * Write list prop.
   *
   * @param list the list
   * @return the string
   */
  public static String writeListProp(List<?> list) {
    StringBuilder sb = new StringBuilder();
    for (Iterator<?> it = list.iterator(); it.hasNext(); ) {
      sb.append(it.next().toString());
      if (it.hasNext()) {
        sb.append(";"); 
      }
    }
    return sb.toString();
  }

  /**
   * Write jNPad input prop.
   *
   * @param in the in
   * @return the string
   */
  public static String writeJNPadInputProp(JNPadInput in) {
    StringBuilder sb = new StringBuilder();
    
    sb.append(in.getPath()).append(COMMA_STRING).
       append(IntProp.format(in.getCaretPosition())).append(COMMA_STRING).
       append(BooleanProp.format(in.isReadOnly())).append(COMMA_STRING).
       append(BooleanProp.format(in.isCurrent())).append(COMMA_STRING).
       append(BooleanProp.format(in.isLineWrapped()));

    if(Utilities.isNotEmptyString(in.getSplitConfig())) {
      sb.append(COMMA_STRING).append(in.getSplitConfig());
    }
    
    return sb.toString();
  }

  /**
   * Write jNPad input list prop.
   *
   * @param list the list
   * @return the string
   */
  public static String writeJNPadInputListProp(List<JNPadInput> list) {
    StringBuilder sb = new StringBuilder();
    for (Iterator<JNPadInput> it = list.iterator(); it.hasNext(); ) {
      JNPadInput in = it.next();
      sb.append(writeJNPadInputProp(in));
      if (it.hasNext()) {
        sb.append(";"); 
      }
    }
    return sb.toString();
  }

  /**
   * Save default properties.
   */
  public static void saveDefaultProperties() {
    PrintWriter pw = null;
    try {
      pw = new PrintWriter(new BufferedWriter(new FileWriter(DEFAULTS_FILE_PATH)));

      pw.println("# =========================================================");
      pw.println("# " + JNPad.TITLE + " Default Config");
      pw.println("# =========================================================");
      pw.println();
      pw.println("# Generals:");
	  pw.println(JNPAD_X);
	  pw.println(JNPAD_Y);
      pw.println(JNPAD_WIDTH);
	  pw.println(JNPAD_HEIGHT);
	  pw.println(JNPAD_MAXIMIZE);
	  pw.println(JNPAD_COLORSCHEME);
      pw.println(JNPAD_KEYMAP);
      pw.println(JNPAD_LAF);
	  pw.println(JNPAD_LAF_BOLD_METAL);
	  pw.println(JNPAD_LANG);
	  pw.println(JNPAD_MODE);
	  pw.println(JNPAD_ANTIALIAS);
	  pw.println();
	  pw.println(UNDO_LIMIT);
	  pw.println(USE_CUSTOM_SHORTCUTS);
	  pw.println(CHOOSER_FILE_DIRECTORY);
	  pw.println(FILES_RECENT_MAX);
	  pw.println(SECURE_SAVE);
	  pw.println(FILE_ENCODING);
	  pw.println(REMOVE_END_SPACES);
	  pw.println(STATUSBAR_VISIBLE);
	  pw.println(FINDRESULTS_VISIBLE);
      pw.println(HEAP_MONITOR_VISIBLE);
	  pw.println(DATE_FORMAT);
	  pw.println(TAB_LAYOUT_POLICY);
	  pw.println(TAB_PLACEMENT);
	  pw.println(TAB_FILE_EXTENSION);
	  pw.println(TAB_FILE_ICON);
	  pw.println(TAB_CLOSE_BUTTON);
	  pw.println(TAB_ROUNDED);
	  pw.println(TAB_TABBED);
	  pw.println(SPLIT_CONTINUOUS_LAYOUT);
	  pw.println(SPLIT_DIVIDER_SIZE);
	  pw.println();
	  pw.println();
	  pw.println("# Toolbars:");
	  pw.println(TOOLBAR_VISIBLE);
	  pw.println(TOOLBAR_ROWS);
	  pw.println(TOOLBARS_FILE_SELECTED);
	  pw.println(TOOLBARS_EDIT_RECANTATION_SELECTED);
	  pw.println(TOOLBARS_EDIT_CLIPBOARD_SELECTED);
	  pw.println(TOOLBARS_EDIT_SELECTION_SELECTED);
	  pw.println(TOOLBARS_EDIT_DELETION_SELECTED);
	  pw.println(TOOLBARS_SEARCH_SELECTED);
	  pw.println(TOOLBARS_VIEW_SELECTED);
	  pw.println(TOOLBARS_FORMAT_SELECTED);
	  pw.println(TOOLBARS_WINDOWS_SELECTED);
	  pw.println();
	  pw.println();
	  pw.println("# Titled Label:");
	  pw.println(TITLED_LABEL_FONT);
	  pw.println(TITLED_LABEL_FOREGROUND);
	  pw.println(TITLED_LABEL_GRADIENT1);
	  pw.println(TITLED_LABEL_GRADIENT2);
	  pw.println(TITLED_LABEL_ORIENTATION);
	  pw.println();
	  pw.println();
	  pw.println("# Text Pane:");
	  pw.println(TEXT_FONT);
	  pw.println(TEXT_BACKGROUND);
	  pw.println(TEXT_FOREGROUND);
	  pw.println(TEXT_SELECTION_BACKGROUND);
	  pw.println(TEXT_SELECTION_FOREGROUND);
	  pw.println(TEXT_CARET_INS_COLOR);
	  pw.println(TEXT_CARET_OVR_COLOR);
	  pw.println(TEXT_TAB_SIZE);
	  pw.println(TEXT_TAB_ENABLED);
	  pw.println(TEXT_AUTO_INDENT);
      pw.println(TEXT_AUTO_CLOSE_BRACKETS);
	  pw.println(TEXT_RIGHT_MARGIN_LINE_VISIBLE);
	  pw.println(TEXT_RIGHT_MARGIN_LINE_WIDTH);
	  pw.println(TEXT_RIGHT_MARGIN_LINE_COLOR);
	  pw.println(TEXT_LINE_WRAP);
	  pw.println(TEXT_AUTOCOMPLETION_ENABLED);
	  pw.println(TEXT_AUTOCOMPLETION_ALL);
	  pw.println(TEXT_AUTOCOMPLETION_TRIGGER);
	  pw.println(TEXT_DELIMITERS);
      pw.println();
      pw.println(SYNTAX_CLASSIFY_ENABLED);
      pw.println(SYNTAX_KNOWN_ENABLED);
      pw.println(SYNTAX_COMMENT_COLOR);
      pw.println(SYNTAX_COMMENT_STYLE);
      pw.println(SYNTAX_COMMENT2_COLOR);
      pw.println(SYNTAX_COMMENT2_STYLE);
      pw.println(SYNTAX_COMMENT3_COLOR);
      pw.println(SYNTAX_COMMENT3_STYLE);
      pw.println(SYNTAX_COMMENT4_COLOR);
      pw.println(SYNTAX_COMMENT4_STYLE);
      pw.println(SYNTAX_STRING_COLOR);
      pw.println(SYNTAX_STRING_STYLE);
      pw.println(SYNTAX_NUMBER_COLOR);
      pw.println(SYNTAX_KEYWORD_COLOR);
      pw.println(SYNTAX_KEYWORD_STYLE);
      pw.println(SYNTAX_KEYWORD2_COLOR);
      pw.println(SYNTAX_KEYWORD2_STYLE);
      pw.println(SYNTAX_KEYWORD3_COLOR);
      pw.println(SYNTAX_KEYWORD3_STYLE);
      pw.println(SYNTAX_KEYWORD4_COLOR);
      pw.println(SYNTAX_KEYWORD4_STYLE);
      pw.println(SYNTAX_KEYWORD5_COLOR);
      pw.println(SYNTAX_KEYWORD5_STYLE);
      pw.println(SYNTAX_KEYWORD6_COLOR);
      pw.println(SYNTAX_KEYWORD6_STYLE);
      pw.println(SYNTAX_KEYWORD7_COLOR);
      pw.println(SYNTAX_KEYWORD7_STYLE);
      pw.println(SYNTAX_KEYWORD8_COLOR);
      pw.println(SYNTAX_KEYWORD8_STYLE);
      pw.println(SYNTAX_KEYWORD9_COLOR);
      pw.println(SYNTAX_KEYWORD9_STYLE);
      pw.println(SYNTAX_OPERATOR_COLOR);
      pw.println(SYNTAX_OPERATOR_STYLE);
      pw.println(SYNTAX_BRACKET_COLOR);
      pw.println(SYNTAX_BRACKET_STYLE);
      pw.println("# --- [v0.3] ---");
      pw.println(SYNTAX_COMMENT1_COLOR);
      pw.println(SYNTAX_COMMENT1_STYLE);
      pw.println(SYNTAX_CLASSIFY2_ENABLED);
      pw.println(SYNTAX_KEYWORD10_STYLE);
      pw.println(SYNTAX_KEYWORD11_STYLE);
      pw.println("# ---");
	  pw.println();
	  pw.println(ACTIVE_LINE_VISIBLE);
	  pw.println(ACTIVE_LINE_COLOR);
	  pw.println(BOOKMARKING_ENABLED);
	  pw.println(OCCURRENCES_HIGHLIGHTER_VISIBLE);
	  pw.println(OCCURRENCES_HIGHLIGHTER_COLOR);
      pw.println(OCCURRENCES_HIGHLIGHTER_BORDER_COLOR);
	  pw.println(OCCURRENCES_CIRCULAR_NAVIGATION);
	  pw.println(BOOKMARKS_CIRCULAR_NAVIGATION);
	  pw.println(SEARCH_HIGHLIGHTER_COLOR);
	  pw.println(SEARCH_HIGHLIGHTER_BORDER_COLOR);
	  pw.println(BRACKET_HIGHLIGHTER_VISIBLE);
	  pw.println(BRACKET_HIGHLIGHTER_COLOR);
	  pw.println(VIEW_ACTION_SCOPE);
	  pw.println();
	  pw.println();
	  pw.println("# Gutter:");
	  pw.println(GUTTER_VISIBLE);
	  pw.println(GUTTER_BACKGROUND);
	  pw.println(GUTTER_FOREGROUND);
	  pw.println(GUTTER_CURRENT_FOREGROUND);
	  pw.println(GUTTER_CURRENT_BACKGROUND);
	  pw.println(GUTTER_CURRENT_BACKGROUND_ENABLED);
	  pw.println(GUTTER_UPDATE_FONT);
	  pw.println(GUTTER_BORDER_GAP);
	  pw.println(GUTTER_BORDER_WIDTH);
	  pw.println(GUTTER_BORDER_VISIBLE);
	  pw.println(GUTTER_BORDER_COLOR);
	  pw.println(GUTTER_SELECTION_COLOR);
	  pw.println(GUTTER_SELECTION_BORDER_COLOR);
	  pw.println(GUTTER_SELECTION_WIDTH);
	  pw.println(GUTTER_SELECTION_BORDER);
	  pw.println(GUTTER_BOOKMARK_BACKGROUND);
	  pw.println(GUTTER_BOOKMARK_COLOR);
	  pw.println(GUTTER_BOOKMARK_BORDER_COLOR);
      pw.println(GUTTER_BOOKMARK_WIDTH);
      pw.println(GUTTER_BOOKMARK_GAP);
	  pw.println(GUTTER_BRACKET_SCOPE_VISIBLE);
	  pw.println(GUTTER_BRACKET_SCOPE_COLOR);
	  pw.println();
	  pw.println();
	  pw.println("# Mark Strip:");
      pw.println(MARKER_VISIBLE);
	  pw.println(MARKER_OCCURRENCE_COLOR);
	  pw.println(MARKER_OCCURRENCE_BORDER_COLOR);
	  pw.println(MARKER_SEARCH_COLOR);
	  pw.println(MARKER_SEARCH_BORDER_COLOR);
	  pw.println(MARKER_BOOKMARK_COLOR);
	  pw.println(MARKER_BOOKMARK_BORDER_COLOR);
	  pw.println(MARKER_CARET_COLOR);
	  pw.println(MARKER_PREFERRED_WIDTH);
      pw.println();
      pw.println();
      pw.println("# Minimap [v0.3]: ");
      pw.println(MINIMAP_VIEWRECT_VISIBLE);
      pw.println(MINIMAP_VIEWRECT_COLOR);
      pw.println(MINIMAP_VIEWRECT_BORDER_COLOR);
      pw.println(MINIMAP_FONT_SIZE);
      pw.println();
      pw.println();
	  pw.println("# File Browser:");
	  pw.println(BROWSER_NORMAL_FONT);
	  pw.println(BROWSER_BOLD_FONT);
	  pw.println(BROWSER_DEVICE_FONT);
	  pw.println(BROWSER_DIR_FOREGROUND);
	  pw.println(BROWSER_EXEC_FOREGROUND);
	  pw.println(BROWSER_LINK_FOREGROUND);
	  pw.println(BROWSER_COMP_FOREGROUND);
	  pw.println(BROWSER_IMAGE_FOREGROUND);
	  pw.println(BROWSER_AUDIO_FOREGROUND);
	  pw.println(BROWSER_COLORS_ENABLED);
	  pw.println(BROWSER_HUMAN_READABLE);
	  pw.println(BROWSER_CLASSIFY);
	  pw.println(BROWSER_INFO_VISIBLE);
	  pw.println(BROWSER_TRANSPARENCY);
	  pw.println(BROWSER_LOCATION_HORIZONTAL);
	  pw.println(BROWSER_LOCATION_VERTICAL);
	  pw.println();
	  pw.println();
	  pw.println("# Perform Action:");
	  pw.println(PERFORM_ACTION_TRANSPARENCY);
	  pw.println(PERFORM_ACTION_LOCATION_HORIZONTAL);
	  pw.println(PERFORM_ACTION_LOCATION_VERTICAL);
	  pw.println(PERFORM_ACTION_COLUMNS);
	  pw.println();
	  pw.println();
	  pw.println("# Find:");
	  pw.println(FIND_LOOKIN);
	  pw.println(FIND_FROMCURSOR);
	  pw.println(FIND_MATCH_CASE);
	  pw.println(FIND_MATCH_WHOLEWORD);
	  pw.println(FIND_DIRECTION_DOWN);
      pw.println(FIND_HIGHLIGHT_ALL);
      pw.println(FIND_REGEX);
	  pw.println();
	  pw.println();
	  pw.println("# Replace:");
      pw.println(REPLACE_LOOKIN);
      pw.println(REPLACE_FROMCURSOR);
      pw.println(REPLACE_MATCH_CASE);
      pw.println(REPLACE_MATCH_WHOLEWORD);
      pw.println(REPLACE_DIRECTION_DOWN);
      pw.println(REPLACE_HIGHLIGHT_ALL);
      pw.println(REPLACE_REGEX);
	  pw.println();
	  pw.println();
	  pw.println("# Print:");
	  pw.println(PRINT_LINE_NUMBERS);
	  pw.println(PRINT_HEADER);
	  pw.println(PRINT_WRAP_TEXT);
	  pw.println(PRINT_FONT);
    }
    catch (Exception ex) {
      LOGGER.log(Level.WARNING, ex.getMessage(), ex);
    }
    finally {
      if (pw != null) {
        try {
          pw.close();
        }
        catch (Exception ex) {
          //ignored
        }
      }
    }
  }
  
  /**
   * Adds the prop listener.
   *
   * @param <V> the value type
   * @param prop the prop
   * @param listener the listener
   */
  public static <V> void addPropListener(Prop<V> prop, PropChangeListener<V> listener) {
    prop.addPropListener(listener);
  }

  /**
   * Removes the prop listener.
   *
   * @param <V> the value type
   * @param prop the prop
   * @param listener the listener
   */
  public static <V> void removePropListener(Prop<V> prop, PropChangeListener<V> listener) {
    prop.removePropListener(listener);
  }
  
  static {
    options  = new Properties();
    defaults = new Properties();
    changes  = new Properties();

    FILE_ENCODING = new StringProp("file.encoding", GUIUtilities.getJNPadDefaultEncoding());

    loadProperties();

    if (!isMininalistMode()) {
      loadDefaultProperties();
    }

    loadSearchHistorial();

    initDirectories();

    try {
      String lang = JNPAD_LANG.getValue(); 
      locale = JNPAD_LANG.getDefault().equals(lang) ? Locale.getDefault() : new Locale(lang);
    }
    catch (Exception ex) {
      locale = Locale.getDefault();
      LOGGER.warning(ex.getMessage());
    }

    // --- text font ---
    String fontNames[] = {
        "Courier New", "Courier new", "courier new", "CourierNew", "Couriernew",
        "couriernew", "Courier", "courier", "DialogInput", "Dialoginput",
        "dialoginput", "Dialog Input", "Dialog input", "dialog input", "Dialog",
        "dialog", "Monospaced", "MonoSpaced", "monospaced", "Mono spaced",
        "Mono Spaced", "mono spaced", "Monotxt", "MonoTxt", "monotxt",
        "Lucida Console", "lucida console", "LucidaConsole", "lucidaconsole"
    };

    Font font = new Font(fontNames[0], Font.PLAIN, 13);
    
    try {
      String[] names = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
      for (String fontName : fontNames) {
        if (Arrays.binarySearch(names, fontName) >= 0) {
          font = new Font(fontName, Font.PLAIN, 13);
          if (GUIUtilities.isValidFont(font)) {
            break;
          }
        }
      }
    }
    catch (Exception ex) {
      //ignored
    }
    
    TEXT_FONT = new FontProp("text.font", font);
    // ---
  }

}
