public static PortfolioSnapshot create(Portfolio portfolio, Date time) {
    Map<Security, SecurityPosition> positions = new HashMap<Security, SecurityPosition>();

    for (PortfolioTransaction t : portfolio.getTransactions()) {
      if (t.getDate().getTime() <= time.getTime()) {
        switch (t.getType()) {
          case TRANSFER_IN:
          case BUY:
          case DELIVERY_INBOUND:
            {
              SecurityPosition p = positions.get(t.getSecurity());
              if (p == null)
                positions.put(t.getSecurity(), p = new SecurityPosition(t.getSecurity()));
              p.addTransaction(t);
              break;
            }
          case TRANSFER_OUT:
          case SELL:
          case DELIVERY_OUTBOUND:
            {
              SecurityPosition p = positions.get(t.getSecurity());
              if (p == null)
                positions.put(t.getSecurity(), p = new SecurityPosition(t.getSecurity()));
              p.addTransaction(t);
              break;
            }
          default:
            throw new UnsupportedOperationException(
                "Unsupported operation: " + t.getType()); // $NON-NLS-1$
        }
      }
    }

    ArrayList<SecurityPosition> collection = new ArrayList<SecurityPosition>(positions.values());
    for (Iterator<SecurityPosition> iter = collection.iterator(); iter.hasNext(); ) {
      SecurityPosition p = iter.next();

      if (p.getShares() == 0) {
        iter.remove();
      } else {
        SecurityPrice price = p.getSecurity().getSecurityPrice(time);
        p.setPrice(price);
      }
    }

    return new PortfolioSnapshot(portfolio, time, collection);
  }
 @Override
 public Status process(PortfolioTransaction transaction, Portfolio portfolio) {
   // ensure consistency (in case the user deleted the creation of the
   // security via the dialog)
   process(transaction.getSecurity());
   portfolio.addTransaction(transaction);
   return Status.OK_STATUS;
 }
 private static void collectPortfolioTransactions(
     Client client, Date start, Date end, List<Transaction> transactions) {
   for (Portfolio portfolio : client.getPortfolios()) {
     for (PortfolioTransaction t : portfolio.getTransactions()) {
       if (t.getDate().getTime() > start.getTime() && t.getDate().getTime() <= end.getTime()) {
         switch (t.getType()) {
           case TRANSFER_IN:
           case TRANSFER_OUT:
           case DELIVERY_INBOUND:
           case DELIVERY_OUTBOUND:
             transactions.add(t);
             break;
           case BUY:
           case SELL:
             break;
           default:
             throw new UnsupportedOperationException();
         }
       }
     }
   }
 }
  private static void collectDatesAndValues(
      Date start,
      Date end,
      ClientSnapshot snapshotStart,
      ClientSnapshot snapshotEnd,
      List<Transaction> transactions,
      List<Date> dates,
      List<Double> values) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(start);
    dates.add(cal.getTime());
    values.add(-(snapshotStart.getAssets()) / Values.Amount.divider());

    for (Transaction t : transactions) {
      cal.setTime(t.getDate());
      dates.add(cal.getTime());

      if (t instanceof AccountTransaction) {
        AccountTransaction at = (AccountTransaction) t;
        long amount = at.getAmount();
        if (at.getType() == Type.DEPOSIT || at.getType() == Type.TRANSFER_IN) amount = -amount;
        values.add(amount / Values.Amount.divider());
      } else if (t instanceof PortfolioTransaction) {
        PortfolioTransaction pt = (PortfolioTransaction) t;

        long amount = pt.getAmount();
        if (pt.getType() == PortfolioTransaction.Type.DELIVERY_INBOUND
            || pt.getType() == PortfolioTransaction.Type.TRANSFER_IN) amount = -amount;
        values.add(amount / Values.Amount.divider());
      } else {
        throw new UnsupportedOperationException();
      }
    }

    cal.setTime(end);
    dates.add(cal.getTime());
    values.add(snapshotEnd.getAssets() / Values.Amount.divider());
  }
  private void adaptPortfolioTransactions(
      Portfolio portfolio, ReadOnlyPortfolio pseudoPortfolio, Set<Security> usedSecurities) {
    for (PortfolioTransaction t : portfolio.getTransactions()) {
      usedSecurities.add(t.getSecurity());

      switch (t.getType()) {
        case BUY:
          if (accounts.contains(t.getCrossEntry().getCrossOwner(t)))
            pseudoPortfolio.internalAddTransaction(t);
          else
            pseudoPortfolio.internalAddTransaction(
                convertTo(t, PortfolioTransaction.Type.DELIVERY_INBOUND));
          break;
        case TRANSFER_IN:
          if (portfolios.contains(t.getCrossEntry().getCrossOwner(t)))
            pseudoPortfolio.internalAddTransaction(t);
          else
            pseudoPortfolio.internalAddTransaction(
                convertTo(t, PortfolioTransaction.Type.DELIVERY_INBOUND));
          break;
        case SELL:
          if (accounts.contains(t.getCrossEntry().getCrossOwner(t)))
            pseudoPortfolio.internalAddTransaction(t);
          else
            pseudoPortfolio.internalAddTransaction(
                convertTo(t, PortfolioTransaction.Type.DELIVERY_OUTBOUND));
          break;
        case TRANSFER_OUT:
          if (portfolios.contains(t.getCrossEntry().getCrossOwner(t)))
            pseudoPortfolio.internalAddTransaction(t);
          else
            pseudoPortfolio.internalAddTransaction(
                convertTo(t, PortfolioTransaction.Type.DELIVERY_OUTBOUND));
          break;
        case DELIVERY_INBOUND:
        case DELIVERY_OUTBOUND:
          pseudoPortfolio.internalAddTransaction(t);
          break;
        default:
          throw new UnsupportedOperationException();
      }
    }
  }
 private PortfolioTransaction convertTo(PortfolioTransaction t, PortfolioTransaction.Type type) {
   PortfolioTransaction clone = new PortfolioTransaction();
   clone.setType(type);
   clone.setDate(t.getDate());
   clone.setCurrencyCode(t.getCurrencyCode());
   clone.setSecurity(t.getSecurity());
   clone.setAmount(t.getAmount());
   clone.setShares(t.getShares());
   clone.addUnits(t.getUnits());
   return clone;
 }
  @Override
  public Status process(BuySellEntry entry, Account account, Portfolio portfolio) {
    if (convertBuySellToDelivery) {
      PortfolioTransaction t = entry.getPortfolioTransaction();

      PortfolioTransaction delivery = new PortfolioTransaction();
      delivery.setType(
          t.getType() == PortfolioTransaction.Type.BUY
              ? PortfolioTransaction.Type.DELIVERY_INBOUND
              : PortfolioTransaction.Type.DELIVERY_OUTBOUND);

      delivery.setDate(t.getDate());
      delivery.setSecurity(t.getSecurity());
      delivery.setMonetaryAmount(t.getMonetaryAmount());
      delivery.setNote(t.getNote());
      delivery.setShares(t.getShares());
      delivery.addUnits(t.getUnits());

      return process(delivery, portfolio);
    } else {
      entry.setPortfolio(portfolio);
      entry.setAccount(account);
      entry.insert();
      return Status.OK_STATUS;
    }
  }
  private void updateChart(Security security) {
    ISeries series = chart.getSeriesSet().getSeries(Messages.ColumnQuote);
    if (series != null) chart.getSeriesSet().deleteSeries(Messages.ColumnQuote);
    chart.clearMarkerLines();

    if (security == null || security.getPrices().isEmpty()) {
      chart.getTitle().setText(security == null ? "..." : security.getName()); // $NON-NLS-1$
      chart.redraw();
      return;
    }

    chart.getTitle().setText(security.getName());

    List<SecurityPrice> prices = security.getPrices();

    int index;
    Date[] dates;
    double[] values;

    if (chartPeriod == null) {
      index = 0;
      dates = new Date[prices.size()];
      values = new double[prices.size()];
    } else {
      index =
          Math.abs(
              Collections.binarySearch(
                  prices, new SecurityPrice(chartPeriod, 0), new SecurityPrice.ByDate()));

      if (index >= prices.size()) {
        // no data available
        chart.redraw();
        return;
      }

      dates = new Date[prices.size() - index];
      values = new double[prices.size() - index];
    }

    for (int ii = 0; index < prices.size(); index++, ii++) {
      SecurityPrice p = prices.get(index);
      dates[ii] = p.getTime();
      values[ii] = p.getValue() / Values.Quote.divider();
    }

    ILineSeries lineSeries =
        (ILineSeries) chart.getSeriesSet().createSeries(SeriesType.LINE, Messages.ColumnQuote);
    lineSeries.setXDateSeries(dates);
    lineSeries.setLineWidth(2);
    lineSeries.enableArea(true);
    lineSeries.setSymbolType(PlotSymbolType.NONE);
    lineSeries.setYSeries(values);
    lineSeries.setAntialias(SWT.ON);

    chart.getAxisSet().adjustRange();

    for (Portfolio portfolio : getClient().getPortfolios()) {
      for (PortfolioTransaction t : portfolio.getTransactions()) {
        if (t.getSecurity() == security
            && (chartPeriod == null || chartPeriod.before(t.getDate()))) {
          String label = Values.Share.format(t.getShares());
          switch (t.getType()) {
            case BUY:
            case TRANSFER_IN:
            case DELIVERY_INBOUND:
              chart.addMarkerLine(t.getDate(), new RGB(0, 128, 0), label);
              break;
            case SELL:
            case TRANSFER_OUT:
            case DELIVERY_OUTBOUND:
              chart.addMarkerLine(t.getDate(), new RGB(128, 0, 0), "-" + label); // $NON-NLS-1$
              break;
            default:
              throw new UnsupportedOperationException();
          }
        }
      }
    }

    chart.redraw();
  }