/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.financial.filtering;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import com.opengamma.core.position.Portfolio;
import com.opengamma.core.position.PortfolioNode;
import com.opengamma.core.position.Position;
import com.opengamma.core.position.impl.SimplePortfolio;
import com.opengamma.core.position.impl.SimplePortfolioNode;
import com.opengamma.id.UniqueId;
import com.opengamma.id.UniqueIdSupplier;

/**
 * A filter of portfolios. One or more filters are applied to a portfolio to remove trades, positions, or
 * nodes from it.
 */
public class PortfolioFilter implements FilteringFunction {

  private static final UniqueIdSupplier s_syntheticIdentifiers = new UniqueIdSupplier("PortfolioFilter");

  private final List<FilteringFunction> _filteringFunctions;

  public PortfolioFilter(final FilteringFunction filteringFunction) {
    _filteringFunctions = Collections.singletonList(filteringFunction);
  }

  public PortfolioFilter(final FilteringFunction... filteringFunctions) {
    _filteringFunctions = Arrays.asList(filteringFunctions);
  }

  public PortfolioFilter(final Collection<FilteringFunction> filteringFunctions) {
    _filteringFunctions = new ArrayList<FilteringFunction>(filteringFunctions);
  }

  private static UniqueId createSyntheticIdentifier() {
    return s_syntheticIdentifiers.get();
  }

  private List<FilteringFunction> getFilteringFunctions() {
    return _filteringFunctions;
  }

  @Override
  public boolean acceptPosition(final Position position) {
    for (FilteringFunction function : getFilteringFunctions()) {
      if (!function.acceptPosition(position)) {
        return false;
      }
    }
    return true;
  }

  @Override
  public boolean acceptPortfolioNode(final PortfolioNode portfolioNode) {
    for (FilteringFunction function : getFilteringFunctions()) {
      if (!function.acceptPortfolioNode(portfolioNode)) {
        return false;
      }
    }
    return true;
  }

  protected SimplePortfolioNode filter(final PortfolioNode inputPortfolioNode) {
    final SimplePortfolioNode newPortfolioNode = new SimplePortfolioNode();
    newPortfolioNode.setUniqueId(createSyntheticIdentifier());
    newPortfolioNode.setName(inputPortfolioNode.getName());
    for (Position position : inputPortfolioNode.getPositions()) {
      if (acceptPosition(position)) {
        newPortfolioNode.addPosition(position);
      }
    }
    for (PortfolioNode portfolioNode : inputPortfolioNode.getChildNodes()) {
      final SimplePortfolioNode filteredPortfolioNode = filter(portfolioNode);
      if (acceptPortfolioNode(filteredPortfolioNode)) {
        filteredPortfolioNode.setParentNodeId(newPortfolioNode.getUniqueId());
        newPortfolioNode.addChildNode(filteredPortfolioNode);
      }
    }
    return newPortfolioNode;
  }

  public Portfolio filter(final Portfolio inputPortfolio) {
    return new SimplePortfolio(UniqueId.of(inputPortfolio.getUniqueId().getScheme(), buildPortfolioName(inputPortfolio.getUniqueId().getValue())), buildPortfolioName(inputPortfolio.getName()),
        filter(inputPortfolio.getRootNode()));
  }

  protected String buildPortfolioName(final String existingName) {
    return existingName + " filtered by " + getName();
  }

  @Override
  public String getName() {
    StringBuilder name = new StringBuilder();
    boolean comma = false;
    for (FilteringFunction function : getFilteringFunctions()) {
      if (comma) {
        name.append(", ");
      } else {
        comma = true;
      }
      name.append(function.getName());
    }
    return name.toString();
  }

}

@@ -196,124 +196,18 @@
 til.
-ArrayList;%0Aimport java.util.Arrays;%0Aimport java.util.Collection;%0Aimport java.util.Collections;%0Aimport java.util.List
+Collection
 ;%0A%0Ai
@@ -857,21 +857,16 @@
 e final 
-List%3C
 Filterin
@@ -874,17 +874,18 @@
 Function
-%3E
+%5B%5D
  _filter
@@ -999,34 +999,33 @@
 s = 
-Collections.singletonList(
+new FilteringFunction%5B%5D %7B
 filt
@@ -1033,25 +1033,26 @@
 ringFunction
-)
+ %7D
 ;%0A  %7D%0A%0A  pub
@@ -1150,22 +1150,126 @@
 s = 
-Arrays.asList(
+new FilteringFunction%5BfilteringFunctions.length%5D;%0A    System.arraycopy(filteringFunctions, 0, _filteringFunctions, 0, 
 filt
@@ -1274,32 +1274,39 @@
 lteringFunctions
+.length
 );%0A  %7D%0A%0A  public
@@ -1410,22 +1410,39 @@
 s = 
-new ArrayList%3C
+filteringFunctions.toArray(new 
 Filt
@@ -1458,10 +1458,9 @@
 tion
-%3E(
+%5B
 filt
@@ -1473,16 +1473,24 @@
 unctions
+.size()%5D
 );%0A  %7D%0A%0A
@@ -1605,13 +1605,8 @@
 ate 
-List%3C
 Filt
@@ -1618,17 +1618,18 @@
 Function
-%3E
+%5B%5D
  getFilt

Use an array instead of a list for faster iteration over the functions.