content: /*
   * Copyright (C) 2011 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  package android.filterfw;
  
  import android.annotation.UnsupportedAppUsage;
  import android.content.Context;
  import android.filterfw.core.AsyncRunner;
  import android.filterfw.core.FilterGraph;
  import android.filterfw.core.FilterContext;
  import android.filterfw.core.FrameManager;
  import android.filterfw.core.GraphRunner;
  import android.filterfw.core.RoundRobinScheduler;
  import android.filterfw.core.SyncRunner;
  import android.filterfw.io.GraphIOException;
  import android.filterfw.io.GraphReader;
  import android.filterfw.io.TextGraphReader;
  
  import java.util.ArrayList;
  
  /**
   * A GraphEnvironment provides a simple front-end to filter graph setup and execution using the
   * mobile filter framework. Typically, you use a GraphEnvironment in the following fashion:
   *   1. Instantiate a new GraphEnvironment instance.
   *   2. Perform any configuration, such as adding graph references and setting a GL environment.
   *   3. Load a graph file using loadGraph() or add a graph using addGraph().
   *   4. Obtain a GraphRunner instance using getRunner().
   *   5. Execute the obtained runner.
   * Note that it is possible to add multiple graphs and runners to a single GraphEnvironment.
   *
   * @hide
   */
  public class GraphEnvironment extends MffEnvironment {
  
      public static final int MODE_ASYNCHRONOUS = 1;
      public static final int MODE_SYNCHRONOUS  = 2;
  
      private GraphReader mGraphReader;
      private ArrayList<GraphHandle> mGraphs = new ArrayList<GraphHandle>();
  
      private class GraphHandle {
          private FilterGraph mGraph;
          private AsyncRunner mAsyncRunner;
          private SyncRunner mSyncRunner;
  
          public GraphHandle(FilterGraph graph) {
              mGraph = graph;
          }
  
          public FilterGraph getGraph() {
              return mGraph;
          }
  
          public AsyncRunner getAsyncRunner(FilterContext environment) {
              if (mAsyncRunner == null) {
                  mAsyncRunner = new AsyncRunner(environment, RoundRobinScheduler.class);
                  mAsyncRunner.setGraph(mGraph);
              }
              return mAsyncRunner;
          }
  
          public GraphRunner getSyncRunner(FilterContext environment) {
              if (mSyncRunner == null) {
                  mSyncRunner = new SyncRunner(environment, mGraph, RoundRobinScheduler.class);
              }
              return mSyncRunner;
          }
      }
  
      /**
       * Create a new GraphEnvironment with default components.
       */
      @UnsupportedAppUsage
      public GraphEnvironment() {
          super(null);
      }
  
      /**
       * Create a new GraphEnvironment with a custom FrameManager and GraphReader. Specifying null
       * for either of these, will auto-create a default instance.
       *
       * @param frameManager The FrameManager to use, or null to auto-create one.
       * @param reader        The GraphReader to use for graph loading, or null to auto-create one.
       *                      Note, that the reader will not be created until it is required. Pass
       *                      null if you will not load any graph files.
       */
      public GraphEnvironment(FrameManager frameManager, GraphReader reader) {
          super(frameManager);
          mGraphReader = reader;
      }
  
      /**
       * Returns the used graph reader. This will create one, if a reader has not been set already.
       */
      public GraphReader getGraphReader() {
          if (mGraphReader == null) {
              mGraphReader = new TextGraphReader();
          }
          return mGraphReader;
      }
  
      /**
       * Add graph references to resolve during graph reading. The references added here are shared
       * among all graphs.
       *
       * @param references An alternating argument list of keys (Strings) and values.
       */
      @UnsupportedAppUsage
      public void addReferences(Object... references) {
          getGraphReader().addReferencesByKeysAndValues(references);
      }
  
      /**
       * Loads a graph file from the specified resource and adds it to this environment.
       *
       * @param context       The context in which to read the resource.
       * @param resourceId    The ID of the graph resource to load.
       * @return              A unique ID for the graph.
       */
      @UnsupportedAppUsage
      public int loadGraph(Context context, int resourceId) {
          // Read the file into a graph
          FilterGraph graph = null;
          try {
              graph = getGraphReader().readGraphResource(context, resourceId);
          } catch (GraphIOException e) {
              throw new RuntimeException("Could not read graph: " + e.getMessage());
          }
  
          // Add graph to our list of graphs
          return addGraph(graph);
      }
  
      /**
       * Add a graph to the environment. Consider using loadGraph() if you are loading a graph from
       * a graph file.
       *
       * @param graph The graph to add to the environment.
       * @return      A unique ID for the added graph.
       */
      public int addGraph(FilterGraph graph) {
          GraphHandle graphHandle = new GraphHandle(graph);
          mGraphs.add(graphHandle);
          return mGraphs.size() - 1;
      }
  
      /**
       * Access a specific graph of this environment given a graph ID (previously returned from
       * loadGraph() or addGraph()). Throws an InvalidArgumentException if no graph with the
       * specified ID could be found.
       *
       * @param graphId   The ID of the graph to get.
       * @return          The graph with the specified ID.
       */
      public FilterGraph getGraph(int graphId) {
          if (graphId < 0 || graphId >= mGraphs.size()) {
              throw new IllegalArgumentException(
                  "Invalid graph ID " + graphId + " specified in runGraph()!");
          }
          return mGraphs.get(graphId).getGraph();
      }
  
      /**
       * Get a GraphRunner instance for the graph with the specified ID. The GraphRunner instance can
       * be used to execute the graph. Throws an InvalidArgumentException if no graph with the
       * specified ID could be found.
       *
       * @param graphId       The ID of the graph to get.
       * @param executionMode The mode of graph execution. Currently this can be either
                              MODE_SYNCHRONOUS or MODE_ASYNCHRONOUS.
       * @return              A GraphRunner instance for this graph.
       */
      @UnsupportedAppUsage
      public GraphRunner getRunner(int graphId, int executionMode) {
          switch (executionMode) {
              case MODE_ASYNCHRONOUS:
                  return mGraphs.get(graphId).getAsyncRunner(getContext());
  
              case MODE_SYNCHRONOUS:
                  return mGraphs.get(graphId).getSyncRunner(getContext());
  
              default:
                  throw new RuntimeException(
                      "Invalid execution mode " + executionMode + " specified in getRunner()!");
          }
      }
  
  }
  