// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/ConnectionNotAliveException.java
// public class ConnectionNotAliveException extends DragoniteException {
// 
//     public ConnectionNotAliveException() {
//         super("Connection is not alive");
//     }
// 
//     public ConnectionNotAliveException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/IncorrectSizeException.java
// public class IncorrectSizeException extends DragoniteException {
// 
//     public IncorrectSizeException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/SenderClosedException.java
// public class SenderClosedException extends DragoniteException {
// 
//     public SenderClosedException() {
//         super("Sender closed");
//     }
// 
//     public SenderClosedException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/misc/DragoniteGlobalConstants.java
// public final class DragoniteGlobalConstants {
// 
//     public static final String LIBRARY_VERSION = DragoniteBuildConfig.VERSION;
// 
//     public static final byte PROTOCOL_VERSION = 2;
// 
//     public static final int MIN_SEND_WINDOW_SIZE = 20;
// 
//     public static final int ACK_INTERVAL_MS = 10;
// 
//     public static final int MAX_FAST_RESEND_COUNT = 3;
// 
//     public static final int MAX_SLOW_RESEND_MULT = 4;
// 
//     public static final int INIT_RTT_MS = 200, RTT_MAX_VARIATION_MS = 200, RTT_UPDATE_INTERVAL_MS = 100, RTT_RESEND_CORRECTION_INTERVAL_MS = 2000;
// 
//     public static final int DEV_RTT_MULT = 4;
// 
//     public static final float RTT_RESENDED_REFRESH_MAX_MULT = 1.5f;
// 
//     public static final int MIN_CLOSE_WAIT_MS = 100, CLOSE_WAIT_RTT_MULT = 4;
// 
//     public static final int WEB_PANEL_PORT = 8000;
// 
// }
// 
// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/Message.java
// public interface Message {
// 
//     byte getVersion();
// 
//     MessageType getType();
// 
//     byte[] toBytes();
// 
//     int getFixedLength();
// 
// }


import com.vecsight.dragonite.sdk.exception.ConnectionNotAliveException;
import com.vecsight.dragonite.sdk.exception.IncorrectSizeException;
import com.vecsight.dragonite.sdk.exception.SenderClosedException;
import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants;
import com.vecsight.dragonite.sdk.msg.Message;
import java.io.IOException;
import java.net.SocketAddress;
/*
 * The Dragonite Project
 * -------------------------
 * See the LICENSE file in the root directory for license information.
 */


package com.vecsight.dragonite.sdk.socket;



public class DragoniteServerSocket extends DragoniteSocket {

    private final ReceiveHandler receiver;

    private final ResendHandler resender; //THREAD

    private final SendHandler sender;

    private final BucketPacketSender bucketPacketSender;

    private final ACKSender ackSender; //THREAD

    private final SocketAddress remoteAddress;

    private final DragoniteServer dragoniteServer;

    private volatile boolean alive = true;

    private volatile long lastReceiveTime, lastSendTime;

    private final ConnectionState state = new ConnectionState();

    private final Object closeLock = new Object();

    private volatile String description;

    public DragoniteServerSocket(final SocketAddress remoteAddress, final long sendSpeed, final DragoniteServer dragoniteServer) {
        this.remoteAddress = remoteAddress;
        this.dragoniteServer = dragoniteServer;

        updateLastReceiveTime();

        bucketPacketSender = new BucketPacketSender(bytes -> {
            dragoniteServer.sendPacket(bytes, remoteAddress);
            updateLastSendTime();
        }, sendSpeed);

        ackSender = new ACKSender(this, bucketPacketSender, DragoniteGlobalConstants.ACK_INTERVAL_MS, dragoniteServer.getPacketSize());

        resender = new ResendHandler(this, bucketPacketSender, state, dragoniteServer.getResendMinDelayMS(), DragoniteGlobalConstants.ACK_INTERVAL_MS);

        receiver = new ReceiveHandler(this, ackSender, state, dragoniteServer.getWindowMultiplier(),
                resender, dragoniteServer.getPacketSize());

        sender = new SendHandler(this, bucketPacketSender, receiver, state, resender, dragoniteServer.getPacketSize());

        description = "DSSocket";

    }

// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/ConnectionNotAliveException.java
// public class ConnectionNotAliveException extends DragoniteException {
// 
//     public ConnectionNotAliveException() {
//         super("Connection is not alive");
//     }
// 
//     public ConnectionNotAliveException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/IncorrectSizeException.java
// public class IncorrectSizeException extends DragoniteException {
// 
//     public IncorrectSizeException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/exception/SenderClosedException.java
// public class SenderClosedException extends DragoniteException {
// 
//     public SenderClosedException() {
//         super("Sender closed");
//     }
// 
//     public SenderClosedException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/misc/DragoniteGlobalConstants.java
// public final class DragoniteGlobalConstants {
// 
//     public static final String LIBRARY_VERSION = DragoniteBuildConfig.VERSION;
// 
//     public static final byte PROTOCOL_VERSION = 2;
// 
//     public static final int MIN_SEND_WINDOW_SIZE = 20;
// 
//     public static final int ACK_INTERVAL_MS = 10;
// 
//     public static final int MAX_FAST_RESEND_COUNT = 3;
// 
//     public static final int MAX_SLOW_RESEND_MULT = 4;
// 
//     public static final int INIT_RTT_MS = 200, RTT_MAX_VARIATION_MS = 200, RTT_UPDATE_INTERVAL_MS = 100, RTT_RESEND_CORRECTION_INTERVAL_MS = 2000;
// 
//     public static final int DEV_RTT_MULT = 4;
// 
//     public static final float RTT_RESENDED_REFRESH_MAX_MULT = 1.5f;
// 
//     public static final int MIN_CLOSE_WAIT_MS = 100, CLOSE_WAIT_RTT_MULT = 4;
// 
//     public static final int WEB_PANEL_PORT = 8000;
// 
// }
// 
// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/msg/Message.java
// public interface Message {
// 
//     byte getVersion();
// 
//     MessageType getType();
// 
//     byte[] toBytes();
// 
//     int getFixedLength();
// 
// }


// Path: dragonite-sdk/src/main/java/com/vecsight/dragonite/sdk/socket/DragoniteServerSocket.java
import com.vecsight.dragonite.sdk.exception.ConnectionNotAliveException;
import com.vecsight.dragonite.sdk.exception.IncorrectSizeException;
import com.vecsight.dragonite.sdk.exception.SenderClosedException;
import com.vecsight.dragonite.sdk.misc.DragoniteGlobalConstants;
import com.vecsight.dragonite.sdk.msg.Message;
import java.io.IOException;
import java.net.SocketAddress;

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


package com.vecsight.dragonite.sdk.socket;



public class DragoniteServerSocket extends DragoniteSocket {

    private final ReceiveHandler receiver;

    private final ResendHandler resender; //THREAD

    private final SendHandler sender;

    private final BucketPacketSender bucketPacketSender;

    private final ACKSender ackSender; //THREAD

    private final SocketAddress remoteAddress;

    private final DragoniteServer dragoniteServer;

    private volatile boolean alive = true;

    private volatile long lastReceiveTime, lastSendTime;

    private final ConnectionState state = new ConnectionState();

    private final Object closeLock = new Object();

    private volatile String description;

    public DragoniteServerSocket(final SocketAddress remoteAddress, final long sendSpeed, final DragoniteServer dragoniteServer) {
        this.remoteAddress = remoteAddress;
        this.dragoniteServer = dragoniteServer;

        updateLastReceiveTime();

        bucketPacketSender = new BucketPacketSender(bytes -> {
            dragoniteServer.sendPacket(bytes, remoteAddress);
            updateLastSendTime();
        }, sendSpeed);

        ackSender = new ACKSender(this, bucketPacketSender, DragoniteGlobalConstants.ACK_INTERVAL_MS, dragoniteServer.getPacketSize());

        resender = new ResendHandler(this, bucketPacketSender, state, dragoniteServer.getResendMinDelayMS(), DragoniteGlobalConstants.ACK_INTERVAL_MS);

        receiver = new ReceiveHandler(this, ackSender, state, dragoniteServer.getWindowMultiplier(),
                resender, dragoniteServer.getPacketSize());

        sender = new SendHandler(this, bucketPacketSender, receiver, state, resender, dragoniteServer.getPacketSize());

        description = "DSSocket";

    }

    protected void onHandleMessage(final Message message, final int pktLength) {