/*
 * PS3 Media Server, for streaming any medias to your PS3.
 * Copyright (C) 2008  A.Brochard
 *
 * 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; version 2
 * of the License only.
 *
 * 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.
 */
package net.pms.configuration;


import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import net.pms.io.SystemUtils;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.ConversionException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.event.ConfigurationListener;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.jna.Platform;
import net.pms.logging.PMSThresholdFilter;	//regzamod, add
import net.pms.PMS;

/**
 * Container for all configurable PMS settings. Settings are typically defined by three things:
 * a unique key for use in the configuration file "PMS.conf", a getter (and setter) method and
 * a default value. When a key cannot be found in the current configuration, the getter will
 * return a default value. Setters only store a value, they do not permanently save it to
 * file.
 */
public class PmsConfiguration {
	private static final int DEFAULT_PROXY_SERVER_PORT = -1;
	private static final int DEFAULT_SERVER_PORT = 5001;


	// MEncoder has a hardwired maximum of 8 threads for -lavcopts and -lavdopts:
	// https://code.google.com/p/ps3mediaserver/issues/detail?id=517
	private static final int MENCODER_MAX_THREADS = 8;

	private static final String KEY_ALTERNATE_SUBS_FOLDER = "alternate_subs_folder";
	private static final String KEY_ALTERNATE_THUMB_FOLDER = "alternate_thumb_folder";
	private static final String KEY_AUDIO_BITRATE = "audiobitrate";
	private static final String KEY_AUDIO_CHANNEL_COUNT = "audiochannels";
	private static final String KEY_AUDIO_RESAMPLE = "audio_resample";
	private static final String KEY_AUDIO_THUMBNAILS_METHOD = "audio_thumbnails_method";
	private static final String KEY_AUTO_UPDATE = "auto_update";
	private static final String KEY_AVISYNTH_CONVERT_FPS = "avisynth_convertfps";
	private static final String KEY_AVISYNTH_SCRIPT = "avisynth_script";
	private static final String KEY_BUFFER_TYPE = "buffertype";
	private static final String KEY_CHAPTER_INTERVAL = "chapter_interval";
	private static final String KEY_CHAPTER_SUPPORT = "chapter_support";
	private static final String KEY_CHARSET_ENCODING = "charsetencoding";
	private static final String KEY_CODEC_SPEC_SCRIPT = "codec_spec_script";
	private static final String KEY_DISABLE_FAKESIZE = "disable_fakesize";
	private static final String KEY_DVDISO_THUMBNAILS = "dvd_isos_thumbnails";
	private static final String KEY_EMBED_DTS_IN_PCM = "embed_dts_in_pcm";
	private static final String KEY_ENGINES = "engines";
	private static final String KEY_FFMPEG_ALTERNATIVE_PATH = "alternativeffmpegpath";
	private static final String KEY_FFMPEG_SETTINGS = "ffmpeg";
	private static final String KEY_FIX_25FPS_AV_MISMATCH = "fix_25fps_av_mismatch";
	private static final String KEY_FORCETRANSCODE = "forcetranscode";
	private static final String KEY_HIDE_EMPTY_FOLDERS = "hide_empty_folders";
	private static final String KEY_HIDE_ENGINENAMES = "hide_enginenames";
	private static final String KEY_HIDE_EXTENSIONS = "hide_extensions";
	private static final String KEY_HIDE_MEDIA_LIBRARY_FOLDER = "hide_media_library_folder";
	private static final String KEY_HIDE_TRANSCODE_FOLDER = "hide_transcode_folder";
	private static final String KEY_HIDE_VIDEO_SETTINGS = "hidevideosettings";
	private static final String KEY_HTTP_ENGINE_V2 = "http_engine_v2";
	private static final String KEY_IP_FILTER = "ip_filter";
	private static final String KEY_IPHOTO_ENABLED = "iphoto";
	private static final String KEY_APERTURE_ENABLED = "aperture";
	private static final String KEY_ITUNES_ENABLED = "itunes";
	private static final String KEY_LANGUAGE = "language";
	private static final String KEY_LOGGING_LEVEL = "level";
	private static final String KEY_MAX_AUDIO_BUFFER = "maxaudiobuffer";
	private static final String KEY_MAX_BITRATE = "maximumbitrate";
	private static final String KEY_MAX_MEMORY_BUFFER_SIZE = "maxvideobuffer";
	private static final String KEY_MENCODER_AC3_FIXED = "mencoder_ac3_fixed";
	private static final String KEY_MENCODER_ASS_DEFAULTSTYLE = "mencoder_ass_defaultstyle";
	private static final String KEY_MENCODER_ASS_MARGIN = "mencoder_ass_margin";
	private static final String KEY_MENCODER_ASS = "mencoder_ass";
	private static final String KEY_MENCODER_ASS_OUTLINE = "mencoder_ass_outline";
	private static final String KEY_MENCODER_ASS_SCALE = "mencoder_ass_scale";
	private static final String KEY_MENCODER_ASS_SHADOW = "mencoder_ass_shadow";
	private static final String KEY_MENCODER_AUDIO_LANGS = "mencoder_audiolangs";
	private static final String KEY_MENCODER_AUDIO_SUB_LANGS = "mencoder_audiosublangs";
	private static final String KEY_MENCODER_DECODE = "mencoder_decode";
	private static final String KEY_MENCODER_DISABLE_SUBS = "mencoder_disablesubs";
	private static final String KEY_MENCODER_FONT_CONFIG = "mencoder_fontconfig";
	private static final String KEY_MENCODER_FONT = "mencoder_font";
	private static final String KEY_MENCODER_FORCE_FPS = "mencoder_forcefps";
	private static final String KEY_MENCODER_INTELLIGENT_SYNC = "mencoder_intelligent_sync";
	private static final String KEY_MENCODER_MAIN_SETTINGS = "mencoder_encode";
	private static final String KEY_MENCODER_MAX_THREADS = "mencoder_max_threads";
	private static final String KEY_MENCODER_MT = "mencoder_mt";
	private static final String KEY_MENCODER_MUX_COMPATIBLE = "mencoder_mux_compatible";
	private static final String KEY_MENCODER_NOASS_BLUR = "mencoder_noass_blur";
	private static final String KEY_MENCODER_NOASS_OUTLINE = "mencoder_noass_outline";
	private static final String KEY_MENCODER_NOASS_SCALE = "mencoder_noass_scale";
	private static final String KEY_MENCODER_NOASS_SUBPOS = "mencoder_noass_subpos";
	private static final String KEY_MENCODER_NO_OUT_OF_SYNC = "mencoder_nooutofsync";
	private static final String KEY_MENCODER_OVERSCAN_COMPENSATION_WIDTH = "mencoder_overscan_compensation_width";
	private static final String KEY_MENCODER_OVERSCAN_COMPENSATION_HEIGHT = "mencoder_overscan_compensation_height";
	private static final String KEY_MENCODER_REMUX_AC3 = "mencoder_remux_ac3";
	private static final String KEY_MENCODER_REMUX_MPEG2 = "mencoder_remux_mpeg2";
	private static final String KEY_MENCODER_SCALER = "mencoder_scaler";
	private static final String KEY_MENCODER_SCALEX = "mencoder_scalex";
	private static final String KEY_MENCODER_SCALEY = "mencoder_scaley";
	private static final String KEY_MENCODER_SUB_CP = "mencoder_subcp";
	private static final String KEY_MENCODER_SUB_FRIBIDI = "mencoder_subfribidi";
	private static final String KEY_MENCODER_SUB_LANGS = "mencoder_sublangs";
	private static final String KEY_MENCODER_USE_PCM = "mencoder_usepcm";
	private static final String KEY_MENCODER_VOBSUB_SUBTITLE_QUALITY = "mencoder_vobsub_subtitle_quality";
	private static final String KEY_MENCODER_YADIF = "mencoder_yadif";
	private static final String KEY_MINIMIZED = "minimized";
	private static final String KEY_MIN_MEMORY_BUFFER_SIZE = "minvideobuffer";
	private static final String KEY_MIN_STREAM_BUFFER = "minwebbuffer";
	private static final String KEY_MIN_STREAM_BUFFER_SECONDARY = "minwebbuffer_secondary";
	private static final String KEY_MUX_ALLAUDIOTRACKS = "tsmuxer_mux_all_audiotracks";
	private static final String KEY_NETWORK_INTERFACE = "network_interface";
	private static final String KEY_NOTRANSCODE = "notranscode";
	private static final String KEY_NUMBER_OF_CPU_CORES = "nbcores";
	private static final String KEY_OPEN_ARCHIVES = "enable_archive_browsing";
	private static final String KEY_OVERSCAN = "mencoder_overscan";
	private static final String KEY_PLUGIN_DIRECTORY = "plugins";
	private static final String KEY_PREVENTS_SLEEP = "prevents_sleep_mode";
	private static final String KEY_PROFILE_NAME = "name";
	private static final String KEY_PROXY_SERVER_PORT = "proxy";
	private static final String KEY_SERVER_HOSTNAME = "hostname";
	private static final String KEY_SERVER_PORT = "port";
	private static final String KEY_SHARES = "shares";
	private static final String KEY_SKIP_LOOP_FILTER_ENABLED = "skiploopfilter";
	private static final String KEY_SKIP_NETWORK_INTERFACES = "skip_network_interfaces";
	private static final String KEY_SORT_METHOD = "key_sort_method";
	private static final String KEY_SUBS_COLOR = "subs_color";
	private static final String KEY_TEMP_FOLDER_PATH = "temp";
	private static final String KEY_THUMBNAIL_SEEK_POS = "thumbnail_seek_pos";
	private static final String KEY_THUMBNAILS_ENABLED = "thumbnails";
	private static final String KEY_IMAGE_THUMBNAILS_ENABLED = "image_thumbnails";
	private static final String KEY_TRANSCODE_BLOCKS_MULTIPLE_CONNECTIONS = "transcode_block_multiple_connections";
	private static final String KEY_TRANSCODE_KEEP_FIRST_CONNECTION = "transcode_keep_first_connection";
	private static final String KEY_TSMUXER_FORCEFPS = "tsmuxer_forcefps";
	private static final String KEY_TSMUXER_PREREMIX_AC3 = "tsmuxer_preremix_ac3";
	private static final String KEY_TURBO_MODE_ENABLED = "turbomode";
	private static final String KEY_USE_CACHE = "usecache";
	private static final String KEY_USE_MPLAYER_FOR_THUMBS = "use_mplayer_for_video_thumbs";
	private static final String KEY_USE_SUBTITLES = "autoloadsrt";
	private static final String KEY_VIDEOTRANSCODE_START_DELAY = "key_videotranscode_start_delay";
	private static final String KEY_VIRTUAL_FOLDERS = "vfolders";
	private static final String KEY_UPNP_PORT = "upnp_port";
	private static final String KEY_UUID = "uuid";
	private static final String KEY_MENCODER_FORCED_SUB_LANG = "forced_sub_lang";
	private static final String KEY_MENCODER_FORCED_SUB_TAGS = "forced_sub_tags";
	
	//---- regzamod add start ---------------------
	private static final String KEY_RZ_MOD = "rz_mod";		//regzamod, regza_mod
	private static final String KEY_RZ_TEST = "rz_test";	//regzamod, test_mode
	private static final String KEY_RZ_DEBUG = "rz_debug";	//regzamod, debug print
	private static final String KEY_RZ_TRACE = "rz_trace";	//regzamod, debug print
	private static final String KEY_RZ_DUMP_UA_HEADER = "rz_dump_ua_header";	//regzamod, Dump UserAgentHeader
	private static final String KEY_RZ_STREAM_DUMP = "rz_stream_dump";	//regzamod, stream dump 
	private static final String KEY_RZ_PLAYLIST_ENCODE = "rz_playlist_encode";	// regzamod, Playlist Encode
	private static final String KEY_RZ_METAFILE_ENCODE = "rz_metafile_encode";	// regzamod, Metafile Encode
	private static final String KEY_RZ_LOGBACK_LEVEL_DISP = "rz_logback_level_disp";	// for logdisp
	private static final String KEY_RZ_LOGBACK_LEVEL_FILE = "rz_logback_level_file";	// for logfile
	private static final String KEY_RZ_BUFFER_CHECK_INTERVAL   = "rz_buffer_check_interval";	// unfreed buffr chek
	private static final String KEY_RZ_FORCE_GC_INTERVAL  = "rz_force_gc_interval";	// force cyclic gc
	private static final String KEY_RZ_GC_ON_STOP_PLAYING = "rz_gc_on_stop_playing";	// 
	private static final String KEY_RZ_NETTY_CONN_MAX     = "rz_netty_conn_max";	// 
	private static final String KEY_RZ_DIRECT_SEEK        = "rz_direct_seek";	// 
	private static final String KEY_RZ_BUFFER_SEEK        = "rz_buffer_seek";	// 
	private static final String KEY_RZ_BUFFER_ROLLBACK    = "rz_buffer_rollback";	// 
	private static final String KEY_RZ_FFMPEG_ABITRATE    = "rz_ffmpeg_abitrate";	// 
	private static final String KEY_RZ_DUPMSG_SUPP_TIME   = "rz_dupmsg_supp_time";	// 
	private static final String KEY_RZ_FFMPEG_PATH        = "rz_ffmpeg_path";	// 
	private static final String KEY_RZ_MENCODER_PATH      = "rz_mencoder_path";	// 
	//private static final String KEY_RZ_FFMPEG_PATH_NEW    = "rz_ffmpeg_path_new";	// 
	//private static final String KEY_RZ_MENCODER_PATH_NEW  = "rz_mencoder_path_new";	// 
		
	private static final String KEY_RZ_SORT_WHEN_REFRESH= "rz_sort_when_refresh";	// sort when refresh
	private static final String KEY_RZ_METAFILE_SUFFIX= "rz_metafile_suffix";		// suffix of playMetafile
	private static final String KEY_RZ_PROFILE_ENABLED= "rz_profile_enabled";		// playProfile enabled 
	private static final String KEY_RZ_PROFILE_SUFFIX= "rz_profile_suffix";		// suffix of playProfile
	private static final String KEY_RZ_PROFILE_FF= "rz_profile_ff";		// profile for folder
	private static final String KEY_RZ_DISP_SORT_MENU= "rz_disp_sort_menu";	
	private static final String KEY_RZ_CLOSE_AFTER_SEND= "rz_close_after_send";	
	private static final String KEY_RZ_MENU_TYPE= "rz_menu_type";
	private static final String KEY_RZ_SORT_MENU_TYPE= "rz_sort_menu_type";
	private static final String KEY_RZ_UPDATE_CHECK_NLS= "rz_update_check_nls";
	private static final String KEY_RZ_UPDATE_CHECK_PLS= "rz_update_check_pls";
	private static final String KEY_RZ_UPDATE_CHECK_MIN= "rz_update_check_min";  //minimum interval(msec)

	private static final String KEY_RZ_WEB_REFRESH_INTERVAL= "rz_web_refresh_interval";	// Web contents 
	private static final String KEY_RZ_WEB_FORCE_RESIZE= "rz_web_force_resize";
	private static final String KEY_RZ_WEB_RESIZE_W= "rz_web_resize_w";
	private static final String KEY_RZ_WEB_RESIZE_H= "rz_web_resize_h";
	private static final String KEY_RZ_WEB_REMUX= "rz_web_remux";
	private static final String KEY_RZ_WEB_QUALITY= "rz_web_quality";
	private static final String KEY_RZ_WEB_SORT_TYPE= "rz_web_sort_type";
	private static final String KEY_RZ_WEB_DURATION_ADD= "rz_web_duration_add";
	private static final String KEY_RZ_WEB_MEDIAINFO_PATH= "rz_web_mediainfo_path";
	private static final String KEY_RZ_WEB_RESOLVE_INTVL= "rz_web_resolve_intvl";
	private static final String KEY_RZ_WEB_RESOLVE_DELAY="rz_web_resolve_delay";

	private static final String KEY_RZ_AUDIO_AS_VIDEO= "rz_audio_as_video";
	private static final String KEY_RZ_AAV_PLAYER_PATH= "rz_aav_player_path";
	private static final String KEY_RZ_AAV_START_DELAY= "rz_aav_start_delay";
	private static final String KEY_RZ_AAV_RESIZE_W= "rz_aav_resize_w";
	private static final String KEY_RZ_AAV_RESIZE_H= "rz_aav_resize_h";
	private static final String KEY_RZ_AAV_CLIP_PATH1= "rz_aav_clip_path1";
	private static final String KEY_RZ_AAV_CLIP_PATH2= "rz_aav_clip_path2";
	private static final String KEY_RZ_AAV_CLIP_INTERVAL= "rz_aav_clip_interval";
	private static final String KEY_RZ_AAV_CLIP_SELTYPE= "rz_aav_clip_seltype";
	private static final String KEY_RZ_AAV_CAPTION= "rz_aav_caption";
	private static final String KEY_RZ_AAV_IMGFIT= "rz_aav_imgfit";
	
	private static final String KEY_RZ_IMAGE_AS_VIDEO= "rz_image_as_video";
	private static final String KEY_RZ_IAV_PLAYER_PATH= "rz_iav_player_path";
	private static final String KEY_RZ_IAV_CLIP_PATH1= "rz_iav_clip_path1";
	private static final String KEY_RZ_IAV_CLIP_PATH2= "rz_iav_clip_path2";
	private static final String KEY_RZ_IAV_CLIP_INTERVAL= "rz_iav_clip_interval";
	private static final String KEY_RZ_IAV_CLIP_SELTYPE= "rz_iav_clip_seltype";
	private static final String KEY_RZ_IAV_CAPTION= "rz_iav_caption";
	private static final String KEY_RZ_IAV_GAPLESS= "rz_iav_gapless";
	private static final String KEY_RZ_IAV_IMGFIT= "rz_iav_imgfit";
	
	private static final String KEY_RZ_RESUME_MODE= "rz_resume_mode";
	private static final String KEY_RZ_RESUME_PLAY_MIN_TIME1= "rz_resume_play_min_time1";
	private static final String KEY_RZ_RESUME_PLAY_MIN_TIME2= "rz_resume_play_min_time2";
	private static final String KEY_RZ_RESUME_REWIND_TIME= "rz_resume_rewind_time";
	private static final String KEY_RZ_RESUME_DURATION_DELTA= "rz_resume_duration_delta";
	private static final String KEY_RZ_RESUME_SORT_TYPE= "rz_resume_sort_type";
	private static final String KEY_RZ_RESUME_PER_FOLDER_WEB= "rz_resume_per_folder_web";
	private static final String KEY_RZ_RESNAME_PATHADD_ISO= "rz_resname_pathadd_iso";
	
	private static final String KEY_RZ_UNKNOWN_DURATION_MAX= "rz_unknown_duration_max";
	
	private static final String KEY_RZ_FORCE_MEM_FREE= "rz_force_mem_free";
	private static final String KEY_RZ_WAIT_STREAM_MAX_TIME= "rz_wait_stream_max_time";
	private static final String KEY_RZ_WAIT_STREAM_MAX_TIME2= "rz_wait_stream_max_time2";
	private static final String KEY_RZ_WAIT_STREAM_MIN_BUFF= "rz_wait_stream_min_buff";
	private static final String KEY_RZ_REPLY_PROCESSING= "rz_reply_processing";
	private static final String KEY_RZ_REPLY_ERROR= "rz_reply_error";

	private static final String KEY_RZ_ROOT_PER_SESSION= "rz_root_per_session";
	private static final String KEY_RZ_REND_SCRIPT_ENABLED= "rz_rend_script_enabled";
	private static final String KEY_RZ_SERVER_NAME= "rz_server_name";
	private static final String KEY_RZ_MACHINE_NAME= "rz_machine_name";

	private static final String KEY_RZ_KWDMENU_CONF= "rz_kwdmenu_conf";
	private static final String KEY_RZ_KWDLIST_CONF= "rz_kwdlist_conf";
	private static final String KEY_RZ_KWDLIST_UPDATE_PROG= "rz_kwdlist_update_prog";
	private static final String KEY_RZ_CLIPLIST_CONF= "rz_cliplist_conf";
	
	private static final String KEY_RZ_AUTO_SEARCH_LOCK= "rz_auto_search_lock";
	private static final String KEY_RZ_ACTION_BUTTON_TYPE= "rz_action_button_type";
	private static final String KEY_RZ_MINFO_MULTI= "rz_minfo_multi";  //Mediainfo by multi-threading 
	private static final String KEY_RZ_ITUNES_PARSE_MODE= "rz_itunes_parse_mode";  
	private static final String KEY_RZ_ITUNES_IGNORE_KINDS= "rz_itunes_ignore_kinds";  
	private static final String KEY_RZ_REND_OPT_SCRIPT= "rz_rend_opt_script";	
	private static final String KEY_RZ_THUMBNAILS_GETLATER= "rz_thumbnails_getlater";	
	
	private static final String KEY_RZ_MEDIA_PARSE_TYPE= "rz_media_parse_type";	
	private static final String KEY_RZ_MEDIA_PARSE_THREAD= "rz_media_parse_thread";	
	
	private static final String KEY_RZ_DLNA_PROF_CACHE= "rz_dlna_prof_cache";	
	private static final String KEY_RZ_UPNP_ENABLE= "rz_upnp_enable";	
	private static final String KEY_RZ_REND_JUDGE_TYPE= "rz_rend_judge_type";	
	private static final String KEY_RZ_PYTHON_PATH= "rz_python_path";
	private static final String KEY_RZ_USERDATA_PATH= "rz_userdata_path";
	
	//---- start waits
	private static final String KEY_RZ_DEF_START_WAIT="rz_def_startwait";
	private static final String KEY_RZ_TRANS_START_WAIT="rz_trans_startwait";
	private static final String KEY_RZ_REMUX_START_WAIT="rz_remux_startwait";
	private static final String KEY_RZ_WEB_START_WAIT="rz_web_startwait";
	private static final String KEY_RZ_AAV_START_WAIT="rz_aav_startwait";
	private static final String KEY_RZ_IAV_START_WAIT="rz_iav_startwait";
	
	
	//---- regzamod add end ---------------------

	// the name of the subdirectory under which PMS config files are stored for this build (default: "PMS for Regza").
	// see Build for more details
	private static final String PROFILE_DIRECTORY_NAME = Build.getProfileDirectoryName();

	// the default profile name displayed on the renderer
	private static String HOSTNAME;

	private static final String DEFAULT_AVI_SYNTH_SCRIPT =
		"#AviSynth script is now fully customisable !\n"
		+ "#You must use the following variables (\"clip\" being the avisynth variable of the movie):\n"
		+ "#<movie>: insert the complete DirectShowSource instruction [ clip=DirectShowSource(movie, convertfps) ]\n"
		+ "#<sub>: insert the complete TextSub/VobSub instruction if there's any detected srt/sub/idx/ass subtitle file\n"
		+ "#<moviefilename>: variable of the movie filename, if you want to do all this by yourself\n"
		+ "#Be careful, the custom script MUST return the clip object\n"
		+ "<movie>\n"
		+ "<sub>\n"
		+ "return clip";
	private static final String BUFFER_TYPE_FILE = "file";
	private static final int MAX_MAX_MEMORY_BUFFER_SIZE = 600;
	private static final char LIST_SEPARATOR = ',';
	private static final String KEY_FOLDERS = "folders";
	private final PropertiesConfiguration configuration;
	private final TempFolder tempFolder;
	private final ProgramPathDisabler programPaths;

	private final IpFilter filter = new IpFilter();
	private String temp_dir;

	/**
	 * The set of the keys defining when the HTTP server has to restarted due to a configuration change
	 */
	public static final Set<String> NEED_RELOAD_FLAGS = new HashSet<String>(
		Arrays.asList(
			KEY_ALTERNATE_THUMB_FOLDER,
			KEY_NETWORK_INTERFACE,
			KEY_IP_FILTER,
			KEY_SORT_METHOD,
			KEY_HIDE_EMPTY_FOLDERS,
			KEY_HIDE_TRANSCODE_FOLDER,
			KEY_HIDE_MEDIA_LIBRARY_FOLDER,
			KEY_OPEN_ARCHIVES,
			KEY_USE_CACHE,
			KEY_HIDE_ENGINENAMES,
			KEY_ITUNES_ENABLED,
			KEY_IPHOTO_ENABLED,
			KEY_APERTURE_ENABLED,
			KEY_ENGINES,
			KEY_FOLDERS,
			KEY_HIDE_VIDEO_SETTINGS,
			KEY_AUDIO_THUMBNAILS_METHOD,
			KEY_NOTRANSCODE,
			KEY_FORCETRANSCODE,
			KEY_SERVER_PORT,
			KEY_SERVER_HOSTNAME,
			KEY_CHAPTER_SUPPORT,
			KEY_HIDE_EXTENSIONS
		)
	);

	//--------------------------------------------------------------------------------------
	// Define System folder/file paths
	//--------------------------------------------------------------------------------------
	//--------------------------------------------------------------------------------------
	// 1) Base Config file
	//--------------------------------------------------------------------------------------
	/*
		The following code enables a single setting - PMS_PROFILE - to be used to
		initialize PROFILE_PATH i.e. the path to the current session's profile (AKA PMS.conf).
		It also initializes PROFILE_DIRECTORY - i.e. the directory the profile is located in -
		which is needed for configuration-by-convention detection of WEB.conf (anything else?).

		While this convention - and therefore PROFILE_DIRECTORY - will remain,
		adding more configurables - e.g. web_conf = ... - is on the TODO list.

		PMS_PROFILE is read (in this order) from the property pms.profile.path or the
		environment variable PMS_PROFILE. If PMS is launched with the command-line option
		"profiles" (e.g. from a shortcut), it displays a file chooser dialog that
		allows the pms.profile.path property to be set. This makes it easy to run PMS
		under multiple profiles without fiddling with environment variables, properties or
		command-line arguments.

		1) if PMS_PROFILE is not set, PMS.conf is located in: 

			Windows:             %ALLUSERSPROFILE%\$build
			Mac OS X:            $HOME/Library/Application Support/$build
			Everything else:     $HOME/.config/$build

		- where $build is a subdirectory that ensures incompatible PMS builds don't target/clobber
		the same configuration files. The default value for $build is "PMS". Other builds might use e.g.
		"PMS Rendr Edition" or "pms-mlx".

		2) if a relative or absolute *directory path* is supplied (the directory must exist),
		it is used as the profile directory and the profile is located there under the default profile name (PMS.conf):

			PMS_PROFILE = /absolute/path/to/dir
			PMS_PROFILE = relative/path/to/dir # relative to the working directory

		Amongst other things, this can be used to restore the legacy behaviour of locating PMS.conf in the current
		working directory e.g.:

			PMS_PROFILE=. ./PMS.sh

		3) if a relative or absolute *file path* is supplied (the file doesn't have to exist),
		it is taken to be the profile, and its parent dir is taken to be the profile (i.e. config file) dir: 

			PMS_PROFILE = PMS.conf            # profile dir = .
			PMS_PROFILE = folder/dev.conf     # profile dir = folder
			PMS_PROFILE = /path/to/some.file  # profile dir = /path/to/
	 */
	private static final String DEFAULT_PROFILE_FILENAME = "PMS.conf";
	private static final String ENV_PROFILE_PATH = "PMS_PROFILE";
	private static final String PROPERTY_PROFILE_PATH = "pms.profile.path";
	
	private static final String PROFILE_BASE_DIRECTORY;	// ex. ~/parent_dir_of_conf/
	private static final String PROFILE_DIRECTORY; 		// ex. ~/parent_dir_of_conf/conf/
	private static final String PROFILE_PATH; 			// ex. ~/parent_dir_of_conf/conf/PMS.conf

	static {
		// first try the system property, typically set via the profile chooser
		String profile = System.getProperty(PROPERTY_PROFILE_PATH);

		// failing that, try the environment variable
		if (profile == null) {
			profile = System.getenv(ENV_PROFILE_PATH);
		}

		if (profile != null) {
			File f = new File(profile);

			// if it exists, we know whether it's a file or directory
			// otherwise, it must be a file since we don't autovivify directories

			if (f.exists() && f.isDirectory()) {
				PROFILE_DIRECTORY = FilenameUtils.normalize(f.getAbsolutePath());
				PROFILE_PATH = FilenameUtils.normalize(new File(f, DEFAULT_PROFILE_FILENAME).getAbsolutePath());
				PROFILE_BASE_DIRECTORY = PROFILE_DIRECTORY;
			} else { // doesn't exist or is a file (i.e. not a directory)
				PROFILE_DIRECTORY = FilenameUtils.normalize(f.getParentFile().getAbsolutePath());
				PROFILE_PATH = FilenameUtils.normalize(f.getAbsolutePath());
				PROFILE_BASE_DIRECTORY = PROFILE_DIRECTORY;
			}
		} else {
			String profileDir = null;
			
			if (Platform.isWindows()) {
				//profileDir = "./conf"; // i.e. current (working) directory/conf
				profileDir = "conf"; // i.e. current (working) directory/conf
				File fw=new File(profileDir);
				if(fw.isDirectory()) {
					//exists :noop
				}
				else {	//original
					String programData = System.getenv("ALLUSERSPROFILE");
					if (programData != null) {
						profileDir = String.format("%s/%s/conf", programData, PROFILE_DIRECTORY_NAME);
					} else {
						//profileDir = "./conf"; // i.e. current (working) directory/conf
						profileDir = "conf"; // i.e. current (working) directory
					}
				} 
			} else if (Platform.isMac()) {
				profileDir = String.format(
					"%s/%s/%s/conf",
					System.getProperty("user.home"),
					"/Library/Application Support",
					PROFILE_DIRECTORY_NAME
				);
			} else {
				String xdgConfigHome = System.getenv("XDG_CONFIG_HOME");

				if (xdgConfigHome == null) {
					profileDir = String.format("%s/.config/%s/conf", System.getProperty("user.home"), PROFILE_DIRECTORY_NAME);
				} else {
					profileDir = String.format("%s/%s/conf", xdgConfigHome, PROFILE_DIRECTORY_NAME);
				}
			}

			File f = new File(profileDir);
			if ((f.exists() || f.mkdir()) && f.isDirectory()) {
				PROFILE_DIRECTORY = FilenameUtils.normalize(f.getAbsolutePath());   // ex. ../conf
			} else {
				PROFILE_DIRECTORY = FilenameUtils.normalize(new File("").getAbsolutePath());
			}
			//PROFILE_BASE_DIRECTORY = FilenameUtils.normalize(f.getParentFile().getAbsolutePath());
			PROFILE_BASE_DIRECTORY = FilenameUtils.normalize(f.getAbsoluteFile().getParentFile().getAbsolutePath());
			PROFILE_PATH = FilenameUtils.normalize(new File(PROFILE_DIRECTORY, DEFAULT_PROFILE_FILENAME).getAbsolutePath());
		}
	}
	
	//regzam, moved getLogger() after above static { }, 
	//static: for the case call before creating instance (PmsConfiguration load)
	private static final Logger logger = LoggerFactory.getLogger(PmsConfiguration.class);

	//regzam, moved constructor after above static { }, 
	//i.e. after PROFILE_XXXX value fixed, to avoid to fail getDebugLogDir() called by getLogger()
	public PmsConfiguration() throws ConfigurationException, IOException {
		configuration = new PropertiesConfiguration();
		configuration.setListDelimiter((char) 0);
		configuration.setFileName(PROFILE_PATH);

		File pmsConfFile = new File(PROFILE_PATH);

		if (pmsConfFile.exists() && pmsConfFile.isFile()) {
			configuration.load(PROFILE_PATH);
		}

		tempFolder = new TempFolder(getString(KEY_TEMP_FOLDER_PATH, null));  //defined in configuration/TempFolder.java
		programPaths = createProgramPathsChain(configuration);
		Locale.setDefault(new Locale(getLanguage()));
	}
	
	
	//--------------------------------------------------------------------------------------
	// 2) Other system folders
	//--------------------------------------------------------------------------------------
	public static String getProfileBaseDir() {
		return PROFILE_BASE_DIRECTORY;
	}
	public static String getProfileDirectory() {
		return PROFILE_DIRECTORY;
	}
	public static String getProfilePath() {
		return PROFILE_PATH;
	}
	public static String getDebugLogDir() {
		return PROFILE_BASE_DIRECTORY;
	}
	public static String getDatabaseDir() {
		return PROFILE_BASE_DIRECTORY + File.separator + "database";
	}

	static String UserDataPath;
	public String getUserDataFolder() {
		if(UserDataPath!=null) return UserDataPath;
		String path=rz_getString(KEY_RZ_USERDATA_PATH, null);
		if(path==null) {
			path=PROFILE_BASE_DIRECTORY+ File.separator + "UserData";
		}
		else {
			path=kwd_replace(path,1);
		}
		File f=new File(path);
		if(!f.exists()) {
			boolean b=f.mkdir();
			if(!b) {
				logger.error("getUserDataFolder: mkdir error, path="+path);
			}
		}
		UserDataPath=path;
		return path;
	}

	public File getTempFolder() throws IOException {
		return tempFolder.getTempFolder();
	}

	public String getTempDir() {
		if(temp_dir!=null) return temp_dir;
		try {
			File f=getTempFolder();
			temp_dir=f.getAbsolutePath();
		} catch (IOException e) {
			temp_dir="temp";
		}
		return temp_dir;
	}
	
	private String kwd_replace (String str, int except) {
		str=str.replace("$conf$"     ,PROFILE_DIRECTORY);
		str=str.replace("$conf_base$",PROFILE_BASE_DIRECTORY);
		str=str.replace("$temp$"     ,getTempDir());
		str=str.replace("$inst$"     ,"./");
		if(except==0) {  // to avoid infinit loop called by getUserDataFolder() it's self
			str=str.replace("$user_data$",getUserDataFolder());
		}
		return str;
	}

	/**
	 * Check if we have disabled something first, then check the config file,
	 * then the Windows registry, then check for a platform-specific
	 * default.
	 */
	private static ProgramPathDisabler createProgramPathsChain(Configuration configuration) {
		return new ProgramPathDisabler(
			new ConfigurationProgramPaths(configuration,
			new WindowsRegistryProgramPaths(
			new PlatformSpecificDefaultPathsFactory().get())));
	}

	
	public String getVlcPath() {
		return programPaths.getVlcPath();
	}

	public void disableVlc() {
		programPaths.disableVlc();
	}

	public String getEac3toPath() {
		return programPaths.getEac3toPath();
	}

	public String getMencoderPath() {
		return programPaths.getMencoderPath();
	}

	/*
	public String getMencoderPath_new() {
		String path=getRZ_mencoder_new();
		if(path!=null) return path;
		return programPaths.getMencoderPath();
	}
	*/

	public String getRzWebMediaInfo_Path() {	//regzamod
		return programPaths.getRzWebMediaInfo_Path();
	}


	public int getMencoderMaxThreads() {
		return Math.min(getInt(KEY_MENCODER_MAX_THREADS, getNumberOfCpuCores()), MENCODER_MAX_THREADS);
	}

	public String getDCRawPath() {
		return programPaths.getDCRaw();
	}

	public void disableMEncoder() {
		programPaths.disableMencoder();
	}

	public String getFfmpegPath() {
		if(getRZ_ffmpeg_path()!=null) {
			return getRZ_ffmpeg_path();
		}
		return programPaths.getFfmpegPath();
	}
	
	/*
	public String getFfmpegPath_new() {
		String path=getRZ_ffmpeg_new();
		if(path!=null) return path;
		return programPaths.getFfmpegPath();
	}
	*/

	public void disableFfmpeg() {
		programPaths.disableFfmpeg();
	}

	public String getMplayerPath() {
		if(getRZ_mencoder_path()!=null) {
			return getRZ_mencoder_path();
		}
		return programPaths.getMplayerPath();
	}

	public void disableMplayer() {
		programPaths.disableMplayer();
	}

	public String getTsmuxerPath() {
		return programPaths.getTsmuxerPath();
	}

	public String getFlacPath() {
		return programPaths.getFlacPath();
	}

	//---- regzamod add start --------------------
	public boolean	getRZ_Mod() {
		return rz_getBoolean(KEY_RZ_MOD, false);
	}
	public int	getRZ_Debug() {
		return rz_getInt(KEY_RZ_DEBUG, 0);
	}
	public int	getRZ_Trace() {
		return rz_getInt(KEY_RZ_TRACE, 0);
	}
	public int	getRZ_dump_ua_header() {
		return rz_getInt(KEY_RZ_DUMP_UA_HEADER, 0);
	}
	public int getRZ_StreamDump() {
		return rz_getInt(KEY_RZ_STREAM_DUMP, 0);
	}
	public int	getRZ_Test() {
		return rz_getInt(KEY_RZ_TEST, 0);
	}
	public String getRZ_PlaylistEncode() {
		return rz_getString(KEY_RZ_PLAYLIST_ENCODE, "UTF-8");
	}
	public String getRZ_MetafileEncode() {
		return rz_getString(KEY_RZ_METAFILE_ENCODE, "UTF-8");
	}
	public String getRZ_LogbackLevel_disp() {
		return rz_getString(KEY_RZ_LOGBACK_LEVEL_DISP, "INFO");
	}
	public String getRZ_LogbackLevel_file() {
		return rz_getString(KEY_RZ_LOGBACK_LEVEL_FILE, "DEBUG");
	}
	public String getRZ_MetafileSuffix() {
		return rz_getString(KEY_RZ_METAFILE_SUFFIX, "pxm");
	}
	public int getRZ_ProfileEnabled() {
		return rz_getInt(KEY_RZ_PROFILE_ENABLED, 1);
	}
	public String getRZ_ProfileSuffix() {
		return rz_getString(KEY_RZ_PROFILE_SUFFIX, "pxf");
	}
	public String getRZ_ProfileFF() {
		return rz_getString(KEY_RZ_PROFILE_FF, "_folder.pxf");
	}
	
	public void setRZ_LogbackLevel_disp(String level) {
		configuration.setProperty(KEY_RZ_LOGBACK_LEVEL_DISP, level);
	}
	public void setRZ_LogbackLevel_file(String level) {
		configuration.setProperty(KEY_RZ_LOGBACK_LEVEL_FILE, level);
		PMSThresholdFilter tf= new PMSThresholdFilter();
		tf.SetLoggerLevel(level);
	}
	public int getRZ_BufferCheckInterval() {
		return rz_getInt(KEY_RZ_BUFFER_CHECK_INTERVAL, 30);
	}
	public int getRZ_force_gc_interval() {
		return rz_getInt(KEY_RZ_FORCE_GC_INTERVAL, 0);
	}
	public int getRZ_gc_on_stop_playing() {
		return rz_getInt(KEY_RZ_GC_ON_STOP_PLAYING, 0);
	}
	public int getRZ_ForceMemFree() {
		return rz_getInt(KEY_RZ_FORCE_MEM_FREE, 0);
	}
	public boolean isRZ_sort_when_refresh() {
		return rz_getBoolean(KEY_RZ_SORT_WHEN_REFRESH, false);
	}
	public boolean isRZ_disp_sort_menu() {
		return rz_getBoolean(KEY_RZ_DISP_SORT_MENU, false);
	}
	public boolean isRZ_close_after_send() {
		return rz_getBoolean(KEY_RZ_CLOSE_AFTER_SEND, true);
	}
	public int getRZ_wait_stream_max_time() {
		return rz_getInt(KEY_RZ_WAIT_STREAM_MAX_TIME, 10000);	//msec
	}
	public int getRZ_wait_stream_max_time2() {
		return rz_getInt(KEY_RZ_WAIT_STREAM_MAX_TIME2, 10000);	//msec
	}
	public int getRZ_wait_stream_min_buff() {
		return rz_getInt(KEY_RZ_WAIT_STREAM_MIN_BUFF, 0);		//bytes
	}
	public int getRZ_reply_processing() {
		return rz_getInt(KEY_RZ_REPLY_PROCESSING, 0);
	}
	public int getRZ_reply_error() {
		return rz_getInt(KEY_RZ_REPLY_ERROR, 0);
	}
	public int getRZ_menu_type() {
		return rz_getInt(KEY_RZ_MENU_TYPE, 2);	// 0,1: legacy, 2: new_type
	}
	public int getRZ_sort_menu_type() {
		return rz_getInt(KEY_RZ_SORT_MENU_TYPE, 2);	// 0,1: legacy, 2: new_type
	}
	public String getRZ_resume_sort_type() {
		return rz_getString(KEY_RZ_RESUME_SORT_TYPE, "date_r");
	}
	public int getRZ_update_check_nls() {  //for normal folder entries
		return rz_getInt(KEY_RZ_UPDATE_CHECK_NLS,3);	//OR of 0:noop,1:cre/del/ren/move,2:modify
	}
	public int getRZ_update_check_pls() { //for playlist entries
		return rz_getInt(KEY_RZ_UPDATE_CHECK_PLS,3);	//OR of 0:noop,1:cre/del/ren/move,2:modify
	}
		public int getRZ_update_check_min() { //minimum check interval (msec)
		return rz_getInt(KEY_RZ_UPDATE_CHECK_MIN,2000);  //default 2000msec
	}
	public int getRZ_netty_conn_max() {
		return rz_getInt(KEY_RZ_NETTY_CONN_MAX, -1);  //-1:default -> use CPU *2
	}
	public boolean isRZ_direct_seek() {
		return rz_getBoolean(KEY_RZ_DIRECT_SEEK, false);
	}
	public int getRZ_buffer_seek() {
		return rz_getInt(KEY_RZ_BUFFER_SEEK, 0);
	}
	public int getRZ_buffer_rollback() {
		return rz_getInt(KEY_RZ_BUFFER_ROLLBACK, 0);
	}
	public boolean isRZ_root_per_session() {
		return rz_getBoolean(KEY_RZ_ROOT_PER_SESSION, false);
	}
	public boolean isRZ_rend_script_enabled() {
		return rz_getBoolean(KEY_RZ_REND_SCRIPT_ENABLED, false);
	}
	public int getRZ_ffmpeg_abitrate() {
		return rz_getInt(KEY_RZ_FFMPEG_ABITRATE, -1);  //audio bitrate (kbps)
	}
	public float getRZ_dupmsg_supp_time() {
		return rz_getFloat(KEY_RZ_DUPMSG_SUPP_TIME, 0.0);  //audio bitrate (kbps)
	}
	/*
	public String getRZ_ffmpeg_path_new() {
		return rz_getString(KEY_RZ_FFMPEG_NEW, null);  //
	}
	public String getRZ_mencoder_path_new() {
		return rz_getString(KEY_RZ_MENCODER_PATH_NEW, null);  //
	}
	*/
	public String getRZ_ffmpeg_path() {
		return rz_getString(KEY_RZ_FFMPEG_PATH, null);  //
	}
	public String getRZ_mencoder_path() {
		return rz_getString(KEY_RZ_MENCODER_PATH, null);  //
	}
	
	//---- Web Contents ----------
	public int	getRZ_web_refresh_interval() {
		return rz_getInt(KEY_RZ_WEB_REFRESH_INTERVAL, 600);	//default: 600sec (10 min)
	}
	public String getRZ_web_sort_type() {
		return rz_getString(KEY_RZ_WEB_SORT_TYPE, "original");
	}
	public void setRZ_web_sort_type(String value) {
		configuration.setProperty(KEY_RZ_WEB_SORT_TYPE, value);
	}
	public boolean isRZ_web_force_resize() {
		return rz_getBoolean(KEY_RZ_WEB_FORCE_RESIZE, false);
	}
	public void setRZ_web_force_resize(boolean value) {
		configuration.setProperty(KEY_RZ_WEB_FORCE_RESIZE, ""+value);
	}
	public int getRZ_web_resize_w() {
		return rz_getInt(KEY_RZ_WEB_RESIZE_W, 720);
	}
	public void setRZ_web_resize_w(int value) {
		configuration.setProperty(KEY_RZ_WEB_RESIZE_W, ""+value);
	}
	public int getRZ_web_resize_h() {
		return rz_getInt(KEY_RZ_WEB_RESIZE_H, 480);
	}
	public void setRZ_web_resize_h(int value) {
		configuration.setProperty(KEY_RZ_WEB_RESIZE_H, ""+value);
	}
	public boolean isRZ_web_remux() {
		return rz_getBoolean(KEY_RZ_WEB_REMUX, false);
	}
	public void setRZ_web_remux(boolean value) {
		configuration.setProperty(KEY_RZ_WEB_REMUX, ""+value);
	}
	public String getRZ_web_quality() {
		return rz_getString(KEY_RZ_WEB_QUALITY, "best");
	}
	public void setRZ_web_quality(String value) {
		configuration.setProperty(KEY_RZ_WEB_QUALITY, value);
	}
	public int getRZ_web_duration_add() {
		return rz_getInt(KEY_RZ_WEB_DURATION_ADD, 0);
	}
	public String getRZ_web_mediainfo_path() {
		return rz_getString(KEY_RZ_WEB_MEDIAINFO_PATH, "$python_path$,regzamod/RzWEBplayer/RzWebMediaInfo.py");
	}
	public int getRZ_rz_web_resolve_intvl() {
		return rz_getInt(KEY_RZ_WEB_RESOLVE_INTVL, -1);
	}
	
	//---- AAV(AudioAsVideo) ----------
	public boolean isRZ_audio_as_video() {
		return getBoolean(KEY_RZ_AUDIO_AS_VIDEO, false);
	}
	public boolean isRZ_aav_caption() {
		return getBoolean(KEY_RZ_AAV_CAPTION, true);
	}
	public String getRZ_aav_player_path() {
		return rz_getString(KEY_RZ_AAV_PLAYER_PATH, "$python_path$,regzamod/RzAAVplayer/RzAAVplayer.py");
	}
	public String getRZ_aav_clip_path1() {
		return rz_getString(KEY_RZ_AAV_CLIP_PATH1, null);
	}
	public String getRZ_aav_clip_path2() {
		return rz_getString(KEY_RZ_AAV_CLIP_PATH2, null);
	}
	public int getRZ_aav_start_delay() {
		return rz_getInt(KEY_RZ_AAV_START_DELAY, 4);
	}
	public int getRZ_aav_clip_seltype() {
		return rz_getInt(KEY_RZ_AAV_CLIP_SELTYPE, 1);
	}
	public int getRZ_aav_clip_interval() {
		return rz_getInt(KEY_RZ_AAV_CLIP_INTERVAL, 10);
	}
	public int getRZ_aav_resize_w() {
		return rz_getInt(KEY_RZ_AAV_RESIZE_W, 720);
	}
	public int getRZ_aav_resize_h() {
		return rz_getInt(KEY_RZ_AAV_RESIZE_H, 480);
	}
	public int getRZ_aav_imgfit() {
		return rz_getInt(KEY_RZ_AAV_IMGFIT, 1);
	}

	public void setRZ_audio_as_video(boolean val) {
		configuration.setProperty(KEY_RZ_AUDIO_AS_VIDEO, val);
	}
	public void setRZ_aav_caption(boolean val) {
		configuration.setProperty(KEY_RZ_AAV_CAPTION, val);
	}
	public void setRZ_aav_clip_seltype(int val) {
		configuration.setProperty(KEY_RZ_AAV_CLIP_SELTYPE, ""+val);
	}
	public void setRZ_aav_clip_interval(int val) {
		String sval=""+val;
		configuration.setProperty(KEY_RZ_AAV_CLIP_INTERVAL, sval);
	}
	public void setRZ_aav_resize_w(int w) {
		configuration.setProperty(KEY_RZ_AAV_RESIZE_W, ""+w);
	}
	public void setRZ_aav_resize_h(int h) {
		configuration.setProperty(KEY_RZ_AAV_RESIZE_H, ""+h);
	}
	public void setRZ_aav_clip_path1(String path) {
		configuration.setProperty(KEY_RZ_AAV_CLIP_PATH1, path);
	}
	public void setRZ_aav_clip_path2(String path) {
		configuration.setProperty(KEY_RZ_AAV_CLIP_PATH2, path);
	}
	public void setRZ_aav_imgfit(int val) {
		configuration.setProperty(KEY_RZ_AAV_IMGFIT, ""+val);
	}
	
	//---- IAV(ImageAsVideo) ----------
	public boolean isRZ_image_as_video() {
		return getBoolean(KEY_RZ_IMAGE_AS_VIDEO, false);
	}
	public boolean isRZ_iav_caption() {
		return getBoolean(KEY_RZ_IAV_CAPTION, true);
	}
	public boolean isRZ_iav_gapless() {
		return getBoolean(KEY_RZ_IAV_GAPLESS, false);
	}
	public String getRZ_iav_player_path() {
		return rz_getString(KEY_RZ_IAV_PLAYER_PATH, "$python_path$,regzamod/RzIAVplayer/RzIAVplayer.py");
	}
	public String getRZ_iav_clip_path1() {
		return rz_getString(KEY_RZ_IAV_CLIP_PATH1, null);
	}
	public String getRZ_iav_clip_path2() {
		return rz_getString(KEY_RZ_IAV_CLIP_PATH2, null);
	}
	public int getRZ_iav_clip_interval() {
		return rz_getInt(KEY_RZ_IAV_CLIP_INTERVAL, 10);
	}
	public int getRZ_iav_clip_seltype() {
		return rz_getInt(KEY_RZ_IAV_CLIP_SELTYPE, 0);
	}
	public int getRZ_iav_imgfit() {
		return rz_getInt(KEY_RZ_IAV_IMGFIT, 1);
	}

	public void setRZ_image_as_video(boolean val) {
		configuration.setProperty(KEY_RZ_IMAGE_AS_VIDEO, val);
	}
	public void setRZ_iav_caption(boolean val) {
		configuration.setProperty(KEY_RZ_IAV_CAPTION, val);
	}
	public void setRZ_iav_gapless(boolean val) {
		configuration.setProperty(KEY_RZ_IAV_GAPLESS, val);
	}
	public void setRZ_iav_clip_path1(String path) {
		configuration.setProperty(KEY_RZ_IAV_CLIP_PATH1, path);
	}
	public void setRZ_iav_clip_path2(String path) {
		configuration.setProperty(KEY_RZ_IAV_CLIP_PATH2, path);
	}
	public void setRZ_iav_clip_interval(int val) {
		String sval=""+val;
		configuration.setProperty(KEY_RZ_IAV_CLIP_INTERVAL, ""+sval);
	}
	public void setRZ_iav_clip_seltype(int val) {
		configuration.setProperty(KEY_RZ_IAV_CLIP_SELTYPE, ""+val);
	}
	public void setRZ_iav_imgfit(int val) {
		configuration.setProperty(KEY_RZ_IAV_IMGFIT, ""+val);
	}
	
	//---- resume controll
	public int getRZ_resume_mode() {
		return rz_getInt(KEY_RZ_RESUME_MODE, 0);
	}
	public float getRZ_resume_play_min_time1() {
		return rz_getFloat(KEY_RZ_RESUME_PLAY_MIN_TIME1, 5.0);
	}
	public float getRZ_resume_play_min_time2() {
		return rz_getFloat(KEY_RZ_RESUME_PLAY_MIN_TIME2, 5.0);
	}
	public float getRZ_resume_rewind_time() {
		return rz_getFloat(KEY_RZ_RESUME_REWIND_TIME, 10.0);
	}
	public float getRZ_resume_duration_delta() {
		return rz_getFloat(KEY_RZ_RESUME_DURATION_DELTA, 60.0);
	}
	public float getRZ_unknown_duration_max() {
		return rz_getFloat(KEY_RZ_UNKNOWN_DURATION_MAX, 1800.0);  //default 1800 sec(30 min)
	}
	public int getRZ_resname_pathadd_iso() {
		return rz_getInt(KEY_RZ_RESNAME_PATHADD_ISO, 1);
	}
	public int getRZ_resume_per_folder_web() {
		return rz_getInt(KEY_RZ_RESUME_PER_FOLDER_WEB, 0);
	}
	
	//---- misc -----------------------------------
	public String getRZ_server_name() {
		return rz_getString(KEY_RZ_SERVER_NAME, "PMS-FRZ");
	}
	public String getRZ_machine_name() {
		return rz_getString(KEY_RZ_MACHINE_NAME, null);
	}
	public String getRZ_kwdmenu_conf() {
		String str=rz_getString(KEY_RZ_KWDMENU_CONF, "$conf$/KwdMenu.conf");
		//str=str.replace("$conf$",PROFILE_DIRECTORY);
		str=kwd_replace(str,0);
		return str;
	}
	
	// kwd list
	public String getRZ_kwdlist_conf() {
		String str=rz_getString(KEY_RZ_KWDLIST_CONF, "$conf$/KwdList.conf");
		//str=str.replace("$conf$",PROFILE_DIRECTORY);
		str=kwd_replace(str,0);
		return str;
	}
	
	public List<String> getRZ_kwdlist_confPaths() {
		List<?> objs=configuration.getList(KEY_RZ_KWDLIST_CONF);
		List<String> paths=new ArrayList<String>();
		
		for (Object line : objs) {
			String path=line.toString();
			//path=path.replace("$conf$",PROFILE_DIRECTORY);
			path=kwd_replace(path,0);
			paths.add(path);
		}
		return paths;
	}

	public String getRZ_kwdlist_update_prog() {
		return rz_getString(KEY_RZ_KWDLIST_UPDATE_PROG, "utility/kwdUpdate_kick.bat");
	}
	
	public String getRZ_cliplist_conf() {
		String str=rz_getString(KEY_RZ_CLIPLIST_CONF, "$conf$/ClipList.conf");
		//str=str.replace("$conf$",PROFILE_DIRECTORY);
		str=kwd_replace(str,0);
		return str;
	}
	
	public int getRZ_auto_search_lock() {
		//val=0:nolock,=1:lock some folders(web/resume/settings),=2:lock all
		return rz_getInt(KEY_RZ_AUTO_SEARCH_LOCK, 0);  //default=nolock
	}
	public int getRZ_action_button_type() {
		//val=1:file_btn,=2:folder_btn
		return rz_getInt(KEY_RZ_ACTION_BUTTON_TYPE, 2); //default=folder_btn
	}
	public boolean isRZ_minfo_multi() {
		return rz_getBoolean(KEY_RZ_MINFO_MULTI, false);
	}
	public int getRZ_itunes_parse_mode() {
		return rz_getInt(KEY_RZ_ITUNES_PARSE_MODE, 0);
	}
	public String[] getRZ_itunes_ignore_kinds() {
		String str=rz_getString(KEY_RZ_ITUNES_IGNORE_KINDS, null);
		if(str==null) return null;
		String[] kinds=str.split(",");
		return kinds;
	}
	public int getRZ_thumbnails_getlater() {
		return rz_getInt(KEY_RZ_THUMBNAILS_GETLATER, 1);
	}
	public int getRZ_media_parse_type() {
		return rz_getInt(KEY_RZ_MEDIA_PARSE_TYPE, 1);
	}
	public int getRZ_media_parse_thread() {
		return rz_getInt(KEY_RZ_MEDIA_PARSE_THREAD, 3);
	}
	public int getRZ_dlna_prof_cache() {
		return rz_getInt(KEY_RZ_DLNA_PROF_CACHE, 0);
	}
	
	public List<?> getScriptList() {
		return configuration.getList(KEY_RZ_REND_OPT_SCRIPT);
	}
	
	public boolean isRZ_UpnpEnabled() {
		return rz_getBoolean(KEY_RZ_UPNP_ENABLE, false);
	}
	public int getRZ_rend_judge_type() {
		return rz_getInt(KEY_RZ_REND_JUDGE_TYPE, 0);
	}
	public String getRZ_python_path() {
		return rz_getString(KEY_RZ_PYTHON_PATH, "C:/Python27/python.exe");
	}
	public int getRZ_web_resolve_delay() {
		return rz_getInt(KEY_RZ_WEB_RESOLVE_DELAY, 1000);  //msec
	}
	
	
	//---- start waits
	//------------------------------------------------------------------------------
	// get following values for start playing tuning params, see OutputParams.java
	//	params.waitbeforestart   =mval[0];         //wait time before kick player (msec)
	//	params.minBufferSize     =mval[1];         //wait min Buffered before 1st send (MBytes, on Tras/Remux BufferMem)
	//	params.secondread_minsize=mval[2]*1000000; //wait min Buffered before 2nd send (Bytes,  on Tras/Remux BufferMem)
	//------------------------------------------------------------------------------
	private static double mval_def[]={5000,1,1};  // defaults: 5000msc,1MB,1MB
	public double[] getRZ_def_startwait() {
		String str=rz_getString(KEY_RZ_DEF_START_WAIT,"-");
		if(str.equals("-")) return mval_def;
		return getMvalStartWait(str,mval_def);
	}
	public double[] getRZ_trans_startwait() {
		String str=rz_getString(KEY_RZ_TRANS_START_WAIT,"-");
		if(str.equals("-")) return getRZ_def_startwait();
		return getMvalStartWait(str,getRZ_def_startwait());
	}
	public double[] getRZ_remux_startwait() {
		String str=rz_getString(KEY_RZ_REMUX_START_WAIT,"-");
		if(str.equals("-")) return getRZ_def_startwait();
		return getMvalStartWait(str,getRZ_def_startwait());
	}
	public double[] getRZ_web_startwait() {
		String str=rz_getString(KEY_RZ_WEB_START_WAIT,"-");
		if(str.equals("-")) return getRZ_def_startwait();
		return getMvalStartWait(str,getRZ_def_startwait());
	}
	public double[] getRZ_aav_startwait() {
		String str=rz_getString(KEY_RZ_AAV_START_WAIT,"-");
		if(str.equals("-")) return getRZ_def_startwait();
		return getMvalStartWait(str,getRZ_def_startwait());
	}
	public double[] getRZ_iav_startwait() {
		String str=rz_getString(KEY_RZ_IAV_START_WAIT,"-");
		if(str.equals("-")) return getRZ_def_startwait();
		return getMvalStartWait(str,getRZ_def_startwait());
	}
	private double[] getMvalStartWait(String str,double def[]) {
		double mval[]={0,0,0};
		String mstr[]=str.split(",");
		int cnt=0;
		try {
			for (String s: mstr) {
				double val=Double.parseDouble(s.trim());
				if(val>=0) mval[cnt]=val;
				else if(def!=null) mval[cnt]=def[cnt];
				cnt++;
				if(cnt>2) break;
			}
		} catch (NumberFormatException e) {
			logger.warn("PmsConfiguration.getMvalStartWait: getRZ_xxx_startwait() value error="+e.getMessage());
		} 
		return mval;
	}
	

	//---- regzamod add end -----------------------------------
	
	/**
	 * If the framerate is not recognized correctly and the video runs too fast or too
	 * slow, tsMuxeR can be forced to parse the fps from FFmpeg. Default value is true.
	 * @return True if tsMuxeR should parse fps from FFmpeg.
	 */
	public boolean isTsmuxerForceFps() {
		return configuration.getBoolean(KEY_TSMUXER_FORCEFPS, true);
	}

	/**
	 * Force tsMuxeR to mux all audio tracks.
	 * TODO: Remove this redundant code.
	 * @return True
	 */
	public boolean isTsmuxerPreremuxAc3() {
		return true;
	}

	/**
	 * The AC3 audio bitrate determines the quality of digital audio sound. An AV-receiver
	 * or amplifier has to be capable of playing this quality. Default value is 640.
	 * @return The AC3 audio bitrate.
	 */
	public int getAudioBitrate() {
		return getInt(KEY_AUDIO_BITRATE, 640);
	}

	/**
	 * Force tsMuxeR to mux all audio tracks.
	 * TODO: Remove this redundant code; getter always returns true.
	 */
	public void setTsmuxerPreremuxAc3(boolean value) {
		configuration.setProperty(KEY_TSMUXER_PREREMIX_AC3, value);
	}

	/**
	 * If the framerate is not recognized correctly and the video runs too fast or too
	 * slow, tsMuxeR can be forced to parse the fps from FFmpeg.
	 * @param value Set to true if tsMuxeR should parse fps from FFmpeg.
	 */
	public void setTsmuxerForceFps(boolean value) {
		configuration.setProperty(KEY_TSMUXER_FORCEFPS, value);
	}

	/**
	 * The server port where PMS listens for TCP/IP traffic. Default value is 5001.
	 * @return The port number.
	 */
	public int getServerPort() {
		return getInt(KEY_SERVER_PORT, DEFAULT_SERVER_PORT);
	}

	/**
	 * Set the server port where PMS must listen for TCP/IP traffic.
	 * @param value The TCP/IP port number.
	 */
	public void setServerPort(int value) {
		configuration.setProperty(KEY_SERVER_PORT, value);
	}

	/**
	 * The hostname of the server.
	 * @return The hostname if it is defined, otherwise <code>null</code>.
	 */
	public String getServerHostname() {
		String value = getString(KEY_SERVER_HOSTNAME, "");
		if (StringUtils.isNotBlank(value)) {
			return value;
		} else {
			return null;
		}
	}

	/**
	 * Set the hostname of the server.
	 * @param value The hostname.
	 */
	public void setHostname(String value) {
		configuration.setProperty(KEY_SERVER_HOSTNAME, value);
	}

	/**
	 * The TCP/IP port number for a proxy server. Default value is -1.
	 * TODO: Is this still used?
	 * @return The proxy port number.
	 */
	public int getProxyServerPort() {
		return getInt(KEY_PROXY_SERVER_PORT, DEFAULT_PROXY_SERVER_PORT);
	}

	/**
	 * Get the code of the preferred language for the PMS user interface. Default
	 * is based on the locale.
	 * @return The ISO 639 language code.
	 */
	public String getLanguage() {
		String def = Locale.getDefault().getLanguage();
		if (def == null) {
			def = "en";
		}
		String value = getString(KEY_LANGUAGE, def);
		return StringUtils.isNotBlank(value) ? value.trim() : def;
	}

	/**
	 * Return the <code>int</code> value for a given configuration key. First, the key
	 * is looked up in the current configuration settings. If it exists and contains a
	 * valid value, that value is returned. If the key contains an invalid value or
	 * cannot be found, the specified default value is returned.
	 * @param key The key to look up.
	 * @param def The default value to return when no valid key value can be found.
	 * @return The value configured for the key.
	 */
	private int getInt(String key, int def) {
		if(false) {	//regzamod2, Foolish apache.commons will cause ConversionException!!
			String val=getString(key,null);
			if(val==null) return def;
			return Integer.parseInt(val);
		}
		try {
			return configuration.getInt(key, def);
		} catch (ConversionException e) {
			return def;
		}
	}

	/**
	 * Return the <code>boolean</code> value for a given configuration key. First, the
	 * key is looked up in the current configuration settings. If it exists and contains
	 * a valid value, that value is returned. If the key contains an invalid value or
	 * cannot be found, the specified default value is returned.
	 * @param key The key to look up.
	 * @param def The default value to return when no valid key value can be found.
	 * @return The value configured for the key.
	 */
	private String getString (String key, String def) {	//original
		String value = configuration.getString(key, def);
		if (value != null) {
			value = value.trim();
		}
		return value;
	}
	
	private boolean getBoolean(String key, boolean def) {
		try {
			return configuration.getBoolean(key, def);
		} catch (ConversionException e) {
			return def;
		}
	}

	private boolean rz_getBoolean (String key, boolean def) {
		String s=rz_getString(key,"unknown");
		if(s.equals("true")) return true;
		else if(s.equals("false")) return false;
		else return def;
	}

	private int rz_getInt (String key, int def) {
		String s=rz_getString(key,""+def);
		return Integer.parseInt(s);
	}
	
	private float rz_getFloat (String key, double def) {
		String s=rz_getString(key, ""+def);
		return Float.parseFloat(s);
	}

	private String rz_getString (String key, String def) {//regzamod,  omit tail's #data
		String value = configuration.getString(key, def);
		if (value != null) {
			//---- regzamod, ignore comment parts begin with #
			int pos = value.indexOf("#");	
			if(pos>-1) {
				value=value.substring(0,pos);
			}
			//----
			value = value.trim();
		}
		if(value==null || value.length()<=0) {
			return def;
		}
		return value;
	}

	
	/**
	 * Return a <code>List</code> of <code>String</code> values for a given configuration
	 * key. First, the key is looked up in the current configuration settings. If it
	 * exists and contains a valid value, that value is returned. If the key contains an
	 * invalid value or cannot be found, a list with the specified default values is
	 * returned.
	 * @param key The key to look up.
	 * @param def The default values to return when no valid key value can be found.
	 *            These values should be entered as a comma separated string, whitespace
	 *            will be trimmed. For example: <code>"gnu,    gnat  ,moo "</code> will be
	 *            returned as <code>{ "gnu", "gnat", "moo" }</code>.
	 * @return The list of value strings configured for the key.
	 */
	private List<String> getStringList(String key, String def) {
		String value = getString(key, def);
		if (value != null) {
			String[] arr = value.split(",");
			List<String> result = new ArrayList<String>(arr.length);
			for (String str : arr) {
				if (str.trim().length() > 0) {
					result.add(str.trim());
				}
			}
			return result;
		} else {
			return Collections.emptyList();
		}
	}

	/**
	 * Returns the preferred minimum size for the transcoding memory buffer in megabytes.
	 * Default value is 12.
	 * @return The minimum memory buffer size.
	 */
	public int getMinMemoryBufferSize() {
		return getInt(KEY_MIN_MEMORY_BUFFER_SIZE, 12);
	}

	/**
	 * Returns the preferred maximum size for the transcoding memory buffer in megabytes.
	 * The value returned has a top limit of 600. Default value is 400.
	 * @return The maximum memory buffer size.
	 */
	public int getMaxMemoryBufferSize() {
		return Math.max(0, Math.min(MAX_MAX_MEMORY_BUFFER_SIZE, getInt(KEY_MAX_MEMORY_BUFFER_SIZE, 400)));
	}

	/**
	 * Returns the top limit that can be set for the maximum memory buffer size.
	 * @return The top limit.
	 */
	public String getMaxMemoryBufferSizeStr() {
		return String.valueOf(MAX_MAX_MEMORY_BUFFER_SIZE);
	}

	/**
	 * Set the preferred maximum for the transcoding memory buffer in megabytes. The top
	 * limit for the value is 600.
	 * @param value The maximum buffer size.
	 */
	public void setMaxMemoryBufferSize(int value) {
		configuration.setProperty(KEY_MAX_MEMORY_BUFFER_SIZE, Math.max(0, Math.min(MAX_MAX_MEMORY_BUFFER_SIZE, value)));
	}

	/**
	 * Returns the font scale used for ASS subtitling. Default value is 1.0.
	 * @return The ASS font scale.
	 */
	public String getMencoderAssScale() {
		return getString(KEY_MENCODER_ASS_SCALE, "1.0");
	}

	/**
	 * Some versions of mencoder produce garbled audio because the "ac3" codec is used
	 * instead of the "ac3_fixed" codec. Returns true if "ac3_fixed" should be used.
	 * Default is false.
	 * See https://code.google.com/p/ps3mediaserver/issues/detail?id=1092#c1
	 * @return True if "ac3_fixed" should be used. 
	 */
	public boolean isMencoderAc3Fixed() {
		return configuration.getBoolean(KEY_MENCODER_AC3_FIXED, false);
	}

	/**
	 * Returns the margin used for ASS subtitling. Default value is 10.
	 * @return The ASS margin.
	 */
	public String getMencoderAssMargin() {
		return getString(KEY_MENCODER_ASS_MARGIN, "10");
	}

	/**
	 * Returns the outline parameter used for ASS subtitling. Default value is 1.
	 * @return The ASS outline parameter.
	 */
	public String getMencoderAssOutline() {
		return getString(KEY_MENCODER_ASS_OUTLINE, "1");
	}

	/**
	 * Returns the shadow parameter used for ASS subtitling. Default value is 1.
	 * @return The ASS shadow parameter.
	 */
	public String getMencoderAssShadow() {
		return getString(KEY_MENCODER_ASS_SHADOW, "1");
	}

	/**
	 * Returns the subfont text scale parameter used for subtitling without ASS.
	 * Default value is 3.
	 * @return The subfont text scale parameter.
	 */
	public String getMencoderNoAssScale() {
		return getString(KEY_MENCODER_NOASS_SCALE, "3");
	}

	/**
	 * Returns the subpos parameter used for subtitling without ASS.
	 * Default value is 2.
	 * @return The subpos parameter.
	 */
	public String getMencoderNoAssSubPos() {
		return getString(KEY_MENCODER_NOASS_SUBPOS, "2");
	}

	/**
	 * Returns the subfont blur parameter used for subtitling without ASS.
	 * Default value is 1.
	 * @return The subfont blur parameter.
	 */
	public String getMencoderNoAssBlur() {
		return getString(KEY_MENCODER_NOASS_BLUR, "1");
	}

	/**
	 * Returns the subfont outline parameter used for subtitling without ASS.
	 * Default value is 1.
	 * @return The subfont outline parameter.
	 */
	public String getMencoderNoAssOutline() {
		return getString(KEY_MENCODER_NOASS_OUTLINE, "1");
	}

	/**
	 * Set the subfont outline parameter used for subtitling without ASS.
	 * @param value The subfont outline parameter value to set.
	 */
	public void setMencoderNoAssOutline(String value) {
		configuration.setProperty(KEY_MENCODER_NOASS_OUTLINE, value);
	}

	/**
	 * Some versions of mencoder produce garbled audio because the "ac3" codec is used
	 * instead of the "ac3_fixed" codec.
	 * See https://code.google.com/p/ps3mediaserver/issues/detail?id=1092#c1
	 * @param value Set to true if "ac3_fixed" should be used.
	 */
	public void setMencoderAc3Fixed(boolean value) {
		configuration.setProperty(KEY_MENCODER_AC3_FIXED, value);
	}

	/**
	 * Set the margin used for ASS subtitling.
	 * @param value The ASS margin value to set.
	 */
	public void setMencoderAssMargin(String value) {
		configuration.setProperty(KEY_MENCODER_ASS_MARGIN, value);
	}

	/**
	 * Set the outline parameter used for ASS subtitling.
	 * @param value The ASS outline parameter value to set.
	 */
	public void setMencoderAssOutline(String value) {
		configuration.setProperty(KEY_MENCODER_ASS_OUTLINE, value);
	}

	/**
	 * Set the shadow parameter used for ASS subtitling.
	 * @param value The ASS shadow parameter value to set.
	 */
	public void setMencoderAssShadow(String value) {
		configuration.setProperty(KEY_MENCODER_ASS_SHADOW, value);
	}

	/**
	 * Set the font scale used for ASS subtitling.
	 * @param value The ASS font scale value to set.
	 */
	public void setMencoderAssScale(String value) {
		configuration.setProperty(KEY_MENCODER_ASS_SCALE, value);
	}

	/**
	 * Set the subfont text scale parameter used for subtitling without ASS.
	 * @param value The subfont text scale parameter value to set.
	 */
	public void setMencoderNoAssScale(String value) {
		configuration.setProperty(KEY_MENCODER_NOASS_SCALE, value);
	}

	/**
	 * Set the subfont blur parameter used for subtitling without ASS.
	 * @param value The subfont blur parameter value to set.
	 */
	public void setMencoderNoAssBlur(String value) {
		configuration.setProperty(KEY_MENCODER_NOASS_BLUR, value);
	}

	/**
	 * Set the subpos parameter used for subtitling without ASS.
	 * @param value The subpos parameter value to set.
	 */
	public void setMencoderNoAssSubPos(String value) {
		configuration.setProperty(KEY_MENCODER_NOASS_SUBPOS, value);
	}

	/**
	 * Set the maximum number of concurrent mencoder threads.
	 * FIXME: Currently unused.
	 * @param value The maximum number of concurrent threads.
	 */
	public void setMencoderMaxThreads(int value) {
		configuration.setProperty(KEY_MENCODER_MAX_THREADS, value);
	}

	/**
	 * Set the preferred language for the PMS user interface.
	 * @param value The ISO 639 language code.
	 */
	public void setLanguage(String value) {
		configuration.setProperty(KEY_LANGUAGE, value);
		Locale.setDefault(new Locale(getLanguage()));
	}

	/**
	 * Returns the number of seconds from the start of a video file (the seek
	 * position) where the thumbnail image for the movie should be extracted
	 * from. Default is 1 second.
	 * @return The seek position in seconds.
	 */
	public int getThumbnailSeekPos() {
		return getInt(KEY_THUMBNAIL_SEEK_POS, 1);
	}

	/**
	 * Sets the number of seconds from the start of a video file (the seek
	 * position) where the thumbnail image for the movie should be extracted
	 * from.
	 * @param value The seek position in seconds.
	 */
	public void setThumbnailSeekPos(int value) {
		configuration.setProperty(KEY_THUMBNAIL_SEEK_POS, value);
	}

	/**
	 * Older versions of mencoder do not support ASS/SSA subtitles on all
	 * platforms. Returns true if mencoder supports them. Default is true
	 * on Windows and OS X, false otherwise.
	 * See https://code.google.com/p/ps3mediaserver/issues/detail?id=1097
	 * @return True if mencoder supports ASS/SSA subtitles.
	 */
	public boolean isMencoderAss() {
		return getBoolean(KEY_MENCODER_ASS, Platform.isWindows() || Platform.isMac());
	}

	/**
	 * Returns whether or not subtitles should be disabled when using MEncoder
	 * as transcoding engine. Default is false, meaning subtitles should not
	 * be disabled.
	 * @return True if subtitles should be disabled, false otherwise.
	 */
	public boolean isMencoderDisableSubs() {
		return getBoolean(KEY_MENCODER_DISABLE_SUBS, false);
	}

	/**
	 * Returns whether or not the Pulse Code Modulation audio format should be
	 * forced when using MEncoder as transcoding engine. The default is false.
	 * @return True if PCM should be forced, false otherwise.
	 */
	public boolean isMencoderUsePcm() {
		return getBoolean(KEY_MENCODER_USE_PCM, false);
	}

	/**
	 * Returns the name of a TrueType font to use for MEncoder subtitles.
	 * Default is <code>""</code>.
	 * @return The font name.
	 */
	public String getMencoderFont() {
		return getString(KEY_MENCODER_FONT, "");
	}

	/**
	 * Returns the audio language priority for MEncoder as a comma separated
	 * string. For example: <code>"eng,fre,jpn,ger,und"</code>, where "und"
	 * stands for "undefined".
	 * @return The audio language priority string.
	 */
	public String getMencoderAudioLanguages() {
		return getString(KEY_MENCODER_AUDIO_LANGS, getDefaultLanguages());
	}

	/**
	 * Returns a string of comma separated audio or subtitle languages,
	 * ordered by priority. 
	 * @return The string of languages.
	 */
	private String getDefaultLanguages() {
		if ("fr".equals(getLanguage())) {
			return "fre,jpn,ger,eng,und";
		} else {
			return "eng,fre,jpn,ger,und";
		}
	}

	/**
	 * Returns the subtitle language priority for MEncoder as a comma
	 * separated string. For example: <code>"eng,fre,jpn,ger,und"</code>,
	 * where "und" stands for "undefined".
	 * @return The subtitle language priority string.
	 */
	public String getMencoderSubLanguages() {
		return getString(KEY_MENCODER_SUB_LANGS, getDefaultLanguages());
	}

	public String getMencoderForcedSubLanguage() {
		return getString(KEY_MENCODER_FORCED_SUB_LANG, getLanguage());
	}

	public String getMencoderForcedSubTags() {
  		return getString(KEY_MENCODER_FORCED_SUB_TAGS, "forced");
  	}

	/**
	 * Returns a string of audio language and subtitle language pairs
	 * ordered by priority for MEncoder to try to match. Audio language
	 * and subtitle language should be comma separated as a pair,
	 * individual pairs should be semicolon separated. "*" can be used to
	 * match any language. Subtitle language can be defined as "off". For
	 * example: <code>"en,off;jpn,eng;*,eng;*;*"</code>.
	 * Default value is <code>""</code>.
	 * @return The audio and subtitle languages priority string.
	 */
	public String getMencoderAudioSubLanguages() {
		return getString(KEY_MENCODER_AUDIO_SUB_LANGS, "");
	}

	/**
	 * Returns whether or not MEncoder should use FriBiDi mode, which
	 * is needed to display subtitles in languages that read from right to
	 * left, like Arabic, Farsi, Hebrew, Urdu, etc. Default value is false.
	 * @return True if FriBiDi mode should be used, false otherwise.
	 */
	public boolean isMencoderSubFribidi() {
		return getBoolean(KEY_MENCODER_SUB_FRIBIDI, false);
	}

	/**
	 * Returns the character encoding (or code page) that MEncoder should use
	 * for displaying subtitles. Default is "cp1252".
	 * @return The character encoding.
	 */
	public String getMencoderSubCp() {
		return getString(KEY_MENCODER_SUB_CP, "cp1252");
	}

	/**
	 * Returns whether or not MEncoder should use fontconfig for displaying
	 * subtitles. Default is false.
	 * @return True if fontconfig should be used, false otherwise.
	 */
	public boolean isMencoderFontConfig() {
		return getBoolean(KEY_MENCODER_FONT_CONFIG, false);
	}

	public void setMencoderForceFps(boolean value) {
		configuration.setProperty(KEY_MENCODER_FORCE_FPS, value);
	}

	public boolean isMencoderForceFps() {
		return getBoolean(KEY_MENCODER_FORCE_FPS, false);
	}

	public void setMencoderAudioLanguages(String value) {
		configuration.setProperty(KEY_MENCODER_AUDIO_LANGS, value);
	}

	public void setMencoderSubLanguages(String value) {
		configuration.setProperty(KEY_MENCODER_SUB_LANGS, value);
	}

	public void setMencoderForcedSubLanguage(String value) {
		configuration.setProperty(KEY_MENCODER_FORCED_SUB_LANG, value);
	}

	public void setMencoderForcedSubTags(String value) {
		configuration.setProperty(KEY_MENCODER_FORCED_SUB_TAGS, value);
	}

	public void setMencoderAudioSubLanguages(String value) {
		configuration.setProperty(KEY_MENCODER_AUDIO_SUB_LANGS, value);
	}

	public String getMencoderDecode() {
		return getString(KEY_MENCODER_DECODE, "");
	}

	public void setMencoderDecode(String value) {
		configuration.setProperty(KEY_MENCODER_DECODE, value);
	}

	public void setMencoderSubCp(String value) {
		configuration.setProperty(KEY_MENCODER_SUB_CP, value);
	}

	public void setMencoderSubFribidi(boolean value) {
		configuration.setProperty(KEY_MENCODER_SUB_FRIBIDI, value);
	}

	public void setMencoderFont(String value) {
		configuration.setProperty(KEY_MENCODER_FONT, value);
	}

	public void setMencoderAss(boolean value) {
		configuration.setProperty(KEY_MENCODER_ASS, value);
	}

	public void setMencoderFontConfig(boolean value) {
		configuration.setProperty(KEY_MENCODER_FONT_CONFIG, value);
	}

	public void setMencoderDisableSubs(boolean value) {
		configuration.setProperty(KEY_MENCODER_DISABLE_SUBS, value);
	}

	public void setMencoderUsePcm(boolean value) {
		configuration.setProperty(KEY_MENCODER_USE_PCM, value);
	}

	public boolean isArchiveBrowsing() {
		return getBoolean(KEY_OPEN_ARCHIVES, false);
	}

	public void setArchiveBrowsing(boolean value) {
		configuration.setProperty(KEY_OPEN_ARCHIVES, value);
	}

	public boolean isMencoderYadif() {
		return getBoolean(KEY_MENCODER_YADIF, false);
	}

	public void setMencoderYadif(boolean value) {
		configuration.setProperty(KEY_MENCODER_YADIF, value);
	}

	public boolean isMencoderScaler() {
		return getBoolean(KEY_MENCODER_SCALER, false);
	}

	public void setMencoderScaler(boolean value) {
		configuration.setProperty(KEY_MENCODER_SCALER, value);
	}

	public int getMencoderScaleX() {
		return getInt(KEY_MENCODER_SCALEX, 0);
	}

	public void setMencoderScaleX(int value) {
		configuration.setProperty(KEY_MENCODER_SCALEX, value);
	}

	public int getMencoderScaleY() {
		return getInt(KEY_MENCODER_SCALEY, 0);
	}

	public void setMencoderScaleY(int value) {
		configuration.setProperty(KEY_MENCODER_SCALEY, value);
	}

	public int getAudioChannelCount() {
		return getInt(KEY_AUDIO_CHANNEL_COUNT, 6);
	}

	public void setAudioChannelCount(int value) {
		configuration.setProperty(KEY_AUDIO_CHANNEL_COUNT, value);
	}

	public void setAudioBitrate(int value) {
		configuration.setProperty(KEY_AUDIO_BITRATE, value);
	}

	public String getMaximumBitrate() {
		return getString(KEY_MAX_BITRATE, "110");
	}

	public void setMaximumBitrate(String value) {
		configuration.setProperty(KEY_MAX_BITRATE, value);
	}

	public boolean getThumbnailsEnabled() {
		return getBoolean(KEY_THUMBNAILS_ENABLED, true);
	}

	public void setThumbnailsEnabled(boolean value) {
		configuration.setProperty(KEY_THUMBNAILS_ENABLED, value);
	}
	
	public boolean getImageThumbnailsEnabled() {
		return getBoolean(KEY_IMAGE_THUMBNAILS_ENABLED, true);
	}

	public void setImageThumbnailsEnabled(boolean value) {
		configuration.setProperty(KEY_IMAGE_THUMBNAILS_ENABLED, value);
	}

	public int getNumberOfCpuCores() {
		int nbcores = Runtime.getRuntime().availableProcessors();
		if (nbcores < 1) {
			nbcores = 1;
		}
		return getInt(KEY_NUMBER_OF_CPU_CORES, nbcores);
	}

	public void setNumberOfCpuCores(int value) {
		configuration.setProperty(KEY_NUMBER_OF_CPU_CORES, value);
	}

	public boolean isTurboModeEnabled() {
		return getBoolean(KEY_TURBO_MODE_ENABLED, false);
	}

	public void setTurboModeEnabled(boolean value) {
		configuration.setProperty(KEY_TURBO_MODE_ENABLED, value);
	}

	public boolean isMinimized() {
		return getBoolean(KEY_MINIMIZED, false);
	}

	public void setMinimized(boolean value) {
		configuration.setProperty(KEY_MINIMIZED, value);
	}

	public boolean getUseSubtitles() {
		return getBoolean(KEY_USE_SUBTITLES, true);
	}

	public void setUseSubtitles(boolean value) {
		configuration.setProperty(KEY_USE_SUBTITLES, value);
	}

	public boolean getHideVideoSettings() {
		return getBoolean(KEY_HIDE_VIDEO_SETTINGS, false);
	}

	public void setHideVideoSettings(boolean value) {
		configuration.setProperty(KEY_HIDE_VIDEO_SETTINGS, value);
	}

	public boolean getUseCache() {
		return getBoolean(KEY_USE_CACHE, false);
	}

	public void setUseCache(boolean value) {
		configuration.setProperty(KEY_USE_CACHE, value);
	}

	public void setAvisynthConvertFps(boolean value) {
		configuration.setProperty(KEY_AVISYNTH_CONVERT_FPS, value);
	}

	public boolean getAvisynthConvertFps() {
		return getBoolean(KEY_AVISYNTH_CONVERT_FPS, true);
	}

	public String getAvisynthScript() {
		return getString(KEY_AVISYNTH_SCRIPT, DEFAULT_AVI_SYNTH_SCRIPT);
	}

	public void setAvisynthScript(String value) {
		configuration.setProperty(KEY_AVISYNTH_SCRIPT, value);
	}

	public String getCodecSpecificConfig() {
		return getString(KEY_CODEC_SPEC_SCRIPT, "");
	}

	public void setCodecSpecificConfig(String value) {
		configuration.setProperty(KEY_CODEC_SPEC_SCRIPT, value);
	}

	public int getMaxAudioBuffer() {
		return getInt(KEY_MAX_AUDIO_BUFFER, 100);
	}

	public int getMinStreamBuffer() {  //for web stream?, really nobody use this 
		return getInt(KEY_MIN_STREAM_BUFFER, 1);   //MByte
	}
	public int getMinStreamBufferSecondary() {//for web stream?, really nobody use this
		return getInt(KEY_MIN_STREAM_BUFFER_SECONDARY, 100000); //Bytes
	}

	public boolean isFileBuffer() {  //for use file as buffer, only used by FFMpegVideo.java
		String bufferType = getString(KEY_BUFFER_TYPE, "").trim();
		return bufferType.equals(BUFFER_TYPE_FILE);
	}

	public void setFfmpegSettings(String value) {
		configuration.setProperty(KEY_FFMPEG_SETTINGS, value);
	}

	public String getFfmpegSettings() {
		return getString(KEY_FFMPEG_SETTINGS, "-threads 2 -g 1 -qscale 1 -qmin 2");
	}

	public boolean isMencoderNoOutOfSync() {
		return getBoolean(KEY_MENCODER_NO_OUT_OF_SYNC, true);
	}

	public void setMencoderNoOutOfSync(boolean value) {
		configuration.setProperty(KEY_MENCODER_NO_OUT_OF_SYNC, value);
	}

	public boolean getTrancodeBlocksMultipleConnections() {
		return configuration.getBoolean(KEY_TRANSCODE_BLOCKS_MULTIPLE_CONNECTIONS, false);
	}

	public void setTranscodeBlocksMultipleConnections(boolean value) {
		configuration.setProperty(KEY_TRANSCODE_BLOCKS_MULTIPLE_CONNECTIONS, value);
	}

	public boolean getTrancodeKeepFirstConnections() {
		return configuration.getBoolean(KEY_TRANSCODE_KEEP_FIRST_CONNECTION, true);
	}

	public void setTrancodeKeepFirstConnections(boolean value) {
		configuration.setProperty(KEY_TRANSCODE_KEEP_FIRST_CONNECTION, value);
	}

	public String getCharsetEncoding() {
		return getString(KEY_CHARSET_ENCODING, "850");
	}

	public void setCharsetEncoding(String value) {
		configuration.setProperty(KEY_CHARSET_ENCODING, value);
	}

	public boolean isMencoderIntelligentSync() {
		return getBoolean(KEY_MENCODER_INTELLIGENT_SYNC, true);
	}

	public void setMencoderIntelligentSync(boolean value) {
		configuration.setProperty(KEY_MENCODER_INTELLIGENT_SYNC, value);
	}

	public String getFfmpegAlternativePath() {
		return getString(KEY_FFMPEG_ALTERNATIVE_PATH, null);
	}

	public void setFfmpegAlternativePath(String value) {
		configuration.setProperty(KEY_FFMPEG_ALTERNATIVE_PATH, value);
	}

	public boolean getSkipLoopFilterEnabled() {
		return getBoolean(KEY_SKIP_LOOP_FILTER_ENABLED, false);
	}
	
	/**
	 * The list of network interfaces that should be skipped when checking
	 * for an available network interface. Entries should be comma separated
	 * and typically exclude the number at the end of the interface name.
	 * <p>
	 * Default is to skip the interfaces created by Virtualbox, OpenVPN and
	 * Parallels: "tap,vmnet,vnic".
	 * @return The string of network interface names to skip.
	 */
	public List<String> getSkipNetworkInterfaces() {
		return getStringList(KEY_SKIP_NETWORK_INTERFACES, "tap,vmnet,vnic");
	}
	
	public void setSkipLoopFilterEnabled(boolean value) {
		configuration.setProperty(KEY_SKIP_LOOP_FILTER_ENABLED, value);
	}

	public String getMencoderMainSettings() {
		return getString(KEY_MENCODER_MAIN_SETTINGS, "keyint=5:vqscale=1:vqmin=2");
	}

	public void setMencoderMainSettings(String value) {
		configuration.setProperty(KEY_MENCODER_MAIN_SETTINGS, value);
	}

	public String getMencoderVobsubSubtitleQuality() {
		return getString(KEY_MENCODER_VOBSUB_SUBTITLE_QUALITY, "3");
	}

	public void setMencoderVobsubSubtitleQuality(String value) {
		configuration.setProperty(KEY_MENCODER_VOBSUB_SUBTITLE_QUALITY, value);
	}

	public String getMencoderOverscanCompensationWidth() {
		return getString(KEY_MENCODER_OVERSCAN_COMPENSATION_WIDTH, "0");
	}

	public void setMencoderOverscanCompensationWidth(String value) {
		if (value.trim().length() == 0) {
			value = "0";
		}
		configuration.setProperty(KEY_MENCODER_OVERSCAN_COMPENSATION_WIDTH, value);
	}

	public String getMencoderOverscanCompensationHeight() {
		return getString(KEY_MENCODER_OVERSCAN_COMPENSATION_HEIGHT, "0");
	}

	public void setMencoderOverscanCompensationHeight(String value) {
		if (value.trim().length() == 0) {
			value = "0";
		}
		configuration.setProperty(KEY_MENCODER_OVERSCAN_COMPENSATION_HEIGHT, value);
	}

	public int getLoggingLevel() {
		return getInt(KEY_LOGGING_LEVEL, 2);
	}

	public void setEnginesAsList(ArrayList<String> enginesAsList) {
		configuration.setProperty(KEY_ENGINES, listToString(enginesAsList));
	}

	public List<String> getEnginesAsList(SystemUtils registry) {
		List<String> engines = stringToList(getString(KEY_ENGINES, "mencoder,avsmencoder,tsmuxer,mplayeraudio,ffmpegaudio,tsmuxeraudio,vlcvideo,mencoderwebvideo,mplayervideodump,mplayerwebaudio,vlcaudio,ffmpegdvrmsremux,rawthumbs"));
		engines = hackAvs(registry, engines);
		return engines;
	}

	private static String listToString(List<String> enginesAsList) {
		return StringUtils.join(enginesAsList, LIST_SEPARATOR);
	}

	private static List<String> stringToList(String input) {
		List<String> output = new ArrayList<String>();
		Collections.addAll(output, StringUtils.split(input, LIST_SEPARATOR));
		return output;
	}
	// TODO: Get this out of here
	private static boolean avsHackLogged = false;

	// TODO: Get this out of here
	private static List<String> hackAvs(SystemUtils registry, List<String> input) {
		List<String> toBeRemoved = new ArrayList<String>();
		for (String engineId : input) {
			if (engineId.startsWith("avs") && !registry.isAvis() && Platform.isWindows()) {
				if (!avsHackLogged) {
					logger.info("AviSynth is not installed. You cannot use " + engineId + " as a transcoding engine.");
					avsHackLogged = true;
				}
				toBeRemoved.add(engineId);
			}
		}
		List<String> output = new ArrayList<String>();
		output.addAll(input);
		output.removeAll(toBeRemoved);
		return output;
	}

	public void save() throws ConfigurationException {
		configuration.save();
		logger.info("Configuration saved to: " + PROFILE_PATH);
	}

	public String getFolders() {
		return getString(KEY_FOLDERS, "");
	}

	public void setFolders(String value) {
		configuration.setProperty(KEY_FOLDERS, value);
	}

	public String getNetworkInterface() {
		return getString(KEY_NETWORK_INTERFACE, "");
	}

	public void setNetworkInterface(String value) {
		configuration.setProperty(KEY_NETWORK_INTERFACE, value);
	}

	public boolean isHideEngineNames() {
		return getBoolean(KEY_HIDE_ENGINENAMES, false);
	}

	public void setHideEngineNames(boolean value) {
		configuration.setProperty(KEY_HIDE_ENGINENAMES, value);
	}

	public boolean isHideExtensions() {
		return getBoolean(KEY_HIDE_EXTENSIONS, false);
	}

	public void setHideExtensions(boolean value) {
		configuration.setProperty(KEY_HIDE_EXTENSIONS, value);
	}

	public String getShares() {
		return getString(KEY_SHARES, "");
	}

	public void setShares(String value) {
		configuration.setProperty(KEY_SHARES, value);
	}

	public String getNoTranscode() {
		return getString(KEY_NOTRANSCODE, "");
	}

	public void setNoTranscode(String value) {
		configuration.setProperty(KEY_NOTRANSCODE, value);
	}

	public String getForceTranscode() {
		return getString(KEY_FORCETRANSCODE, "");
	}

	public void setForceTranscode(String value) {
		configuration.setProperty(KEY_FORCETRANSCODE, value);
	}

	public void setMencoderMT(boolean value) {
		configuration.setProperty(KEY_MENCODER_MT, value);
	}

	public boolean getMencoderMT() {
		boolean isMultiCore = getNumberOfCpuCores() > 1;
		return getBoolean(KEY_MENCODER_MT, isMultiCore);
	}

	public void setRemuxAC3(boolean value) {
		configuration.setProperty(KEY_MENCODER_REMUX_AC3, value);
	}

	public boolean isRemuxAC3() {
		return getBoolean(KEY_MENCODER_REMUX_AC3, true);
	}

	public void setMencoderRemuxMPEG2(boolean value) {
		configuration.setProperty(KEY_MENCODER_REMUX_MPEG2, value);
	}

	public boolean isMencoderRemuxMPEG2() {
		return getBoolean(KEY_MENCODER_REMUX_MPEG2, true);
	}

	public void setDisableFakeSize(boolean value) {
		configuration.setProperty(KEY_DISABLE_FAKESIZE, value);
	}

	public boolean isDisableFakeSize() {
		return getBoolean(KEY_DISABLE_FAKESIZE, false);
	}

	public void setMencoderAssDefaultStyle(boolean value) {
		configuration.setProperty(KEY_MENCODER_ASS_DEFAULTSTYLE, value);
	}

	public boolean isMencoderAssDefaultStyle() {
		return getBoolean(KEY_MENCODER_ASS_DEFAULTSTYLE, false);
	}

	public int getMEncoderOverscan() {
		return getInt(KEY_OVERSCAN, 0);
	}

	public void setMEncoderOverscan(int value) {
		configuration.setProperty(KEY_OVERSCAN, value);
	}

	/**
	 * Returns sort method to use for ordering lists of files. One of the
	 * following values is returned:
	 * <ul>
	 * <li>0: Locale-sensitive A-Z</li>
	 * <li>1: Sort by modified date, newest first</li>
	 * <li>2: Sort by modified date, oldest first</li>
	 * <li>3: Case-insensitive ASCIIbetical sort</li>
	 * <li>4: Locale-sensitive natural sort</li>
	 * </ul>
	 * Default value is 0.
	 * @return The sort method
	 */
	public int getSortMethod() {
		return getInt(KEY_SORT_METHOD, 0);
	}

	/**
	 * Set the sort method to use for ordering lists of files. The following
	 * values are recognized:
	 * <ul>
	 * <li>0: Locale-sensitive A-Z</li>
	 * <li>1: Sort by modified date, newest first</li>
	 * <li>2: Sort by modified date, oldest first</li>
	 * <li>3: Case-insensitive ASCIIbetical sort</li>
	 * <li>4: Locale-sensitive natural sort</li>
	 * </ul>
	 * @param value The sort method to use
	 */
	public void setSortMethod(int value) {
		configuration.setProperty(KEY_SORT_METHOD, value);
	}

	public int getAudioThumbnailMethod() {
		return getInt(KEY_AUDIO_THUMBNAILS_METHOD, 0);
	}

	public void setAudioThumbnailMethod(int value) {
		configuration.setProperty(KEY_AUDIO_THUMBNAILS_METHOD, value);
	}

	public String getAlternateThumbFolder() {
		return getString(KEY_ALTERNATE_THUMB_FOLDER, "");
	}

	public void setAlternateThumbFolder(String value) {
		configuration.setProperty(KEY_ALTERNATE_THUMB_FOLDER, value);
	}

	public String getAlternateSubsFolder() {
		return getString(KEY_ALTERNATE_SUBS_FOLDER, "");
	}

	public void setAlternateSubsFolder(String value) {
		configuration.setProperty(KEY_ALTERNATE_SUBS_FOLDER, value);
	}

	public void setDTSEmbedInPCM(boolean value) {
		configuration.setProperty(KEY_EMBED_DTS_IN_PCM, value);
	}

	public boolean isDTSEmbedInPCM() {
		return getBoolean(KEY_EMBED_DTS_IN_PCM, false);
	}

	public void setMencoderMuxWhenCompatible(boolean value) {
		configuration.setProperty(KEY_MENCODER_MUX_COMPATIBLE, value);
	}

	public boolean isMencoderMuxWhenCompatible() {
		return getBoolean(KEY_MENCODER_MUX_COMPATIBLE, true);
	}

	public void setMuxAllAudioTracks(boolean value) {
		configuration.setProperty(KEY_MUX_ALLAUDIOTRACKS, value);
	}

	public boolean isMuxAllAudioTracks() {
		return getBoolean(KEY_MUX_ALLAUDIOTRACKS, false);
	}

	public void setUseMplayerForVideoThumbs(boolean value) {
		configuration.setProperty(KEY_USE_MPLAYER_FOR_THUMBS, value);
	}

	public boolean isUseMplayerForVideoThumbs() {
		return getBoolean(KEY_USE_MPLAYER_FOR_THUMBS, false);
	}

	public String getIpFilter() {
		return getString(KEY_IP_FILTER, "");
	}
	
	public synchronized IpFilter getIpFiltering() {
	    filter.setRawFilter(getIpFilter());
	    return filter;
	}

	public void setIpFilter(String value) {
		configuration.setProperty(KEY_IP_FILTER, value);
	}

	public void setPreventsSleep(boolean value) {
		configuration.setProperty(KEY_PREVENTS_SLEEP, value);
	}

	public boolean isPreventsSleep() {
		return getBoolean(KEY_PREVENTS_SLEEP, false);
	}

	public void setHTTPEngineV2(boolean value) {
		configuration.setProperty(KEY_HTTP_ENGINE_V2, value);
	}

	public boolean isHTTPEngineV2() {
		return getBoolean(KEY_HTTP_ENGINE_V2, true);
	}

	public boolean getIphotoEnabled() {
		return getBoolean(KEY_IPHOTO_ENABLED, false);
	}

	public void setIphotoEnabled(boolean value) {
		configuration.setProperty(KEY_IPHOTO_ENABLED, value);
	}
	
	public boolean getApertureEnabled() {
		return getBoolean(KEY_APERTURE_ENABLED, false);
	}

	public void setApertureEnabled(boolean value) {
		configuration.setProperty(KEY_APERTURE_ENABLED, value);
	}

	public boolean getItunesEnabled() {
		return getBoolean(KEY_ITUNES_ENABLED, false);
	}

	public void setItunesEnabled(boolean value) {
		configuration.setProperty(KEY_ITUNES_ENABLED, value);
	}

	public boolean isHideEmptyFolders() {
		return getBoolean(PmsConfiguration.KEY_HIDE_EMPTY_FOLDERS, false);
	}

	public void setHideEmptyFolders(final boolean value) {
		this.configuration.setProperty(PmsConfiguration.KEY_HIDE_EMPTY_FOLDERS, value);
	}

	public boolean isHideMediaLibraryFolder() {
		return getBoolean(PmsConfiguration.KEY_HIDE_MEDIA_LIBRARY_FOLDER, false);
	}

	public void setHideMediaLibraryFolder(final boolean value) {
		this.configuration.setProperty(PmsConfiguration.KEY_HIDE_MEDIA_LIBRARY_FOLDER, value);
	}

	public boolean getHideTranscodeEnabled() {
		return getBoolean(KEY_HIDE_TRANSCODE_FOLDER, false);
	}

	public void setHideTranscodeEnabled(boolean value) {
		configuration.setProperty(KEY_HIDE_TRANSCODE_FOLDER, value);
	}

	public boolean isDvdIsoThumbnails() {
		return getBoolean(KEY_DVDISO_THUMBNAILS, false);
	}

	public void setDvdIsoThumbnails(boolean value) {
		configuration.setProperty(KEY_DVDISO_THUMBNAILS, value);
	}

	public Object getCustomProperty(String property) {
		return configuration.getProperty(property);
	}

	public void setCustomProperty(String property, Object value) {
		configuration.setProperty(property, value);
	}

	public boolean isChapterSupport() {
		return getBoolean(KEY_CHAPTER_SUPPORT, false);
	}

	public void setChapterSupport(boolean value) {
		configuration.setProperty(KEY_CHAPTER_SUPPORT, value);
	}

	public int getChapterInterval() {
		return getInt(KEY_CHAPTER_INTERVAL, 5);
	}

	public void setChapterInterval(int value) {
		configuration.setProperty(KEY_CHAPTER_INTERVAL, value);
	}

	public int getSubsColor() {
		return getInt(KEY_SUBS_COLOR, 0xffffffff);
	}

	public void setSubsColor(int value) {
		configuration.setProperty(KEY_SUBS_COLOR, value);
	}

	public boolean isFix25FPSAvMismatch() {
		return getBoolean(KEY_FIX_25FPS_AV_MISMATCH, false);
	}

	public void setFix25FPSAvMismatch(boolean value) {
		configuration.setProperty(KEY_FIX_25FPS_AV_MISMATCH, value);
	}

	public int getVideoTranscodeStartDelay() {
		//return getInt(KEY_VIDEOTRANSCODE_START_DELAY, 6);	//origin
		return getInt(KEY_VIDEOTRANSCODE_START_DELAY, 6000);	// regzamod,change to sec to mili-sec
	}

	public void setVideoTranscodeStartDelay(int value) {
		configuration.setProperty(KEY_VIDEOTRANSCODE_START_DELAY, value);
	}

	public boolean isAudioResample() {
		return getBoolean(KEY_AUDIO_RESAMPLE, true);
	}

	public void setAudioResample(boolean value) {
		configuration.setProperty(KEY_AUDIO_RESAMPLE, value);
	}

	public String getVirtualFolders() {
		return getString(KEY_VIRTUAL_FOLDERS, "");
	}


	public String getPluginDirectory() {
		return getString(KEY_PLUGIN_DIRECTORY, "plugins");
	}

	public void setPluginDirectory(String value) {
		configuration.setProperty(KEY_PLUGIN_DIRECTORY, value);
	}

	public String getProfileName() {
		if(getRZ_machine_name()!=null) {
			return getRZ_machine_name();  //regzamod
		}
		if (HOSTNAME == null) { // calculate this lazily
			try {
				HOSTNAME = InetAddress.getLocalHost().getHostName();
			} catch (UnknownHostException e) {
				logger.info("Can't determine hostname");
				HOSTNAME = "unknown host";
			}
		}
		return getString(KEY_PROFILE_NAME, HOSTNAME);
	}

	public boolean isAutoUpdate() {
		return Build.isUpdatable() && configuration.getBoolean(KEY_AUTO_UPDATE, false);
	}

	public void setAutoUpdate(boolean value) {
		configuration.setProperty(KEY_AUTO_UPDATE, value);
	}

	public String getIMConvertPath() {
		return programPaths.getIMConvertPath();
	}

	public int getUpnpPort() {
		return getInt(KEY_UPNP_PORT, 1900);
	}

	public String getUuid() {
		return getString(KEY_UUID, null);
	}

	public void setUuid(String value){
		configuration.setProperty(KEY_UUID, value);
	}

	public void addConfigurationListener(ConfigurationListener l) {
		configuration.addConfigurationListener(l);
	}

	public void removeConfigurationListener(ConfigurationListener l) {
		configuration.removeConfigurationListener(l);
	}
}
