// Path: src/main/java/com/github/xsavikx/androidscreencast/api/recording/atom/AtomType.java
// public enum AtomType {
//     MEDIA_DATA("mdat"),
//     MOVIE("moov"),
//     MOVIE_HEADER("mvhd"),
//     TRACK("trak"),
//     TRACK_HEADER("tkhd"),
//     MEDIA("mdia"),
//     MEDIA_HEADER("mdhd"),
//     HANDLER("hdlr"),
//     MEDIA_HANDLER("mhlr"),
//     VIDEO("vide"),
//     MEDIA_INFORMATION("minf"),
//     VIDEO_MEDIA_INFORMATION("vmhd"),
//     FILE_ALIAS("alis"),
//     DATA_INFORMATION("dinf"),
//     DATA_REFERENCE("dref"),
//     SAMPLE_TABLE("stbl"),
//     SAMPLE_DESCRIPTION("stsd"),
//     RAW("raw "),
//     JAVA("java"),
//     JPEG("jpeg"),
//     PNG("png "),
//     TIME_TO_SAMPLE_MAPPING("stts"),
//     SAMPLE_TO_CHUNK_MAPPING("stsc"),
//     SAMPLE_SIZE("stsz"),
//     STANDARD_CHUNK_OFFSET_TABLE("stco"),
//     WIDE_CHUNK_OFFSET_TABLE("co64"),
//     FILE_TYPE("ftyp"),
//     QUICK_TIME("qt  "),
//     WIDE("wide"),
//     DATA_HANDLER("dhlr");
//     /**
//      * String representation of AtomType that must have exactly 4 characters
//      */
//     private final String stringRepresentation;
// 
//     AtomType(String stringRepresentation) {
//         this.stringRepresentation = stringRepresentation;
//     }
// 
//     public String toStringRepresentation() {
//         return stringRepresentation;
//     }
// }
// 
// Path: src/main/java/com/github/xsavikx/androidscreencast/exception/IORuntimeException.java
// public final class IORuntimeException extends AndroidScreenCastRuntimeException {
// 
//     public IORuntimeException(String message, IOException cause) {
//         super(message, cause);
//     }
// 
//     public IORuntimeException(IOException cause) {
//         super(cause);
//     }
// 
//     public IORuntimeException(String message, IOException cause, boolean enableSuppression, boolean writableStackTrace) {
//         super(message, cause, enableSuppression, writableStackTrace);
//     }
// }


import static com.google.common.base.Preconditions.checkNotNull;
import com.github.xsavikx.androidscreencast.api.recording.atom.AtomType;
import com.github.xsavikx.androidscreencast.exception.IORuntimeException;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import static com.google.common.base.Preconditions.checkArgument;
/*
 * Copyright 2020 Yurii Serhiichuk
 *
 * 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 com.github.xsavikx.androidscreencast.api.recording;




public final class DataAtomOutputStream extends FilterOutputStream {

    private static final long MAC_TIMESTAMP_EPOCH = new GregorianCalendar(1904, Calendar.JANUARY, 1).getTimeInMillis();
    /**
     * The number of bytes written to the data output stream so far. If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
     */
    private long written;

    public DataAtomOutputStream(OutputStream out) {
        super(out);
    }

    /**
     * Increases the written counter by the specified value until it reaches Long.MAX_VALUE.
     */
    private void incCount(int value) {
        long temp = written + value;
        if (temp < 0) {
            temp = Long.MAX_VALUE;
        }
        written = temp;
    }

    /**
     * Returns the current value of the counter <code>written</code>, the number of bytes written to this data output stream so far. If the counter
     * overflows, it will be wrapped to Integer.MAX_VALUE.
     *
     * @return the value of the <code>written</code> field.
     * @see java.io.DataOutputStream#written
     */
    public final long size() {
        return written;
    }

    /**
     * Writes <code>len</code> bytes from the specified byte array starting at offset <code>off</code> to the underlying output stream. If no exception
     * is thrown, the counter <code>written</code> is incremented by <code>len</code> .
     *
     * @param b   the data.
     * @param off the start offset in the data.
     * @param len the number of bytes to write.
     * @throws IOException if an I/O error occurs.
     * @see java.io.FilterOutputStream#out
     */
    @Override
    public synchronized void write(byte[] b, int off, int len) throws IOException {
        out.write(b, off, len);
// Path: src/main/java/com/github/xsavikx/androidscreencast/api/recording/atom/AtomType.java
// public enum AtomType {
//     MEDIA_DATA("mdat"),
//     MOVIE("moov"),
//     MOVIE_HEADER("mvhd"),
//     TRACK("trak"),
//     TRACK_HEADER("tkhd"),
//     MEDIA("mdia"),
//     MEDIA_HEADER("mdhd"),
//     HANDLER("hdlr"),
//     MEDIA_HANDLER("mhlr"),
//     VIDEO("vide"),
//     MEDIA_INFORMATION("minf"),
//     VIDEO_MEDIA_INFORMATION("vmhd"),
//     FILE_ALIAS("alis"),
//     DATA_INFORMATION("dinf"),
//     DATA_REFERENCE("dref"),
//     SAMPLE_TABLE("stbl"),
//     SAMPLE_DESCRIPTION("stsd"),
//     RAW("raw "),
//     JAVA("java"),
//     JPEG("jpeg"),
//     PNG("png "),
//     TIME_TO_SAMPLE_MAPPING("stts"),
//     SAMPLE_TO_CHUNK_MAPPING("stsc"),
//     SAMPLE_SIZE("stsz"),
//     STANDARD_CHUNK_OFFSET_TABLE("stco"),
//     WIDE_CHUNK_OFFSET_TABLE("co64"),
//     FILE_TYPE("ftyp"),
//     QUICK_TIME("qt  "),
//     WIDE("wide"),
//     DATA_HANDLER("dhlr");
//     /**
//      * String representation of AtomType that must have exactly 4 characters
//      */
//     private final String stringRepresentation;
// 
//     AtomType(String stringRepresentation) {
//         this.stringRepresentation = stringRepresentation;
//     }
// 
//     public String toStringRepresentation() {
//         return stringRepresentation;
//     }
// }
// 
// Path: src/main/java/com/github/xsavikx/androidscreencast/exception/IORuntimeException.java
// public final class IORuntimeException extends AndroidScreenCastRuntimeException {
// 
//     public IORuntimeException(String message, IOException cause) {
//         super(message, cause);
//     }
// 
//     public IORuntimeException(IOException cause) {
//         super(cause);
//     }
// 
//     public IORuntimeException(String message, IOException cause, boolean enableSuppression, boolean writableStackTrace) {
//         super(message, cause, enableSuppression, writableStackTrace);
//     }
// }


// Path: src/main/java/com/github/xsavikx/androidscreencast/api/recording/DataAtomOutputStream.java
import static com.google.common.base.Preconditions.checkNotNull;
import com.github.xsavikx.androidscreencast.api.recording.atom.AtomType;
import com.github.xsavikx.androidscreencast.exception.IORuntimeException;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import static com.google.common.base.Preconditions.checkArgument;

/*
 * Copyright 2020 Yurii Serhiichuk
 *
 * 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 com.github.xsavikx.androidscreencast.api.recording;




public final class DataAtomOutputStream extends FilterOutputStream {

    private static final long MAC_TIMESTAMP_EPOCH = new GregorianCalendar(1904, Calendar.JANUARY, 1).getTimeInMillis();
    /**
     * The number of bytes written to the data output stream so far. If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
     */
    private long written;

    public DataAtomOutputStream(OutputStream out) {
        super(out);
    }

    /**
     * Increases the written counter by the specified value until it reaches Long.MAX_VALUE.
     */
    private void incCount(int value) {
        long temp = written + value;
        if (temp < 0) {
            temp = Long.MAX_VALUE;
        }
        written = temp;
    }

    /**
     * Returns the current value of the counter <code>written</code>, the number of bytes written to this data output stream so far. If the counter
     * overflows, it will be wrapped to Integer.MAX_VALUE.
     *
     * @return the value of the <code>written</code> field.
     * @see java.io.DataOutputStream#written
     */
    public final long size() {
        return written;
    }

    /**
     * Writes <code>len</code> bytes from the specified byte array starting at offset <code>off</code> to the underlying output stream. If no exception
     * is thrown, the counter <code>written</code> is incremented by <code>len</code> .
     *
     * @param b   the data.
     * @param off the start offset in the data.
     * @param len the number of bytes to write.
     * @throws IOException if an I/O error occurs.
     * @see java.io.FilterOutputStream#out
     */
    @Override
    public synchronized void write(byte[] b, int off, int len) throws IOException {
        out.write(b, off, len);
        incCount(len);