package name.abuchen.portfolio.ui.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import name.abuchen.portfolio.model.Account;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.Portfolio;
import name.abuchen.portfolio.snapshot.filter.ClientFilter;
import name.abuchen.portfolio.snapshot.filter.PortfolioClientFilter;
import name.abuchen.portfolio.ui.Images;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.dialogs.ListSelectionDialog;
public final class ClientFilterMenu implements IMenuListener
{
public static class Item
{
String label;
String uuids;
ClientFilter filter;
public Item(String label, String uuids, ClientFilter filter)
{
this.label = label;
this.uuids = uuids;
this.filter = filter;
}
public String getLabel()
{
return label;
}
public String getUUIDs()
{
return uuids;
}
public ClientFilter getFilter()
{
return filter;
}
}
private static final int MAXIMUM_NO_CUSTOM_ITEMS = 10;
private final Client client;
private final IPreferenceStore preferences;
private final List<Consumer<ClientFilter>> listeners = new ArrayList<>();
private List<Item> defaultItems = new ArrayList<>();
private LinkedList<Item> customItems = new LinkedList<>();
private Item selectedItem;
public ClientFilterMenu(Client client, IPreferenceStore preferences)
{
this.client = client;
this.preferences = preferences;
selectedItem = new Item(Messages.PerformanceChartLabelEntirePortfolio, null, c -> c);
defaultItems.add(selectedItem);
client.getPortfolios().forEach(portfolio -> {
defaultItems.add(new Item(portfolio.getName(), null, new PortfolioClientFilter(portfolio)));
defaultItems.add(new Item(portfolio.getName() + " + " + portfolio.getReferenceAccount().getName(), //$NON-NLS-1$
null, new PortfolioClientFilter(portfolio, portfolio.getReferenceAccount())));
});
loadCustomItems();
}
public ClientFilterMenu(Client client, IPreferenceStore preferences, Consumer<ClientFilter> listener)
{
this(client, preferences);
this.listeners.add(listener);
}
private void loadCustomItems()
{
String code = preferences.getString(ClientFilterDropDown.class.getSimpleName());
if (code == null || code.isEmpty())
return;
Map<String, Object> uuid2object = new HashMap<>();
client.getPortfolios().forEach(p -> uuid2object.put(p.getUUID(), p));
client.getAccounts().forEach(a -> uuid2object.put(a.getUUID(), a));
String[] items = code.split(";"); //$NON-NLS-1$
for (String item : items)
{
String[] uuids = item.split(","); //$NON-NLS-1$
Object[] objects = Arrays.stream(uuids).map(uuid2object::get).filter(o -> o != null).toArray();
if (objects.length > 0)
{
Item newItem = buildItem(objects);
customItems.add(newItem);
}
}
}
@Override
public void menuAboutToShow(IMenuManager manager)
{
defaultItems.forEach(item -> {
Action action = new SimpleAction(item.label, a -> {
selectedItem = item;
listeners.forEach(l -> l.accept(item.filter));
});
action.setChecked(item.equals(selectedItem));
manager.add(action);
});
manager.add(new Separator());
customItems.forEach(item -> {
Action action = new SimpleAction(item.label, a -> {
selectedItem = item;
customItems.remove(item);
customItems.addFirst(item);
listeners.forEach(l -> l.accept(item.filter));
});
action.setChecked(item.equals(selectedItem));
manager.add(action);
});
manager.add(new Separator());
manager.add(new SimpleAction(Messages.LabelClientFilterNew, a -> createCustomFilter()));
manager.add(new SimpleAction(Messages.LabelClientClearCustomItems, a -> {
if (customItems.contains(selectedItem))
{
selectedItem = defaultItems.get(0);
listeners.forEach(l -> l.accept(selectedItem.filter));
}
customItems.clear();
preferences.setToDefault(ClientFilterDropDown.class.getSimpleName());
}));
}
private void createCustomFilter()
{
LabelProvider labelProvider = new LabelProvider()
{
@Override
public Image getImage(Object element)
{
return element instanceof Account ? Images.ACCOUNT.image() : Images.PORTFOLIO.image();
}
};
ListSelectionDialog dialog = new ListSelectionDialog(Display.getDefault().getActiveShell(), labelProvider);
dialog.setTitle(Messages.LabelClientFilterDialogTitle);
dialog.setMessage(Messages.LabelClientFilterDialogMessage);
List<Object> elements = new ArrayList<>();
elements.addAll(client.getPortfolios());
elements.addAll(client.getAccounts());
dialog.setElements(elements);
if (dialog.open() == ListSelectionDialog.OK)
{
Object[] selected = dialog.getResult();
if (selected.length > 0)
{
Item newItem = buildItem(selected);
selectedItem = newItem;
customItems.addFirst(newItem);
if (customItems.size() > MAXIMUM_NO_CUSTOM_ITEMS)
customItems.removeLast();
preferences.putValue(ClientFilterDropDown.class.getSimpleName(), String.join(";", //$NON-NLS-1$
customItems.stream().map(i -> i.uuids).collect(Collectors.toList())));
listeners.forEach(l -> l.accept(newItem.filter));
}
}
}
private Item buildItem(Object[] selected)
{
List<Portfolio> portfolios = Arrays.stream(selected).filter(o -> o instanceof Portfolio).map(o -> (Portfolio) o)
.collect(Collectors.toList());
List<Account> accounts = Arrays.stream(selected).filter(o -> o instanceof Account).map(o -> (Account) o)
.collect(Collectors.toList());
String label = String.join(", ", //$NON-NLS-1$
Arrays.stream(selected).map(String::valueOf).collect(Collectors.toList()));
String uuids = String.join(",", //$NON-NLS-1$
Arrays.stream(selected).map(
o -> o instanceof Account ? ((Account) o).getUUID() : ((Portfolio) o).getUUID())
.collect(Collectors.toList()));
return new Item(label, uuids, new PortfolioClientFilter(portfolios, accounts));
}
public boolean hasActiveFilter()
{
return defaultItems.indexOf(selectedItem) != 0;
}
public ClientFilter getSelectedFilter()
{
return selectedItem.filter;
}
public void addListener(Consumer<ClientFilter> listener)
{
listeners.add(listener);
}
public List<Item> getCustomItems()
{
return Collections.unmodifiableList(customItems);
}
}