// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/ConnectionAlreadyExistsException.java
// public class ConnectionAlreadyExistsException extends MuxException {
// 
//     public ConnectionAlreadyExistsException() {
//         super("Connection already exists");
//     }
// 
//     public ConnectionAlreadyExistsException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/MultiplexerClosedException.java
// public class MultiplexerClosedException extends MuxException {
// 
//     public MultiplexerClosedException() {
//         super("Multiplexer closed");
//     }
// 
//     public MultiplexerClosedException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/Frame.java
// public interface Frame {
// 
//     byte getVersion();
// 
//     FrameType getType();
// 
//     byte[] toBytes();
// 
//     int getFixedLength();
// 
//     int getExpectedLength();
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/FrameParser.java
// public class FrameParser {
// 
//     private final FrameBuffer frameBuffer;
// 
//     private boolean needMore = false;
// 
//     private int expectedLength = 0;
// 
//     public FrameParser(final int maxFrameSize) {
//         frameBuffer = new FrameBuffer(maxFrameSize);
//     }
// 
//     public Frame feed(final byte[] rawBytes) {
// 
//         frameBuffer.add(rawBytes);
// 
//         if (!needMore || frameBuffer.getSize() >= expectedLength) {
// 
//             try {
//                 final Frame frame = parseFrameRaw(frameBuffer.get());
// 
//                 if (frame.getExpectedLength() == 0) {
//                     frameBuffer.reset();
//                     needMore = false;
//                     return frame;
// 
//                 } else {
//                     expectedLength = frame.getExpectedLength();
//                     needMore = true;
//                 }
//             } catch (final IncorrectFrameException e) {
//                 frameBuffer.reset();
//                 needMore = false;
//             }
//             return null;
// 
//         } else {
//             return null;
//         }
// 
//     }
// 
//     private static Frame parseFrameRaw(final byte[] rawBytes) throws IncorrectFrameException {
//         if (rawBytes.length >= 2) {
//             try {
//                 switch (FrameType.fromByte(rawBytes[1])) {
//                     case CREATE:
//                         return new CreateConnectionFrame(rawBytes);
//                     case CLOSE:
//                         return new CloseConnectionFrame(rawBytes);
//                     case DATA:
//                         return new DataFrame(rawBytes);
//                     case PAUSE:
//                         return new PauseConnectionFrame(rawBytes);
//                     case CONTINUE:
//                         return new ContinueConnectionFrame(rawBytes);
//                     default:
//                         throw new IncorrectFrameException("Unknown Frame Type");
//                 }
//             } catch (final IllegalArgumentException e) {
//                 throw new IncorrectFrameException("Unknown Frame Type");
//             }
//         } else {
//             throw new IncorrectFrameException("Packet is too short");
//         }
//     }
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/FrameType.java
// private static final FrameType[] types = FrameType.values();


import com.vecsight.dragonite.mux.exception.ConnectionAlreadyExistsException;
import com.vecsight.dragonite.mux.exception.MultiplexerClosedException;
import com.vecsight.dragonite.mux.frame.Frame;
import com.vecsight.dragonite.mux.frame.FrameParser;
import com.vecsight.dragonite.mux.frame.types.*;
import java.util.*;
/*
 * The Dragonite Project
 * -------------------------
 * See the LICENSE file in the root directory for license information.
 */


package com.vecsight.dragonite.mux.conn;



public class Multiplexer {

    private final PacketSender packetSender;

    private final FrameParser frameParser;

    private final Map<Short, MultiplexedConnection> connectionMap = new HashMap<>();

    private final Object connLock = new Object();

    private final Queue<MultiplexedConnection> acceptQueue = new LinkedList<>();

    private final Object acceptLock = new Object();

    private volatile boolean alive = true;

    public Multiplexer(final PacketSender packetSender, final int maxFrameSize) {
        this.packetSender = packetSender;
        frameParser = new FrameParser(maxFrameSize);
    }

// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/ConnectionAlreadyExistsException.java
// public class ConnectionAlreadyExistsException extends MuxException {
// 
//     public ConnectionAlreadyExistsException() {
//         super("Connection already exists");
//     }
// 
//     public ConnectionAlreadyExistsException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/MultiplexerClosedException.java
// public class MultiplexerClosedException extends MuxException {
// 
//     public MultiplexerClosedException() {
//         super("Multiplexer closed");
//     }
// 
//     public MultiplexerClosedException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/Frame.java
// public interface Frame {
// 
//     byte getVersion();
// 
//     FrameType getType();
// 
//     byte[] toBytes();
// 
//     int getFixedLength();
// 
//     int getExpectedLength();
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/FrameParser.java
// public class FrameParser {
// 
//     private final FrameBuffer frameBuffer;
// 
//     private boolean needMore = false;
// 
//     private int expectedLength = 0;
// 
//     public FrameParser(final int maxFrameSize) {
//         frameBuffer = new FrameBuffer(maxFrameSize);
//     }
// 
//     public Frame feed(final byte[] rawBytes) {
// 
//         frameBuffer.add(rawBytes);
// 
//         if (!needMore || frameBuffer.getSize() >= expectedLength) {
// 
//             try {
//                 final Frame frame = parseFrameRaw(frameBuffer.get());
// 
//                 if (frame.getExpectedLength() == 0) {
//                     frameBuffer.reset();
//                     needMore = false;
//                     return frame;
// 
//                 } else {
//                     expectedLength = frame.getExpectedLength();
//                     needMore = true;
//                 }
//             } catch (final IncorrectFrameException e) {
//                 frameBuffer.reset();
//                 needMore = false;
//             }
//             return null;
// 
//         } else {
//             return null;
//         }
// 
//     }
// 
//     private static Frame parseFrameRaw(final byte[] rawBytes) throws IncorrectFrameException {
//         if (rawBytes.length >= 2) {
//             try {
//                 switch (FrameType.fromByte(rawBytes[1])) {
//                     case CREATE:
//                         return new CreateConnectionFrame(rawBytes);
//                     case CLOSE:
//                         return new CloseConnectionFrame(rawBytes);
//                     case DATA:
//                         return new DataFrame(rawBytes);
//                     case PAUSE:
//                         return new PauseConnectionFrame(rawBytes);
//                     case CONTINUE:
//                         return new ContinueConnectionFrame(rawBytes);
//                     default:
//                         throw new IncorrectFrameException("Unknown Frame Type");
//                 }
//             } catch (final IllegalArgumentException e) {
//                 throw new IncorrectFrameException("Unknown Frame Type");
//             }
//         } else {
//             throw new IncorrectFrameException("Packet is too short");
//         }
//     }
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/frame/FrameType.java
// private static final FrameType[] types = FrameType.values();


// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/conn/Multiplexer.java
import com.vecsight.dragonite.mux.exception.ConnectionAlreadyExistsException;
import com.vecsight.dragonite.mux.exception.MultiplexerClosedException;
import com.vecsight.dragonite.mux.frame.Frame;
import com.vecsight.dragonite.mux.frame.FrameParser;
import com.vecsight.dragonite.mux.frame.types.*;
import java.util.*;

/*
 * The Dragonite Project
 * -------------------------
 * See the LICENSE file in the root directory for license information.
 */


package com.vecsight.dragonite.mux.conn;



public class Multiplexer {

    private final PacketSender packetSender;

    private final FrameParser frameParser;

    private final Map<Short, MultiplexedConnection> connectionMap = new HashMap<>();

    private final Object connLock = new Object();

    private final Queue<MultiplexedConnection> acceptQueue = new LinkedList<>();

    private final Object acceptLock = new Object();

    private volatile boolean alive = true;

    public Multiplexer(final PacketSender packetSender, final int maxFrameSize) {
        this.packetSender = packetSender;
        frameParser = new FrameParser(maxFrameSize);
    }

    public MultiplexedConnection createConnection(final short connID) throws ConnectionAlreadyExistsException, MultiplexerClosedException {