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.core;
  
  import android.filterfw.core.Frame;
  import android.filterfw.core.Program;
  
  /**
   * @hide
   */
  public class NativeProgram extends Program {
  
      private int nativeProgramId;
      private boolean mHasInitFunction     = false;
      private boolean mHasTeardownFunction = false;
      private boolean mHasSetValueFunction = false;
      private boolean mHasGetValueFunction = false;
      private boolean mHasResetFunction = false;
      private boolean mTornDown = false;
  
      public NativeProgram(String nativeLibName, String nativeFunctionPrefix) {
          // Allocate the native instance
          allocate();
  
          // Open the native library
          String fullLibName = "lib" + nativeLibName + ".so";
          if (!openNativeLibrary(fullLibName)) {
              throw new RuntimeException("Could not find native library named '" + fullLibName + "' " +
                                         "required for native program!");
          }
  
          // Bind the native functions
          String processFuncName = nativeFunctionPrefix + "_process";
          if (!bindProcessFunction(processFuncName)) {
              throw new RuntimeException("Could not find native program function name " +
                                         processFuncName + " in library " + fullLibName + "! " +
                                         "This function is required!");
          }
  
          String initFuncName = nativeFunctionPrefix + "_init";
          mHasInitFunction = bindInitFunction(initFuncName);
  
          String teardownFuncName = nativeFunctionPrefix + "_teardown";
          mHasTeardownFunction = bindTeardownFunction(teardownFuncName);
  
          String setValueFuncName = nativeFunctionPrefix + "_setvalue";
          mHasSetValueFunction = bindSetValueFunction(setValueFuncName);
  
          String getValueFuncName = nativeFunctionPrefix + "_getvalue";
          mHasGetValueFunction = bindGetValueFunction(getValueFuncName);
  
          String resetFuncName = nativeFunctionPrefix + "_reset";
          mHasResetFunction = bindResetFunction(resetFuncName);
  
          // Initialize the native code
          if (mHasInitFunction && !callNativeInit()) {
              throw new RuntimeException("Could not initialize NativeProgram!");
          }
      }
  
      public void tearDown() {
          if (mTornDown) return;
          if (mHasTeardownFunction && !callNativeTeardown()) {
              throw new RuntimeException("Could not tear down NativeProgram!");
          }
          deallocate();
          mTornDown = true;
      }
  
      @Override
      public void reset() {
          if (mHasResetFunction && !callNativeReset()) {
              throw new RuntimeException("Could not reset NativeProgram!");
          }
      }
  
      @Override
      protected void finalize() throws Throwable {
          tearDown();
      }
  
      @Override
      public void process(Frame[] inputs, Frame output) {
          if (mTornDown) {
              throw new RuntimeException("NativeProgram already torn down!");
          }
          NativeFrame[] nativeInputs = new NativeFrame[inputs.length];
          for (int i = 0; i < inputs.length; ++i) {
              if (inputs[i] == null || inputs[i] instanceof NativeFrame) {
                  nativeInputs[i] = (NativeFrame)inputs[i];
              } else {
                  throw new RuntimeException("NativeProgram got non-native frame as input "+ i +"!");
              }
          }
  
          // Get the native output frame
          NativeFrame nativeOutput = null;
          if (output == null || output instanceof NativeFrame) {
              nativeOutput = (NativeFrame)output;
          } else {
              throw new RuntimeException("NativeProgram got non-native output frame!");
          }
  
          // Process!
          if (!callNativeProcess(nativeInputs, nativeOutput)) {
              throw new RuntimeException("Calling native process() caused error!");
          }
      }
  
      @Override
      public void setHostValue(String variableName, Object value) {
          if (mTornDown) {
              throw new RuntimeException("NativeProgram already torn down!");
          }
          if (!mHasSetValueFunction) {
              throw new RuntimeException("Attempting to set native variable, but native code does not " +
                                         "define native setvalue function!");
          }
          if (!callNativeSetValue(variableName, value.toString())) {
              throw new RuntimeException("Error setting native value for variable '" + variableName + "'!");
          }
      }
  
      @Override
      public Object getHostValue(String variableName) {
          if (mTornDown) {
              throw new RuntimeException("NativeProgram already torn down!");
          }
          if (!mHasGetValueFunction) {
              throw new RuntimeException("Attempting to get native variable, but native code does not " +
                                         "define native getvalue function!");
          }
          return callNativeGetValue(variableName);
      }
  
      static {
          System.loadLibrary("filterfw");
      }
  
      private native boolean allocate();
  
      private native boolean deallocate();
  
      private native boolean nativeInit();
  
      private native boolean openNativeLibrary(String libName);
  
      private native boolean bindInitFunction(String funcName);
      private native boolean bindSetValueFunction(String funcName);
      private native boolean bindGetValueFunction(String funcName);
      private native boolean bindProcessFunction(String funcName);
      private native boolean bindResetFunction(String funcName);
      private native boolean bindTeardownFunction(String funcName);
  
      private native boolean callNativeInit();
      private native boolean callNativeSetValue(String key, String value);
      private native String  callNativeGetValue(String key);
      private native boolean callNativeProcess(NativeFrame[] inputs, NativeFrame output);
      private native boolean callNativeReset();
      private native boolean callNativeTeardown();
  }
  