/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

#define LOG_TAG "Deflater"

#include "JniConstants.h"
#include "ScopedPrimitiveArray.h"
#include "zip.h"

static void Deflater_setDictionaryImpl(JNIEnv* env, jobject, jbyteArray dict, int off, int len, jlong handle) {
    toNativeZipStream(handle)->setDictionary(env, dict, off, len, false);
}

static jlong Deflater_getTotalInImpl(JNIEnv*, jobject, jlong handle) {
    return toNativeZipStream(handle)->stream.total_in;
}

static jlong Deflater_getTotalOutImpl(JNIEnv*, jobject, jlong handle) {
    return toNativeZipStream(handle)->stream.total_out;
}

static jint Deflater_getAdlerImpl(JNIEnv*, jobject, jlong handle) {
    return toNativeZipStream(handle)->stream.adler;
}

static jlong Deflater_createStream(JNIEnv * env, jobject, jint level, jint strategy, jboolean noHeader) {
    UniquePtr<NativeZipStream> jstream(new NativeZipStream);
    if (jstream.get() == NULL) {
        jniThrowOutOfMemoryError(env, NULL);
        return -1;
    }

    /*
     * See zlib.h for documentation of the deflateInit2 windowBits and memLevel parameters.
     *
     * zconf.h says the "requirements for deflate are (in bytes):
     *         (1 << (windowBits+2)) +  (1 << (memLevel+9))
     * that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
     * plus a few kilobytes for small objects."
     */
    int windowBits = noHeader ? -DEF_WBITS : DEF_WBITS;
    int memLevel = DEF_MEM_LEVEL;
    int err = deflateInit2(&jstream->stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
    if (err != Z_OK) {
        throwExceptionForZlibError(env, "java/lang/IllegalArgumentException", err);
        return -1;
    }
    return reinterpret_cast<uintptr_t>(jstream.release());
}

static void Deflater_setInputImpl(JNIEnv* env, jobject, jbyteArray buf, jint off, jint len, jlong handle) {
    toNativeZipStream(handle)->setInput(env, buf, off, len);
}

static jint Deflater_deflateImpl(JNIEnv* env, jobject recv, jbyteArray buf, int off, int len, jlong handle, int flushStyle) {
    NativeZipStream* stream = toNativeZipStream(handle);
    ScopedByteArrayRW out(env, buf);
    if (out.get() == NULL) {
        return -1;
    }
    stream->stream.next_out = reinterpret_cast<Bytef*>(out.get() + off);
    stream->stream.avail_out = len;

    Bytef* initialNextIn = stream->stream.next_in;
    Bytef* initialNextOut = stream->stream.next_out;

    int err = deflate(&stream->stream, flushStyle);
    switch (err) {
    case Z_OK:
        break;
    case Z_STREAM_END:
        static jfieldID finished = env->GetFieldID(JniConstants::deflaterClass, "finished", "Z");
        env->SetBooleanField(recv, finished, JNI_TRUE);
        break;
    case Z_BUF_ERROR:
        // zlib reports this "if no progress is possible (for example avail_in or avail_out was
        // zero) ... Z_BUF_ERROR is not fatal, and deflate() can be called again with more
        // input and more output space to continue compressing".
        break;
    default:
        throwExceptionForZlibError(env, "java/util/zip/DataFormatException", err);
        return -1;
    }

    jint bytesRead = stream->stream.next_in - initialNextIn;
    jint bytesWritten = stream->stream.next_out - initialNextOut;

    static jfieldID inReadField = env->GetFieldID(JniConstants::deflaterClass, "inRead", "I");
    jint inReadValue = env->GetIntField(recv, inReadField);
    inReadValue += bytesRead;
    env->SetIntField(recv, inReadField, inReadValue);
    return bytesWritten;
}

static void Deflater_endImpl(JNIEnv*, jobject, jlong handle) {
    NativeZipStream* stream = toNativeZipStream(handle);
    deflateEnd(&stream->stream);
    delete stream;
}

static void Deflater_resetImpl(JNIEnv* env, jobject, jlong handle) {
    NativeZipStream* stream = toNativeZipStream(handle);
    int err = deflateReset(&stream->stream);
    if (err != Z_OK) {
        throwExceptionForZlibError(env, "java/lang/IllegalArgumentException", err);
    }
}

static void Deflater_setLevelsImpl(JNIEnv* env, jobject, int level, int strategy, jlong handle) {
    NativeZipStream* stream = toNativeZipStream(handle);
    // The deflateParams documentation says that avail_out must never be 0 because it may be
    // necessary to flush, but the Java API ensures that we only get here if there's nothing
    // to flush. To be on the safe side, make sure that we're not pointing to a no longer valid
    // buffer.
    stream->stream.next_out = reinterpret_cast<Bytef*>(NULL);
    stream->stream.avail_out = 0;
    int err = deflateParams(&stream->stream, level, strategy);
    if (err != Z_OK) {
        throwExceptionForZlibError(env, "java/lang/IllegalStateException", err);
    }
}

static JNINativeMethod gMethods[] = {
    NATIVE_METHOD(Deflater, createStream, "(IIZ)J"),
    NATIVE_METHOD(Deflater, deflateImpl, "([BIIJI)I"),
    NATIVE_METHOD(Deflater, endImpl, "(J)V"),
    NATIVE_METHOD(Deflater, getAdlerImpl, "(J)I"),
    NATIVE_METHOD(Deflater, getTotalInImpl, "(J)J"),
    NATIVE_METHOD(Deflater, getTotalOutImpl, "(J)J"),
    NATIVE_METHOD(Deflater, resetImpl, "(J)V"),
    NATIVE_METHOD(Deflater, setDictionaryImpl, "([BIIJ)V"),
    NATIVE_METHOD(Deflater, setInputImpl, "([BIIJ)V"),
    NATIVE_METHOD(Deflater, setLevelsImpl, "(IIJ)V"),
};
int register_java_util_zip_Deflater(JNIEnv* env) {
    return jniRegisterNativeMethods(env, "java/util/zip/Deflater", gMethods, NELEM(gMethods));
}
