public long getAssets() {
    long assets = 0;

    for (AccountSnapshot account : accounts) assets += account.getFunds();

    for (PortfolioSnapshot portfolio : portfolios) assets += portfolio.getValue();

    return assets;
  }
  public static ClientSnapshot create(Client client, Date time) {
    ClientSnapshot snapshot = new ClientSnapshot(client, time);

    for (Account account : client.getAccounts())
      snapshot.accounts.add(AccountSnapshot.create(account, time));

    for (Portfolio portfolio : client.getPortfolios())
      snapshot.portfolios.add(PortfolioSnapshot.create(portfolio, time));

    if (snapshot.portfolios.isEmpty())
      snapshot.jointPortfolio = PortfolioSnapshot.create(new Portfolio(), time);
    else if (snapshot.portfolios.size() == 1) snapshot.jointPortfolio = snapshot.portfolios.get(0);
    else snapshot.jointPortfolio = PortfolioSnapshot.merge(snapshot.portfolios);

    return snapshot;
  }
  private static void addPseudoValuationTansactions(
      Portfolio portfolio,
      CurrencyConverter converter,
      ReportingPeriod period,
      Map<Security, SecurityPerformanceRecord> records) {
    PortfolioSnapshot snapshot =
        PortfolioSnapshot.create(portfolio, converter, period.getStartDate());
    for (SecurityPosition position : snapshot.getPositions()) {
      records
          .get(position.getSecurity())
          .addTransaction(new DividendInitialTransaction(position, period.getStartDate()));
    }

    snapshot = PortfolioSnapshot.create(portfolio, converter, period.getEndDate());
    for (SecurityPosition position : snapshot.getPositions()) {
      records
          .get(position.getSecurity())
          .addTransaction(new DividendFinalTransaction(position, period.getEndDate()));
    }
  }
  public static PortfolioSnapshot merge(List<PortfolioSnapshot> snapshots) {
    if (snapshots.isEmpty())
      throw new RuntimeException(
          "Error: PortfolioSnapshots to be merged must not be empty"); //$NON-NLS-1$

    Portfolio portfolio = new Portfolio();
    portfolio.setName(Messages.LabelJointPortfolio);

    Map<Security, SecurityPosition> securities = new HashMap<Security, SecurityPosition>();
    for (PortfolioSnapshot s : snapshots) {
      portfolio.addAllTransaction(s.getSource().getTransactions());
      for (SecurityPosition p : s.getPositions()) {
        SecurityPosition pos = securities.get(p.getSecurity());
        if (pos == null) securities.put(p.getSecurity(), p);
        else securities.put(p.getSecurity(), SecurityPosition.merge(pos, p));
      }
    }

    return new PortfolioSnapshot(
        portfolio,
        snapshots.get(0).getTime(),
        new ArrayList<SecurityPosition>(securities.values()));
  }
  public Map<InvestmentVehicle, AssetPosition> getPositionsByVehicle() {
    Map<InvestmentVehicle, AssetPosition> answer = new HashMap<InvestmentVehicle, AssetPosition>();

    long assets = getAssets();

    for (SecurityPosition p : jointPortfolio.getPositions())
      answer.put(p.getSecurity(), new AssetPosition(p.getSecurity(), p, assets));

    for (AccountSnapshot a : accounts) {
      SecurityPosition sp = new SecurityPosition(null);
      sp.setShares(Values.Share.factor());
      sp.setPrice(new SecurityPrice(getTime(), a.getFunds()));
      answer.put(a.getAccount(), new AssetPosition(a.getAccount(), sp, assets));
    }
    return answer;
  }