package us.shandian.giga.io;

import android.content.ContentResolver;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import android.util.Log;

import org.schabi.newpipe.streams.io.SharpStream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

public class FileStreamSAF extends SharpStream {

    private final FileInputStream in;
    private final FileOutputStream out;
    private final FileChannel channel;
    private final ParcelFileDescriptor file;

    private boolean disposed;

    public FileStreamSAF(@NonNull ContentResolver contentResolver, Uri fileUri) throws IOException {
        // Notes:
        // the file must exists first
        // ¡read-write mode must allow seek!
        // It is not guaranteed to work with files in the cloud (virtual files), tested in local storage devices

        file = contentResolver.openFileDescriptor(fileUri, "rw");

        if (file == null) {
            throw new IOException("Cannot get the ParcelFileDescriptor for " + fileUri.toString());
        }

        in = new FileInputStream(file.getFileDescriptor());
        out = new FileOutputStream(file.getFileDescriptor());
        channel = out.getChannel();// or use in.getChannel()
    }

    @Override
    public int read() throws IOException {
        return in.read();
    }

    @Override
    public int read(byte[] buffer) throws IOException {
        return in.read(buffer);
    }

    @Override
    public int read(byte[] buffer, int offset, int count) throws IOException {
        return in.read(buffer, offset, count);
    }

    @Override
    public long skip(long amount) throws IOException {
        return in.skip(amount);// ¿or use channel.position(channel.position() + amount)?
    }

    @Override
    public long available() {
        try {
            return in.available();
        } catch (IOException e) {
            return 0;// ¡but not -1!
        }
    }

    @Override
    public void rewind() throws IOException {
        seek(0);
    }

    @Override
    public void close() {
        try {
            disposed = true;

            file.close();
            in.close();
            out.close();
            channel.close();
        } catch (IOException e) {
            Log.e("FileStreamSAF", "close() error", e);
        }
    }

    @Override
    public boolean isClosed() {
        return disposed;
    }

    @Override
    public boolean canRewind() {
        return true;
    }

    @Override
    public boolean canRead() {
        return true;
    }

    @Override
    public boolean canWrite() {
        return true;
    }

    public boolean canSetLength() {
        return true;
    }

    public boolean canSeek() {
        return true;
    }

    @Override
    public void write(byte value) throws IOException {
        out.write(value);
    }

    @Override
    public void write(byte[] buffer) throws IOException {
        out.write(buffer);
    }

    @Override
    public void write(byte[] buffer, int offset, int count) throws IOException {
        out.write(buffer, offset, count);
    }

    public void setLength(long length) throws IOException {
        channel.truncate(length);
    }

    public void seek(long offset) throws IOException {
        channel.position(offset);
    }

    @Override
    public long length() throws IOException {
        return channel.size();
    }
}
