/*
 * Class:     de_rwth_0005faachen_techinfo_ltilib_Matrix
 * Method:    _setData
 * Signature: (J[[F)V
 */
JNIEXPORT void JNICALL Java_de_rwth_1aachen_techinfo_ltilib_Matrix__1setData__J_3_3F
(JNIEnv *env, jobject m, jlong nat, jobjectArray data) {

  jniMatrix* mat;

  jclass cls=env->GetObjectClass(m);
  jfieldID fid=env->GetFieldID(cls, "nativeObject", "J");
  jlong id=env->GetLongField(m,fid);

  if (id!=0) {
    mat=jlong2matrix(id);
  } else {
    mat=new jniMatrix();
  }

  jboolean copy=JNI_FALSE;
  int rows=env->GetArrayLength(data);
  if (rows > 0) {
    int cols=0;
    jfloatArray curr=jfloatArray(env->GetObjectArrayElement(data, 0));
    cols=env->GetArrayLength(curr);
    float* elem=env->GetFloatArrayElements(curr, &copy);
    double* elements=new double[rows*cols];
    for (int j=0; j<cols; j++) {
      elements[j]=elem[j];
    }

    env->ReleaseFloatArrayElements(curr, elem, JNI_ABORT);

    for (int i=1; i<rows; i++) {
      curr=jfloatArray(env->GetObjectArrayElement(data, i));
      if (env->GetArrayLength(curr) != cols) {
        //Error
        fprintf(stderr,"Error in jniMatrix: unequal cols");
      }
      elem=env->GetFloatArrayElements(curr, &copy);
      for (int j=0; j<cols; j++) {
        elements[i*cols+j]=elem[j];
      }
      env->ReleaseFloatArrayElements(curr, elem, JNI_ABORT);
    }

    mat->attach(rows, cols, elements);
  }

  env->SetLongField(m, fid, matrix2jlong(mat));
}
static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz,
        jlong ptr, jint id, jobject outEstimatorObj) {
    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
    VelocityTracker::Estimator estimator;
    bool result = state->getEstimator(id, &estimator);

    jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
            gEstimatorClassInfo.xCoeff));
    jfloatArray yCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
            gEstimatorClassInfo.yCoeff));

    env->SetFloatArrayRegion(xCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
            estimator.xCoeff);
    env->SetFloatArrayRegion(yCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
            estimator.yCoeff);
    env->SetIntField(outEstimatorObj, gEstimatorClassInfo.degree, estimator.degree);
    env->SetFloatField(outEstimatorObj, gEstimatorClassInfo.confidence, estimator.confidence);
    return result;
}
static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj,
        float xOffset, float yOffset, PointerCoords* outRawPointerCoords) {
    outRawPointerCoords->clear();
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_X,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.x) - xOffset);
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_Y,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.y) - yOffset);
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.pressure));
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_SIZE,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.size));
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMajor));
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMinor));
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMajor));
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor));
    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));

    uint64_t bits = env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits);
    if (bits) {
        jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj,
                gPointerCoordsClassInfo.mPackedAxisValues));
        if (valuesArray) {
            jfloat* values = static_cast<jfloat*>(
                    env->GetPrimitiveArrayCritical(valuesArray, NULL));

            uint32_t index = 0;
            do {
                uint32_t axis = __builtin_ctzll(bits);
                uint64_t axisBit = 1LL << axis;
                bits &= ~axisBit;
                outRawPointerCoords->setAxisValue(axis, values[index++]);
            } while (bits);

            env->ReleasePrimitiveArrayCritical(valuesArray, values, JNI_ABORT);
            env->DeleteLocalRef(valuesArray);
        }
    }
}
static jfloatArray obtainPackedAxisValuesArray(JNIEnv* env, uint32_t minSize,
        jobject outPointerCoordsObj) {
    jfloatArray outValuesArray = jfloatArray(env->GetObjectField(outPointerCoordsObj,
            gPointerCoordsClassInfo.mPackedAxisValues));
    if (outValuesArray) {
        uint32_t size = env->GetArrayLength(outValuesArray);
        if (minSize <= size) {
            return outValuesArray;
        }
        env->DeleteLocalRef(outValuesArray);
    }
    uint32_t size = 8;
    while (size < minSize) {
        size *= 2;
    }
    outValuesArray = env->NewFloatArray(size);
    env->SetObjectField(outPointerCoordsObj,
            gPointerCoordsClassInfo.mPackedAxisValues, outValuesArray);
    return outValuesArray;
}