STDMETHODIMP FbPlaylistManager::SetPlaylistSelectionSingle(UINT playlistIndex, UINT itemIndex, VARIANT_BOOL state)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playlist_set_selection_single(playlistIndex, itemIndex, state == VARIANT_TRUE);
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::EnsurePlaylistItemVisible(UINT playlistIndex, UINT itemIndex)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playlist_ensure_visible(playlistIndex, itemIndex);
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::MovePlaylistSelection(UINT playlistIndex, int delta)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playlist_move_selection(playlistIndex, delta);
	return S_OK;
}
STDMETHODIMP FbPlaylistRecyclerManager::Purge(VARIANT affectedItems)
{
	TRACK_FUNCTION();

	try
	{
		unsigned bitArrayCount;
		bool empty;
		static_api_ptr_t<playlist_manager_v3> plm;
		bit_array_bittable mask;
		bitArrayCount = plm->recycler_get_count();
		if (!helpers::com_array_to_bitarray::convert(affectedItems, bitArrayCount, mask, empty)) return E_INVALIDARG;
		if (empty) return S_OK;

		plm->recycler_purge(mask);
	}
	catch (pfc::exception_invalid_params&)
	{
		return E_INVALIDARG;
	}
	catch (...)
	{
		return E_FAIL;
	}

	return S_OK;
}
STDMETHODIMP FbPlaylistManager::SortByFormatV2(UINT playlistIndex, BSTR pattern, INT direction, VARIANT_BOOL * outSuccess)
{
	TRACK_FUNCTION();

	if (!pattern) return E_INVALIDARG;
	if (!outSuccess) return E_POINTER;

	pfc::stringcvt::string_utf8_from_wide spec(pattern);
	service_ptr_t<titleformat_object> script;
	metadb_handle_list metadb_handles;
	pfc::array_t<size_t> order;

	if (static_api_ptr_t<titleformat_compiler>()->compile(script, spec)) {
		static_api_ptr_t<playlist_manager> api;

		// Get metadb_handle_list for playlist specified.
		api->playlist_get_all_items(playlistIndex, metadb_handles);
		order.set_count(metadb_handles.get_count());
		// Reorder metadb handles
		metadb_handle_list_helper::sort_by_format_get_order(metadb_handles, order.get_ptr(), script, NULL, direction);
		// Reorder the playlist
		*outSuccess = TO_VARIANT_BOOL(api->playlist_reorder_items(playlistIndex, order.get_ptr(), order.get_count()));
	} else {
		*outSuccess = VARIANT_FALSE;
	}

	return S_OK;
}
STDMETHODIMP FbPlaybackQueueItem::put_PlaylistItemIndex(UINT itemIndex)
{
	TRACK_FUNCTION();

	m_playback_queue_item.m_item = itemIndex;
	return S_OK;
}
STDMETHODIMP FbTooltip::SetMaxWidth(int width)
{
    TRACK_FUNCTION();

    SendMessage(m_wndtooltip, TTM_SETMAXTIPWIDTH, 0, width);
    return S_OK;
}
STDMETHODIMP FbPlaylistManager::DuplicatePlaylist(UINT from, BSTR name, UINT * outPlaylistIndex)
{
	TRACK_FUNCTION();

	if (!outPlaylistIndex) return E_POINTER;

	static_api_ptr_t<playlist_manager_v4> manager;
	metadb_handle_list contents;
	pfc::string8_fast name_utf8;

	if (from >= manager->get_playlist_count()) return E_INVALIDARG;

	manager->playlist_get_all_items(from, contents);

	if (!name || !*name)
		// If no name specified, create a playlistIndex which will have the same name
		manager->playlist_get_name(from, name_utf8);
	else
		name_utf8 = pfc::stringcvt::string_utf8_from_wide(name);

	stream_reader_dummy dummy_reader;
	abort_callback_dummy dummy_callback;

	t_size idx = manager->create_playlist_ex(name_utf8.get_ptr(), name_utf8.get_length(), from + 1, contents, &dummy_reader, dummy_callback);
	*outPlaylistIndex = idx;
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::RemoveItemFromPlaybackQueue(UINT index)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->queue_remove_mask(bit_array_one(index));
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::CreateAutoPlaylist(UINT idx, BSTR name, BSTR query, BSTR sort, UINT flags, UINT * p)
{
	TRACK_FUNCTION();

	if (!name || !query) return E_INVALIDARG;
	if (!p) return E_POINTER;

	UINT pos = 0;
	HRESULT hr = CreatePlaylist(idx, name, &pos);

	if (FAILED(hr)) return hr;

	pfc::stringcvt::string_utf8_from_wide wquery(query);
	pfc::stringcvt::string_utf8_from_wide wsort(sort);

	try
	{
		*p = pos;
		static_api_ptr_t<autoplaylist_manager>()->add_client_simple(wquery, wsort, pos, flags);
	}
	catch (...)
	{
		*p = pfc_infinite;
	}

	return S_OK;
}
STDMETHODIMP FbPlaylistManager::MovePlaylist(UINT from, UINT to, VARIANT_BOOL * outSuccess)
{
	TRACK_FUNCTION();

	if (!outSuccess) return E_POINTER;

	static_api_ptr_t<playlist_manager> pm;
	order_helper order(pm->get_playlist_count());

	if ((from >= order.get_count()) || (to >= order.get_count()))
	{
		*outSuccess = VARIANT_FALSE;
		return S_OK;
	}

	int inc = (from < to) ? 1 : -1;

	for (t_size i = from; i != to; i += inc)
	{
		order[i] = order[i + inc];
	}

	order[to] = from;

	*outSuccess = TO_VARIANT_BOOL(pm->reorder(order.get_ptr(), order.get_count()));
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::SetPlaylistFocusItem(UINT playlistIndex, UINT itemIndex)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playlist_set_focus_item(playlistIndex, itemIndex);
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::UndoBackup(UINT playlistIndex)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playlist_undo_backup(playlistIndex);
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::ClearPlaylistSelection(UINT playlistIndex)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playlist_clear_selection(playlistIndex);
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::SetActivePlaylistContext()
{
	TRACK_FUNCTION();

	static_api_ptr_t<ui_edit_context_manager>()->set_context_active_playlist();
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::AddPlaylistItemToPlaybackQueue(UINT playlistIndex, UINT playlistItemIndex)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->queue_add_item_playlist(playlistIndex, playlistItemIndex);
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::AddLocations(UINT playlistIndex, VARIANT locations, VARIANT_BOOL select)
{
	TRACK_FUNCTION();
	
	bool toSelect = (select == VARIANT_TRUE);
	helpers::com_array_reader helper;

	if (!helper.convert(&locations)) return E_INVALIDARG;
	pfc::list_t<pfc::string8> locations2;

	for (long i = 0; i < static_cast<long>(helper.get_count()); ++i)
	{
		_variant_t varUrl;

		helper.get_item(i, varUrl);

		if (FAILED(VariantChangeType(&varUrl, &varUrl, 0, VT_BSTR))) return E_INVALIDARG;

		locations2.add_item(pfc::string8(pfc::stringcvt::string_utf8_from_wide(varUrl.bstrVal)));
	}

	pfc::list_const_array_t<const char*, pfc::list_t<pfc::string8> > locations3(locations2, locations2.get_count());

	static_api_ptr_t<playlist_incoming_item_filter_v2>()->process_locations_async(
		locations3,
		playlist_incoming_item_filter_v2::op_flag_background,
		NULL,
		NULL,
		NULL,
		new service_impl_t<js_process_locations>(playlistIndex, toSelect));

	return S_OK;
}
STDMETHODIMP FbPlaylistManager::GetPlaybackQueueContents(VARIANT * outContents)
{
	TRACK_FUNCTION();

	if (!outContents) return E_POINTER;

	pfc::list_t<t_playback_queue_item> contents;
	helpers::com_array_writer<> arrayWriter;

	static_api_ptr_t<playlist_manager>()->queue_get_contents(contents);
	
	if (!arrayWriter.create(contents.get_count()))
	{
		return E_OUTOFMEMORY;
	}

	for (t_size i = 0; i < contents.get_count(); ++i)
	{
		_variant_t var;
		var.vt = VT_DISPATCH;
		var.pdispVal = new com_object_impl_t<FbPlaybackQueueItem>(contents[i]);

		if (FAILED(arrayWriter.put(i, var)))
		{
			// deep destroy
			arrayWriter.reset();
			return E_OUTOFMEMORY;
		}
	}

	outContents->vt = VT_ARRAY | VT_VARIANT;
	outContents->parray = arrayWriter.get_ptr();
	return S_OK;
}
STDMETHODIMP FbTooltip::Deactivate()
{
    TRACK_FUNCTION();

    SendMessage(m_wndtooltip, TTM_ACTIVATE, FALSE, 0);
    return S_OK;
}
STDMETHODIMP FbPlaylistManager::FlushPlaybackQueue()
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->queue_flush();
	return S_OK;
}
STDMETHODIMP FbPlaylistMangerTemplate::UndoRestore(UINT playlistIndex)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playlist_undo_restore(playlistIndex);
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::RemovePlaylistSelection(UINT playlistIndex, VARIANT_BOOL crop)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playlist_remove_selection(playlistIndex, crop == VARIANT_TRUE);
	return S_OK;
}
STDMETHODIMP FbPlaylistManager::put_PlaybackOrder(UINT p)
{
	TRACK_FUNCTION();

	static_api_ptr_t<playlist_manager>()->playback_order_set_active(p);
	return S_OK;
}
STDMETHODIMP FbPlaylistMangerTemplate::GetPlaylistFocusItemIndex(UINT playlistIndex, INT * outPlaylistItemIndex)
{
    TRACK_FUNCTION();

    if (!outPlaylistItemIndex) return E_POINTER;
    (*outPlaylistItemIndex) = static_api_ptr_t<playlist_manager>()->playlist_get_focus_item(playlistIndex);
    return S_OK;
}
STDMETHODIMP FbPlayingItemLocation::get_PlaylistItemIndex(UINT * outPlaylistItemIndex)
{
    TRACK_FUNCTION();

    if (!outPlaylistItemIndex) return E_POINTER;
    (*outPlaylistItemIndex) = m_itemIndex;
    return S_OK;
}
STDMETHODIMP FbPlayingItemLocation::get_IsValid(VARIANT_BOOL * outIsValid)
{
    TRACK_FUNCTION();

    if (!outIsValid) return E_POINTER;
    (*outIsValid) = TO_VARIANT_BOOL(m_isValid);
    return S_OK;
}
STDMETHODIMP FbPlaylistMangerTemplate::ExecutePlaylistDefaultAction(UINT playlistIndex, UINT playlistItemIndex, VARIANT_BOOL * outSuccess)
{
    TRACK_FUNCTION();

    if (!outSuccess) return E_POINTER;

    (*outSuccess) = TO_VARIANT_BOOL(static_api_ptr_t<playlist_manager>()->playlist_execute_default_action(playlistIndex, playlistItemIndex));
    return S_OK;
}
STDMETHODIMP FbPlaylistMangerTemplate::IsPlaybackQueueActive(VARIANT_BOOL * outIsActive)
{
    TRACK_FUNCTION();

    if (!outIsActive) return E_POINTER;

    (*outIsActive) = static_api_ptr_t<playlist_manager>()->queue_is_active();
    return S_OK;
}
STDMETHODIMP FbPlaylistMangerTemplate::GetPlaybackQueueCount(UINT * outCount)
{
    TRACK_FUNCTION();

    if (!outCount) return E_POINTER;

    (*outCount) = static_api_ptr_t<playlist_manager>()->queue_get_count();
    return S_OK;
}
STDMETHODIMP FbPlaylistMangerTemplate::CreatePlaybackQueueItem(IFbPlaybackQueueItem ** outPlaybackQueueItem)
{
    TRACK_FUNCTION();

    if (!outPlaybackQueueItem) return E_POINTER;

    (*outPlaybackQueueItem) = new com_object_impl_t<FbPlaybackQueueItem>();
    return S_OK;
}