/*
you can use fb.trace(something) to output variables/strings/properties to the Console
and it will be used in some examples below.
any parameters in [] are optional and may be omitted.

any undocumented references to "handle" mean a single playlist item like
fb.GetFocusItem();
fb.GetNowPlaying();
plman.GetPlaylistItems(plman.ActivePlaylist).Item(0) //first item in active playlist

any undocumented references to "handle_list" means multiple playlist or library items like
plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
fb.GetLibraryItems();
*/

interface IFbUtils {
	Properties:
		fb.ComponentPath; (string) (read)
		// example: fb.trace(fb.ComponentPath);
		// C:\Users\User\AppData\Roaming\foobar2000\user-components\foo_jscript_panel\

		fb.CursorFollowPlayback; (boolean) (read, write)

		fb.FoobarPath; (string) (read)

		fb.IsPaused; (boolean) (read)

		fb.IsPlaying; (boolean) (read)

		fb.PlaybackLength; (double) (read)
		/*
		example1: fb.trace(fb.PlaybackLength);
		322.843414966166
		example2: fb.trace(Math.round(fb.PlaybackLength));
		323
		*/

		fb.PlaybackFollowCursor; (boolean) (read, write)

		fb.PlaybackTime; (double) (read, write)
		// example: fb.PlaybackTime = 60;
		// jumps to the 1 minute mark.

		fb.ProfilePath; (string) (read)
		fb.StopAfterCurrent; (boolean) (read, write)
		// example: fb.StopAfterCurrent = !fb.StopAfterCurrent;
		// toggles the current value.

		fb.Volume; (float) (read, write);
		// example: fb.Volume = 0;
		// sets the volume to max. -100 is the minimum.

	Methods:
		fb.AcquireUiSelectionHolder(); (IFbUiSelectionHolder)

			interface IFbUiSelectionHolder {
				Methods:
					Dispose(); (void)
					SetSelection(handle_list); (void)
					// sets the selected items.

					SetPlaylistSelectionTracking(); (void)
					/*
					sets selected items to playlist selection and enables tracking.
					when the playlist selection changes, the stored selection is automatically
					updated. tracking ends when a set method is called on any ui_selection_holder
					or when the last reference to this ui_selection_holder is released.
					*/

					SetPlaylistTracking(); (void)
					/*
					sets selected items to playlist selection and enables tracking.
					when the playlist selection changes, the stored selection is automatically
					updated. tracking ends when a set method is called on any ui_selection_holder
					or when the last reference to this ui_selection_holder is released.
					*/
			}

		fb.AddDirectory(); (void)

		fb.AddFiles(); (void)

		fb.ClearPlaylist(); (void)
		// clears active playlist.
		// if you wish to clear a specific playlist, use plman.ClearPlaylist(playlistIndex).

		fb.CreateContextMenuManager(); (IContextMenuManager)

			interface IContextMenuManager {
				// see samples\basic\MainMenuManager All-In-One, samples\basic\Menu Sample.txt

				Methods:
					BuildMenu(IMenuObj, base_id, max_id); (void)

					Dispose(); (void)

					ExecuteByID(id); (boolean)

					InitContext(handle_or_handle_list); (void)

					InitNowPlaying(); (void)
			}

		fb.CreateMainMenuManager(); (IMainMenuManager)

			interface IMainMenuManager {
				// see samples\basic\MainMenuManager All-In-One, samples\basic\Menu Sample.txt

				Methods:
					BuildMenu(IMenuObj, base_id, count); (void)

					Dispose(); (void)

					ExecuteByID(id); (boolean)

					Init(root_name); (void)
			}

		fb.CreateProfiler([name]); (IFbProfiler)

			interface IFbProfiler {
				Properties:
					Time; (int) // milliseconds

				Methods:
					Reset(); (void)
					Print(); (void)
				}

				/*
				example:
				var test = fb.CreateProfiler();
				// do something very time consuming
				fb.trace(test.Time);
				*/

		fb.Exit(); (void)

		fb.GetFocusItem([force]); (IFbMetadbHandle)
		// force: boolean, default true. when true, it will use the first item of the active playlist
		// if it is unable to get the focus item.

		fb.GetLibraryItems(); (IFbMetadbHandleList)
		// returns all Media Library items as a handle list.
		
		fb.GetLibraryRelativePath(handle); (string)
		/* 
		returns an empty string when used on track not in Media Library
		
		example:
		the foobar2000 Media Library is configured to watch "D:\Music" and the
		path of the now playing item is "D:\Music\Albums\Artist\Some Album\Some Song.flac"
		
		var handle = fb.GetNowPlaying();
		fb.trace(fb.GetLibraryRelativePath(handle));
		
		outputs "Albums\Artist\Some Album\Some Song.flac"
		
		NOTE: If you intend to loop through a large handle list and you have no control over what is
		happening in the background, consider using try/catch as errors may occur if the Media Library
		settings/content changes.
		*/
		
		fb.GetNowPlaying(); (IFbMetadbHandle)
		// get handle of now playing item.

		fb.GetQueryItems(handle_list, query); (IFbMetadbHandleList)
		/*
		example1: var a = fb.GetQueryItems(plman.GetPlaylistItems(plman.ActivePlaylist), "rating IS 5");
		example2: var b = fb.GetQueryItems(fb.GetLibraryItems(), "rating IS 5");
		results are unsorted

		NOTE: use try/catch to handle invalid queries. An empty handle list will be returned if the query
		is valid but there are no results.
		*/

		fb.GetSelection(); (IFbMetadbHandle)
		/*
		gets now playing or selected item. what you get will depend on
		"File>Preferences>Display>Selection viewers".
		the return value may be null.
		*/

		fb.GetSelections([flags]); (IFbMetadbHandleList)
		/*
		flags: 0 default, 1 no now playing
		works like GetSelection(), but returns a handle list.
		always returns a valid handle list instance instead of null.
		*/

		fb.GetSelectionType(); (uint)
		/*
		retrieve what the selection is
		0 undefined (no item)
		1 active_playlist_selection
		2 caller_active_playlist
		3 playlist_manager
		4 now_playing
		5 keyboard_shortcut_list
		6 media_library_viewer
		*/

		fb.IsLibraryEnabled(); (boolean)

		fb.IsMetadbInMediaLibrary(handle); (boolean)
		// example: fb.trace(fb.IsMetadbInMediaLibrary(fb.GetNowplaying()));
		// if false, playing track is not in Media Library

		fb.LoadPlaylist(); (void)

		fb.Next(); (void)

		fb.Pause(); (void)

		fb.Play(); (void)

		fb.PlayOrPause(); (void)

		fb.Stop(); (void)

		fb.Prev(); (void)

		fb.Random(); (void)

		fb.RunContextCommand(command[, flags]); (boolean)
		/*
		now playing file only.
		flags:
		0 default (depends on whether SHIFT key is pressed, flag_view_reduced or flag_view_full is selected)
		4 flag_view_reduced
		8 flag_view_full. this can be useful if you need to run context commands the user may have hidden
		  using File>Preferences>Display>Context Menu
		example: fb.RunContextCommand("Properties");
		*/

		fb.RunContextCommandWithMetadb(command, handle_or_handle_list[, flags]); (boolean)
		// same flags as fb.RunContextCommand. handle_or_handle_list can be something like fb.GetFocusItem()
		// or plman.GetPlaylistSelectedItems(plman.ActivePlaylist)

		fb.RunMainMenuCommand(command); (boolean)
		//example: fb.RunMainMenuCommand("File/Add Location...");

		fb.SavePlaylist(); (void)

		fb.ShowConsole(); (void)

		fb.ShowLibrarySearchUI(query); (void)
		// opens the Library>Search window populated with the query you set.

		fb.ShowPopupMessage(msg[, title][, iconid]); (void)
		// title: default "JScript Panel"
		// iconid: default 0 see flags.txt > IconId

		fb.ShowPreferences(); (void)

		fb.TitleFormat(expression); (IFbTitleFormat)

			interface IFbTitleFormat {
				// this will be used in the examples below.
				// var tfo = fb.TitleFormat("%artist%");

				Methods:
					Dispose();
					// example: tfo.Dispose();

					Eval([force]);
					/*
					force: boolean, default false. if true, you can process text that doesn't contain 
						   title formatting even when foobar2000 isn't playing. when playing, you
						   should always get a result.
					
					always use eval when you want dynamic info such as %playback_time%, %bitrate% etc.
					EvalWithMetadb(fb.GetNowplaying()) will not give the results you want.
					example: fb.trace(tfo.Eval());
					*/

					EvalWithMetadb(handle);
					// example: fb.trace(tfo.EvalWithMetadb(fb.GetFocusItem()));
			}

		fb.trace(message); (void)

		fb.VolumeDown(); (void)

		fb.VolumeMute(); (void)

		fb.VolumeUp(); (void)
}

interface IGdiUtils {
	Methods:
		gdi.CreateImage(w, h); (IGdiBitmap)

		gdi.CreateStyleTextRender([pngmode]); (IStyleTextRender)
		// pngmode: boolean, default false.
		// see samples\basic\Glow Text Sample.txt

			interface IStyleTextRender {
				Methods:
					// ---- outline mode ----
					OutLineText(text_color, outline_color, outline_width);
					DoubleOutLineText(text_color, outline_color1, outline_color2, outline_width1, outline_width2);
					GlowText(text_color, glow_color, glow_width);

					// ---- shadow ----
					EnableShadow(enable);
					ResetShadow();
					// it's recommended to call ResetShadow() directly after EnableShadow()
					Shadow(color, thickness, offset_x, offset_y);
					// default shadow, used in solid shadow colour
					DiffusedShadow(colour, thickness, offset_x, offset_y);
					// soft shadow

					// while using DiffusedShadow(), these two methods below are useful
					SetShadowBackgroundColor(colour, width, height);
					SetShadowBackgroundImage(img);

					// ---- Render ----
					// Not recommended if the flags contains something like "center". it won't
					// work properly because of the lack of width and height information.
					RenderStringPoint(g, str, font, x, y[, flags]);
					RenderStringRect(g, str, font, x, y, w, h[, flags]);
					SetPngImage(IGdiBitmap);
					// Only in pngmode, the image should be a transparent image created by gdi.CreateImage().
			}

		gdi.Font(name, size px[, style]); (IGdiFont)
		// size px: see helpers.txt > Point2Pixel function for conversions.
		// style: default 0. see flags.txt > FontStyle

		gdi.Image(path); (IGdiBitmap)
		// example: var img = "e:\\images folder\\my_image.png";
		// note that you must escape backslashes whenever they are in quotes.

		gdi.LoadImageAsync(window_id, path); (uint)
		// returns a unqiue id. see samples\basic\LoadImageAsync.txt
}

interface IFbPlaylistManager {
	Properties:
		plman.ActivePlaylist; (uint) (read, write)
		/*
		example1: fb.trace(plman.ActivePlaylist);
		0 this is the first playlist.
		example2: plman.ActivePlaylist = 1;
		switches to 2nd playlist.
		*/

		plman.PlaybackOrder; (uint) (read, write)
		/*
		0 Default
		1 Repeat (Playlist)
		2 Repeat (Track)
		3 Random
		4 Shuffle (tracks)
		5 Shuffle (albums)
		6 Shuffle (folders)
		see samples\basic\PBOButton(Menu).txt.
		*/

		plman.PlayingPlaylist; (uint) (read, write)

		plman.PlaylistCount; (uint) (read)

		plman.PlaylistItemCount(playlistIndex); (uint) (read)
		// example: fb.trace(plman.PlaylistItemCount(plman.PlayingPlaylist));
		// 12

		plman.PlaylistRecyclerManager; (IFbPlaylistRecyclerManager) (read)

			interface PlaylistRecyclerManager {
				Properties:
					Count; (uint) (read)
					Name(index); (string) (read)
					Content(index); (IFbMetadbHandleList) (read)
					Id(index); (uint) (read)

				Methods:
					FindById(id); (uint)
					Purge(affectedItems); (void)
					// affectedItems: array like [1, 3, 5]

					Restore(index); (void)
					RestoreById(id); (void)
					//returns the index
			}

	Methods:
		plman.AddLocations(playlistIndex, paths[, select]); (void)
		/*
		paths: an array of files/URLs
		select: boolean, default false
		example: plman.AddLocations(plman.ActivePlaylist, ["e:\\1.mp3"]);
		*/

		plman.ClearPlaylist(playlistIndex); (void)
		// unlike fb.ClearPlaylist which clears the active playlist, this requires a "playlistIndex" argument.
		// example: plman.ClearPlaylist(0);

		plman.ClearPlaylistSelection(playlistIndex); (void)
		// example: plman.ClearPlaylistSelection(plman.ActivePlaylist);

		plman.CreateAutoPlaylist(playlistIndex, name, query[, sort][, flags]); (uint)
		// sort: default "". title formatting pattern.
		// flags: default 0, force sort 1

		plman.CreatePlaylist(playlistIndex, name); (uint)
		/*
		example1: plman.CreatePlaylist(0, "");
		creates a new playlist first in the list and it will be named "New playlist"
		numbers will be appended to the end for each new un-named playlist
		example2: plman.CreatePlaylist(plman.PlaylistCount, "my favourites");
		this will be added at the end of the current playlists
		*/

		plman.DuplicatePlaylist(playlistIndex, name); (uint)
		/*
		playlistIndex: source playlist. duplicate playlist gets inserted directly after the source.
		if name is "", name of source playlist is used.
		this duplicates playlist content, not the properties of the playlist eg. Autoplaylist
		*/

		plman.EnsurePlaylistItemVisible(playlistIndex, itemIndex); (void)

		plman.ExecutePlaylistDefaultAction(playlistIndex, playlistItemIndex); (boolean)
		// starts playback by executing default doubleclick/enter action
		// unless overridden by a lock to do something else.

		plman.GetPlayingItemLocation(); (IFbPlayingItemLocation)
		// retrieves playlist position of currently playing item.
		// on failure, the property "IsValid" of IFbPlayingItemLocation interface will be set to false.

			interface IFbPlayingItemLocation {
				Properties:
					IsValid; (boolean) (read)
					PlaylistIndex; (uint) (read)
					PlaylistItemIndex; (uint) (read)
			}

			/*
			example:
			var playing_item_location = plman.GetPlayingItemLocation();
			if (playing_item_location.IsValid) {
				fb.trace(playing_item_location.PlaylistIndex);
				fb.trace(playing_item_location.PlaylistItemIndex);
			}
			*/

		plman.GetPlaylistFocusItemIndex(playlistIndex); (int)
		// example: var focus_item_index = plman.GetPlaylistFocusItemIndex(plman.ActivePlaylist); // 0 first item
		// returns -1 if nothing is selected

		plman.GetPlaylistItems(playlistIndex); (IFbMetadbHandleList)
		// example: var handle_list = plman.GetPlaylistItems(plman.PlayingPlaylist);

		plman.GetPlaylistName(playlistIndex); (string)
		// example: fb.trace(plman.GetPlaylistName(plman.ActivePlaylist));

		plman.GetPlaylistSelectedItems(playlistIndex); (IFbMetadbHandleList)
		// example: var selected_items = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);

		plman.InsertPlaylistItems(playlistIndex, base, handle_list[, select]); (uint)
		/*
		select: boolean, default false.
		inserts new items into specified playlist, at specified position

		example1:
		var ap = plman.ActivePlaylist;
		plman.InsertPlaylistItems(ap, 0, fb.GetLibraryItems());
		adds all library tracks to beginning of playlist.

		example2:
		var ap = plman.ActivePlaylist;
		plman.InsertPlaylistItems(ap, plman.PlaylistItemCount(ap), fb.GetLibraryItems());
		adds all library tracks to end of playlist.
		*/

		plman.InsertPlaylistItemsFilter(playlistIndex, base, handle_list, select = false); (uint)
		// same as above except any duplicates contained in handle_list are removed.

		plman.IsAutoPlaylist(playlistIndex); (boolean)

		plman.IsPlaylistItemSelected(playlistIndex, itemIndex); (boolean)
		// returns true/false

		plman.IsPlaylistLocked(playlistIndex); (boolean)
		/* Note: this returns true if the playlist is an autoplaylist.
		To determine if a playlist is not an autoplaylist but locked with something like foo_utils or
		foo_playlist_attributes, do something like...

		if (!plman.IsAutoPlaylist(plman.ActivePlaylist) && plman.IsPlaylistLocked(plman.ActivePlaylist)) {
			blah();
		}
		*/

		plman.MovePlaylist(from, to); (boolean)

		plman.MovePlaylistSelection(playlistIndex, delta); (void)
		// example:
		// plman.MovePlaylistSelection(plman.ActivePlaylist, plman.PlaylistItemCount(plman.ActivePlaylist));
		// sends selected items to end of playlist.

		plman.RemovePlaylist(playlistIndex); (boolean)

		plman.RemovePlaylistSelection(playlistIndex[, crop]); (boolean)
		/*
		crop: boolean, default false.
		example1: plman.RemovePlaylistSelection(plman.ActivePlaylist);
		removes selected items from playlist.
		example2: plman.RemovePlaylistSelection(plman.ActivePlaylist, true);
		removes items that are NOT selected.
		*/

		plman.RenamePlaylist(playlistIndex, name); (boolean)

		plman.SetActivePlaylistContext(); (void)
		// workaround so you can run fb.RunMainMenuCommand() on the Edit menu when the playlist doesn't have focus.

		plman.SetPlaylistFocusItem(playlistIndex, itemIndex); (void)
		// example: plman.SetPlaylistFocusItem(plman.ActivePlaylist, 0);

		plman.SetPlaylistFocusItemByHandle(playlistIndex, handle); (void)
		/*
		example:
		var ap = plman.ActivePlaylist;
		var handle = plman.GetPlaylistItems(ap).Item(1); //2nd item in playlist
		plman.SetPlaylistFocusItemByHandle(ap, handle);
		*/

		plman.SetPlaylistSelection(playlistIndex, affectedItems, state); (void)
		/*
		affectedItems: array of item indexes.
		state: boolean.
		example: plman.SetPlaylistSelection(plman.ActivePlaylist, [0, 2, 4], true);
		selects tracks first, third and fifth tracks in playlist.
		note this does not affect other selected items.
		*/

		plman.SetPlaylistSelectionSingle(playlistIndex, itemIndex, state); (void)
		/*
		state: boolean
		example1:
		plman.SetPlaylistSelectionSingle(plman.ActivePlaylist, 0, false);
		deselects first playlist item. obviously only works when it is already selected.

		example2:
		var ap = plman.ActivePlaylist;
		plman.SetPlaylistSelectionSingle(ap, plman.PlaylistItemCount(ap) - 1, true);
		selects last item in playlist.
		note this does not affect other selected items.
		*/

		plman.ShowAutoPlaylistUI(playlistIndex); (boolean)
		/*
		shows popup window letting you edit certain Autoplaylist properties.
		example: fb.ShowAutoPlaylistUI(plman.ActivePlaylist);
		before using, check if your playlist is an Autoplaylist by using plman.IsAutoPlaylist(...);
		*/

		plman.SortByFormat(playlistIndex, pattern[, selected_items_only]); (boolean)
		/*
		playlistIndex: index of playlist to alter.
		pattern: title formatting pattern to sort by. Set to "" to randomise the order of items.
		selected_items_only: boolean, default false.
		returns true on success, false on failure (playlist locked etc).
		*/

		plman.SortByFormatV2(playlistIndex, pattern[, direction]); (boolean)
		// direction: default 1 (ascending), -1 (descending).

		plman.UndoBackup(playlistIndex); (void)
		// call before using other plman methods that add/remove/reorder playlist items so a history will be
		// usable from the Edit menu.

	Queue Methods:

		plman.AddItemToPlaybackQueue(handle); (void)

		plman.AddPlaylistItemToPlaybackQueue(playlistIndex, playlistItemIndex); (void)

		plman.CreatePlaybackQueueItem(); (IFbPlaybackQueueItem)

			interface IFbPlaybackQueueItem {
				Properties:
					Handle; (IFbMetadbHandle) (read, write)
					PlaylistIndex; (uint) (read, write)
					PlaylistItemIndex; (uint) (read, write)

				Methods:
					Equals(item); (boolean)
					// item: an instance of IFbPlaybackQueueItem.

					Dispose(); (void)
			}

		plman.FindPlaybackQueueItemIndex(handle, playlistIndex, playlistItemIndex); (int)
		// returns -1 on failure

		plman.FlushPlaybackQueue(); (void)

		plman.GetPlaybackQueueContents(); (VBArray)
		// returns a VBArray so you need to use .toArray() on the result.

		plman.GetPlaybackQueueCount(); (uint)

		plman.IsPlaybackQueueActive(); (boolean)

		plman.RemoveItemFromPlaybackQueue(index); (void)

		plman.RemoveItemsFromPlaybackQueue(affectedItems); (void)
		// affectedItems: array like [1, 3, 5]
}

interface IJSUtils {
	Methods:
		utils.CheckComponent(name[, is_dll]); (boolean)
		// is_dll: boolean, default false. if true, method checks filename as well as the internal name.
		// example: fb.trace(utils.CheckComponent("foo_jscript_panel", true));

		utils.CheckFont(name); (boolean)
		// name: can be either in English or the localised name in your OS.

		utils.FileTest(path, mode); (VARIANT)
		/*
		mode:
		"chardet": guess the charset of a file and return the codepage. it may not be accurate and
				   returns 0 if an error occurred.
		"e": if path exists, return true
		"s": retrieve file size, in bytes
		"d": if path is a directory, return true
		"split": returns a VBArray so you need to use .toArray() on the result.
		example: var arr = utils.FileTest("D:\\Somdir\\Somefile.txt", "split").toArray();
		arr[0] <= "D:\\Somedir\\" (always includes backslash at the end)
		arr[1] <= "Somefile"
		arr[2] <= ".txt"
		*/

		utils.FormatDuration(seconds) (string)
		// example:
		// fb.trace(utils.FormatDuration(plman.GetPlaylistItems(plman.ActivePlaylist).CalcTotalDuration()));
		// 1wk 1d 17:25:30

		utils.FormatFileSize(bytes) (string)
		// example:
		// fb.trace(utils.FormatFileSize(plman.GetPlaylistItems(plman.ActivePlaylist).CalcTotalSize()));
		// 7.9 GB 

		utils.GetAlbumArtAsync(window_id, handle[, art_id][, need_stub][, only_embed][, no_load]); (uint)
		/*
		window_id: window.ID
		art_id: default 0. see flags.txt > AlbumArtId
		need_stub: boolean, default true
		only_embed: boolean, default false
		no_load: boolean, default false. if true, "image" parameter will be null in on_get_album_art_done callback.
		see samples\basic\GetAlbumArtAsync.txt
		*/

		utils.GetAlbumArtEmbedded(rawpath[, art_id]); (IGdiBitmap)
		// art_id: default 0. see flags.txt > AlbumArtId
		// example: var img = utils.GetAlbumArtEmbedded(fb.GetNowPlaying().RawPath, 0);

		utils.GetAlbumArtV2(handle[, art_id][, need_stub]); (IGdiBitmap)
		/*
		art_id: default 0. see flags.txt > AlbumArtId
		need stub: boolean, default true.
		see samples\basic\GetAlbumArtV2.txt
		*/

		utils.GetSysColor(index); (uint)
		/*
		index: http://msdn.microsoft.com/en-us/library/ms724371%28VS.85%29.aspx
		example: var splitter_colour = utils.GetSysColor(15);
		returns 0 if failed.
		*/

		utils.GetSystemMetrics(index); (int)
		// index: http://msdn.microsoft.com/en-us/library/ms724385%28VS.85%29.aspx
		// returns 0 if failed.

		utils.Glob(pattern[, exc_mask][, inc_mask]); (VBArray)
		/*exc_mask: default FILE_ATTRIBUTE_DIRECTORY see flags.txt > Used in utils.Glob()
		inc_mask: default 0xffffffff
		returns a VBArray so you need to use .toArray() on the result.
		example: var arr = utils.Glob("C:\\*.*").toArray();
		*/

		utils.IsKeyPressed(vkey); (boolean)
		// vkey: http://msdn.microsoft.com/en-us/library/ms927178.aspx
		// some are defined in flags.txt > Used with utils.IsKeyPressed()

		utils.MapString(text, lcid, flags); (string)

		utils.PathWildcardMatch(pattern, str); (boolean)
		// using Microsoft MS-DOS wildcards match type. eg "*.txt", "abc?.tx?"

		utils.ReadTextFile(filename[,codepage]); (string)
		/*codepage: default 0 see codepages.txt
		if codepage is 0, text file can be either UTF-16 with BOM or UTF-8 with BOM and ANSI.
		example: var text = utils.ReadTextFile("E:\\some text file.txt");
		*/

		utils.ReadINI(filename, section, key[, defaultval]); (string)
		/*
		an INI file should like this:

		[section]
		key=val

		this only returns up to 255 characters per value.
		example: var username = utils.ReadINI("e:\\my_file.ini", "Last.fm", "username");
		*/

		utils.WriteINI(filename, section, key, val); (boolean)
		// example: utils.WriteINI("e:\\my_file.ini", "Last.fm", "username", "Bob");
}

interface IFbWindow {
	Properties:
		window.DlgCode(); (int) (read, write)
		// see flags.txt > With window.DlgCode
		// example: window.DlgCode(DLGC_WANTALLKEYS);

		window.ID; (read) (int)
		// required in utils.GetAlbumArtAsync, utils.LoadImageAsync

		window.InstanceType; (int)
		// 0 CUI, 1 DUI.
		// you need this to determine which GetFontXXX and GetColorXXX methods to use, assuming you want
		// to support both interfaces.

		window.IsTransparent; (boolean) (read)
		// depends on setting inside JScript Panel Configuration window. you generally use it to determine 
		// whether or not to draw a background.

		window.IsVisible; (boolean) (read)

		window.Height; (int) (read)

		window.MaxHeight; (int) (read, write)
		window.MaxWidth; (int) (read, write)
		window.MinHeight; (int) (read, write)
		window.MinWidth; (int) (read, write)
		// the previous 4 methods can be used to lock the panel size. do not use if panels are contained within
		// Panel Stack Splitter (Columns UI component).

		window.Width; (int) (read)

	Methods:
		window.ClearTimeout(timerID); (void)
		window.ClearInterval(timerID); (void)
		window.SetInterval(func, delay); (uint)
		window.SetTimeout(func, delay); (uint)
		// for the previous 4 methods, see samples\basic\timers.txt

		window.CreatePopupMenu(); (IMenuObj)

			interface IMenuObj {
				// see samples\basic\MainMenuManager All-In-One, samples\basic\Menu Sample.txt

				Properties:
					ID; (uint) (read)

				Methods:
					AppendMenuItem(flags, item_id, text); (void)
					// flags: see flags.txt > Used in AppendMenuItem()
					// item_id: integer greater than 0. each menu item needs a unique id.

					AppendMenuSeparator(); (void)

					AppendTo(parentMenu, flags, text); (void)

					CheckMenuItem(id_or_pos, check[, bypos]); (void)
					// check: boolean.
					// bypos: boolean, default false.

					CheckMenuRadioItem(first, last, check[, bypos]); (void)
					// check: boolean.
					// bypos: boolean, default false.

					Dispose(); (void)

					EnableMenuItem(id_or_pos, enable[, bypos]); (void)
					// enable: boolean.
					// bypos: boolean, default false

					TrackPopupMenu(x, y[, flags]); (int)
					// flags: default 0, see flags.txt > Used in TrackPopupMenu()
			}

		window.CreateThemeManager(class_list); (IThemeManager)
		// class_list: http://msdn.microsoft.com/en-us/library/bb773210%28VS.85%29.aspx
		// see samples\basic\SimpleThemedButton.txt, samples\basic\Themed Seek Bar.txt

			interface IThemeManager {
				// see samples\basic\SimpleThemedButton, samples\basic\Themed Seekbar.txt

				Methods:
					DrawThemeBackground(IGdiGraphics, x, y, w, h[, clip_x][, clip_y][, clip_w][, clip_h]); (void)
					// clip_x, clip_y, clip_w, clip_h: defaults to 0 if omitted

					IsThemePartDefined(partid); (boolean)
					SetPartAndStateID(partid, stateid); (void)
					// partid, stateid: http://msdn.microsoft.com/en-us/library/bb773210%28VS.85%29.aspx
			}

		window.CreateTooltip([font_name][, font_size_px][, font_style]); (IFbTooltip)
		/*(
		font_name: default "Segoe UI"
		font_size_px: default 12
		font_style: default 0 see flags.txt > FontStyle
		*/

			interface IFbTooltip {
				// this will be used in the examples below.
				// var tooltip = window.CreateTooltip();

				Properties:
					Text; (string) (read, write)
					// example: tooltip.Text = "Whoop";

					TrackActivate; (boolean) (write)

				Methods:
					Activate(); (void)
					/*
					only do this when text has changed otherwise it will flicker
					example:
					var text = "...";
					if (tooltip.Text != text) {
						tooltip.Text = text;
						tooltip.Activate();
					}
					*/

					Deactivate(); (void)

					Dispose(); (void)

					GetDelayTime(type); (int)
					SetDelayTime(type, time); (void)
					// type: see flags.txt > Used in IFbTooltip.GetDelayTime() and IFbTooltip.SetDelayTime()

					SetMaxWidth(width); (void)
					/*
					use if you want multi-line tooltips
					example:
					tooltip.SetMaxWidth(800);
					tooltip.Text = "Line1\nLine2";
					use \n as a new line separator
					*/

					TrackPosition(x, y); (void)
					// check x, y positions have changed from last time otherwise it will flicker
			}

		window.GetBackgroundImage(); (IGdiBitmap)
		// retrieve pseudo-transparent background image.

		window.GetColorCUI(type[, client_guid]); (uint)
		window.GetColorDUI(type); (uint)

		window.GetFontCUI(type[, client_guid]); (IGdiFont)
		window.GetFontDUI(type); (IGdiFont)
		/*
		type: see flags.txt > Used in window.GetFontXXX()
		client_guid: default "" see flags.txt > Used in GetFontCUI() as client_guid
		note this returns null if the component was unable to determine your font.
		to avoid errors when trying to use the font or access its properties, you
		should use code something like this...

		var font = window.GetFontDUI(0);
		if (!font) {
			fb.trace("Unable to determine your default font. Using Segoe UI instead.");
			font = gdi.Font("Segoe UI", 12);
		}
		*/

		window.NotifyOthers(name, info); (void)
		/*
		name: string
		info: all variable/array/object types should be supported
		listen for notifications in other panels using on_notify_data(name, info) {}
		*/

		window.Reload(); (void)
		// reload panel

		window.Repaint([force]); (void)
		// force: boolean, default false

		window.RepaintRect(x, y, w, h[, force]); (void)
		/*
		x, y, w, h must be an integer, 0 or above. 
		force: boolean, default false

		if you cannot be sure of calculated x, y values, do
		something like this...
		window.RepaintRect(Math.max(0, x), Math.max(0, y), w, h);

		use this instead of window.Repaint on frequently updated areas
		such as time, bitrate, seekbar, etc. this should reduce CPU usage.
		you can use Windows Task Manager to double check.
		*/

		window.SetCursor(id); (void)
		/*
		this would usually be used inside the on_mouse_move callback
		
		id: see flags.txt > Used in window.SetCursor()
		use -1 if you want to hide the cursor.
		*/

		window.GetProperty(name[, defaultval]); (VARIANT)
		// get value of name from properties.
		// if no value is present, store the defaultval for the name and returns

		window.SetProperty(name, val); (void)
		/*name: string
		val: string, number, boolean
		set property value, if val is invalid/null, it is removed
		property values will be saved per panel instance and are remembered between foobar2000 restarts.
		*/

		window.ShowConfigure(); (void)
		// show configuration window of current panel

		window.ShowProperties(); (void)
		// show properties window of current panel
}

interface IGdiFont {
	// this will be used in the examples below.
	// var my_font = window.GetFontDUI(0); // see flags.txt > FontTypeDUI

	Properties:
		Height (int) (read)
		// example: fb.trace(my_font.Height);
		// 15

		Name (string) (read)
		// example: fb.trace(my_font.Name);
		// Segoe UI

		Size (float) (read)
		// example: fb.trace(my_font.Size);
		// 12

		Style (int) (read)
		// example: fb.trace(my_font.Style);
		// 0 see flags.txt > FontStyle

	Methods:
		Dispose(); (void)
		// example: my_font.Dispose();
}

interface IGdiBitmap {
	/*
	example1: samples\basic\Apply Mask.txt
	example2: samples\basic\BoxBlur.txt
	example3: samples\basic\Glow Text Sample.txt
	example4: samples\basic\StackBlur.txt
	*/

	Properties:
		Height (int) (read)
		Width (int) (read)

	Methods:
		ApplyAlpha(alpha); (IGdiBitmap)
		// alpha: 0-255

		ApplyMask(img); (boolean)
		// Changes will be saved in the current bitmap

		BoxBlur(radius[, iteration]); (void)
		// radius: valid values 1-20
		// iteration: default 1. valid values 1-20

		Clone(x, y, w, h); (IGdiBitmap)

		CreateRawBitmap(); (IGdiRawBitmap)
		// Create a DDB bitmap from IGdiBitmap, which is used in GdiDrawBitmap()

			interface IGdiRawBitmap {
				Properties:
					Width; (int) (read)
					Height; (int) (read)

				Methods:
					Dispose(); (void)
			}

		Dispose(); (void)

		GetColorScheme(max_count); (VBArray)
		// returns a VBArray so you need to use .toArray() on the result.

		GetGraphics();
		// don't forget to use ReleaseGraphics() after operations on IGdiGraphics interface is done.

		ReleaseGraphics(IGdiGraphics); (IGdiGraphics)

		Resize(w, h[, mode]); (IGdiBitmap)
		// mode: default 0. see flags.txt > InterpolationMode

		RotateFlip(mode); (void)
		// mode: see flags.txt > RotateFlipType

		SaveAs(path[, format]); (boolean)
		/*
		path: full path including file extension. the parent folder must already exist.
		format:
		"image/png" (default if omitted)
		"image/bmp"
		"image/jpeg"
		"image/gif"
		"image/tiff"

		example:
		var img = utils.GetAlbumArtEmbedded(fb.GetFocusItem().RawPath, 0);
		if (img)
			img.SaveAs("D:\\export.jpg", "image/jpeg");
		*/

		StackBlur(radius); (void)
		// radius: valid values 2-254
}

interface IGdiGraphics {
	/*
	typically used inside on_paint(gr)
	there are many different ways to get colours.
	use window.GetColorDUI/window.GetColourCUI.
	use RGB function from helpers.txt.
	use predefined colour from helpers.txt.
	and more...
	*/

	Methods:
		gr.CalcTextHeight(str, IGdiFont); (uint)
		// this will only calulate the text height of one line.

		gr.CalcTextWidth(str, IGdiFont); (uint)

		gr.DrawEllipse(x, y, w, h, line_width, color); (void)

		gr.DrawImage(IGdiBitmap, dstX, dstY, dstW, dstH, srcX, srcY, srcW, srcH[, angle][, alpha]); (void)
		// angle: default 0
		// alpha: default 255. valid values 0-255.

		gr.DrawLine(x1, y1, x2, y2, line_width, colour); (void)

		gr.DrawPolygon(color, line_width, points); (void)
		// points: a JScript array.

		gr.DrawString(str, IGdiFont, color, x, y, w, h[, flags]); (void)
		// flags: default 0. see flags.txt > StringFormatFlags

		gr.DrawRect(x, y, w, h, line_width, colour); (void)

		gr.DrawRoundRect(x, y, w, h, arc_width, arc_height, line_width, color); (void)

		gr.EstimateLineWrap(str, IGdiFont, max_width); (VBArray)
		/*
		returns a VBArray so you need to use .toArray() on the result.
		index | meaning
		[0] text line 1
		[1] width of text line 1 (in pixel)
		[2] text line 2
		[3] width of text line 2 (in pixel)
		...
		[2n + 2] text line n
		[2n + 3] width of text line n (px)
		*/

		gr.FillEllipse(x, y, w, h, colour); (void)

		gr.FillGradRect(x, y, w, h, angle, colour1, colour2[, focus]); (void)
		/*
		focus: default 1.0. valid values are between 0.0 and 1.0
		specify where the centred colour will be at its highest intensity.

		NOTE: This may appear buggy depending on rectangle size. The easiest fix is
		to adjust the "angle" by a degree or two.
		*/

		gr.FillPolygon(colour, fillmode, points); (void)
		// fillmode: 0 Alternate, 1 Winding.
		// points: a JScript array.

		gr.FillRoundRect(x, y, w, h, arc_width, arc_height, colour); (void)

		gr.FillSolidRect(x, y, w, h, colour); (void)

		gr.GdiDrawBitmap(IGdiRawBitmap, dstX, dstY, dstW, dstH, srcX, srcY, srcW, srcH); (void)
		// always faster than DrawImage, does not support alpha channel.

		gr.GdiDrawText(str, IGdiFont, color, x, y, w, h[, format]); (VBArray)
		/*
		format: default 0. see flags.txt > DT_*

		returns a VBArray so you need to use .toArray() on the result.
		index | meaning
		[0] left   (DT_CALCRECT)
		[1] top    (DT_CALCRECT)
		[2] right  (DT_CALCRECT)
		[3] bottom (DT_CALCRECT)
		[4] characters drawn
		*/

		gr.MeasureString(str, IGdiFont, x, y, w, h[, flags]); (IMeasureStringInfo)
		// flags: default 0. see flags.txt > StringFormatFlags

			interface IMeasureStringInfo {
				Properties:
					chars; (int) (read)
					Height; (float) (read)
					lines; (int) (read)
					x; (float) (read)
					y; (float) (read)
					Width; (float) (read)

					/*
					example:
					// ==PREPROCESSOR==
					// @import "%fb2k_component_path%docs\flags.txt"
					// @import "%fb2k_component_path%docs\helpers.txt"
					// ==/PREPROCESSOR==

					var sf = StringFormat(StringAlignment.Near, StringAlignment.Near);
					var text = utils.ReadTextFile("z:\\info.txt");
					var font = window.GetFontDUI(0);

					function on_paint(gr) {
						gr.DrawString(text, font, RGB(255, 0, 0), 0, 0, window.Width, window.Height, sf);
						var temp = gr.MeasureString(text, font, 0, 0, window.Width, 10000, sf);
						// if we want to calculate height, we must set the height to be far larger than what
						// the text could possibly be.
						
						fb.trace(temp.Height); // 2761.2421875 // far larger than my panel height!
						fb.trace(temp.Chars); // 7967
					}
					*/
			}

		gr.SetInterpolationMode(mode); (void)
		// mode: default 0. see flags.txt > InterpolationMode

		gr.SetSmoothingMode(mode); (void)
		// mode: default 0. see flags.txt > SmoothingMode

		gr.SetTextRenderingHint(mode); (void)
		// mode: default 0. see flags.txt > TextRenderingHint

		gr.GdiAlphaBlend(IGdiRawBitmap, dstX, dstY, dstW, dstH, srcX, srcY, srcW, srcH[, alpha]); (void)
		// alpha: default 255. valid values 0-255.
}

interface IFbMetadbHandle {
	// this will be used in the examples below.
	// var handle = fb.GetFocusItem();

	Properties:
		Path; (string) (read)
		// example: fb.trace(handle.Path);
		// D:\some song.flac

		RawPath; (string) (read)
		// example: fb.trace(handle.RawPath);
		// file://D:\some song.flac

		SubSong; (int) (read)

		FileSize; (double) (read)

		Length; (double) (read)

	Methods:
		Compare(handle); (boolean)
		/*
		compare two IFbMetadbHandle instances, pointer only.
		example: handle.Compare(handle2);
		if you want to compare them physically, use the "RawPath" property.
		*/

		Dispose(); (void)
		// example: handle.Dispose();

		GetFileInfo(); (IFbFileInfo)

			interface IFbFileInfo {
				/*
				this will be used in the examples below.
				var handle = fb.GetFocusItem();
				var f = handle.GetFileInfo();
				*/

				Properties:
					MetaCount; (read)
					// example: fb.trace(f.MetaCount);
					// 11

					InfoCount; (read)
					// example: fb.trace(f.InfoCount);
					// 9

				Methods:
					Dispose();
					// example: f.Dispose();

					InfoFind(name);
					// returns idx

					InfoName(idx);

					InfoValue(idx);

					MetaAdd(name, value);

					MetaFind(name);
					// returns idx

					MetaInsertValue(idx, vidx, value);

					MetaName(idx);
					/*
					example:
					var text = "";
					for (var i = 0; i < f.MetaCount; i++) {
						text += f.MetaName(i).toUpperCase() + " ");
					}
					fb.trace(text); // ALBUM ARTIST DATE ...
					*/

					MetaRemoveField(name);

					MetaSet(name, value);

					MetaValue(idx, vidx);

					MetaValueCount(idx);
			}

		UpdateFileInfoSimple(field1, value1 [, field2, value2 [,...] ] [, multivalue_fields]);
		/*
		if value is a empty string, field will be removed
		multivalue_fields is a semicolon-separated list containing field names which need to be treated
		as multivalue.

		example:
		handle.UpdateFileInfoSimple("ARTIST", "Enigma", "GENRE", "Downtempo;Ambient", "GENRE");

		GENRE will be treated as a multivalue field. So GENRE[0] = "Downtempo", GENRE[1] = "Ambient"
		*/
}

interface IFbMetadbHandleList {
	/*
	this will be used in the examples below.
	var handle_list = plman.GetPlaylistItems(plman.ActivePlaylist);
	if you want an empty handle list, do this:
	var handle_list = plman.GetPlaylistItems(-1);
	*/

	Properties:
		Count; (uint) (read)
		// example: fb.trace(items.Count);
		// 12

		Item(idx); (IFbMetadbHandle) (read, write)
		// example: fb.trace(fb.TitleFormat("%artist%").EvalWithMetadb(items.Item(0)));
		// displays artist of first item in handle list

	Methods:
		Sort(); (void)
		// Sort and remove duplicates

		Add(handle); (uint)
		// example: handle_list.Add(fb.GetNowPlaying());

		AddRange(handle_list); (void)
		// example: handle_list.Add(fb.GetLibraryItems());

		BSearch(handle); (uint)
		// must be sorted, faster than Find()

		CalcTotalDuration(); (double)
		// returns total in seconds.
		// consider using utils.FormatDuration() on the result.

		CalcTotalSize(); (double)
		// return total in bytes.
		// consider using utils.FormatFileSize() on the result.

		Clone(); (IFbMetadbHandleList)
		// example: var handle_list2 = handle_list.Clone();

		Dispose(); (void)
		// example: handle_list.Dispose();

		Find(handle); (uint)
		// if sorted, use BSearch instead

		Insert(index, handle); (uint)
		/*
		example1: handle_list.Insert(0, fb.GetNowPlaying());
		0 inserts at the start of the handle list.
		example2: handle_list.Insert(items.Count, fb.GetNowPlaying());
		this inserts at the end of the handle list.
		*/

		InsertRange(index, handle_list); (uint)

		MakeDifference(handle_list); (void)
		// must be sorted

		MakeIntersection(handle_list); (void)
		// must be sorted

		MakeUnion(handle_list); (void)
		// must be sorted

		OrderByFormat(tfo, direction); (void)
		/*
		tfo: an instance of IFbTitleFormat.
		direction: integer, ascending while > 0.
		example:
		var handle_list = fb.GetLibraryItems();
		var tfo = fb.TitleFormat("%album artist%|%date%|%album%|%discnumber%|%tracknumber%");
		handle_list.OrderByFormat(tfo, 1);
		*/

		OrderByPath(); (void)

		OrderByRelativePath(); (void)

		Remove(handle); (void)

		RemoveAll(); (void)
		/*
		example: 
		handle_list.RemoveAll();
		fb.trace(handle_list.Count);
		0 - another way to get an empty handle list!
		*/

		RemoveById(idx); (void)
		// example: handle_list.RemoveById(0);
		// remove first item in playlist

		RemoveRange(from, num); (void)
		// example: handle_list.RemoveRange(10, 20);
		
		UpdateFileInfoSimple(field1, value1 [, field2, value2 [,...] ] [, multivalue_fields]);
		/*
		if value is a empty string, field will be removed
		multivalue_fields is a semicolon-separated list containing field names which need to be treated
		as multivalue.

		example:
		handle.UpdateFileInfoSimple("ARTIST", "Enigma", "GENRE", "Downtempo;Ambient", "GENRE");

		GENRE will be treated as a multivalue field. So GENRE[0] = "Downtempo", GENRE[1] = "Ambient"
		*/
}

interface IDropTargetAction {
	// see samples\basic\Drag Drop Basic.txt

	Properties:
		Parsable; (boolean) (read, write)

		Playlist; (read, write)
		// default: -1, active playlist

		ToSelect; (boolean) (read, write)

	Methods:
		ToPlaylist(); (void)
}
