/*
 * Copyright 2015-2025 the original author or authors.
 * 
 * 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 sockslib.server;

import sockslib.common.SocksException;
import sockslib.common.net.NetworkMonitor;
import sockslib.server.msg.ReadableMessage;
import sockslib.server.msg.WritableMessage;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Map;

/**
 * The class <code>Session</code> represents a session between client with SOCKS server.
 * This class is simple encapsulation of java.net.Socket.
 *
 * @author Youchao Feng
 * @version 1.0
 * @date Apr 5, 2015 10:21:28 AM
 */
public interface Session {

    /**
     * Returns socket.
     *
     * @return socket that connected remote host.
     */
    Socket getSocket();

    /**
     * Writes bytes in output stream.
     *
     * @param bytes Bytes
     * @throws SocksException If a SOCKS protocol error occurred.
     * @throws IOException    If an I/O error occurred.
     */
    void write(byte[] bytes) throws SocksException, IOException;

    /**
     * Writes bytes in output stream.
     *
     * @param bytes  Bytes
     * @param offset Offset
     * @param length Bytes length.
     * @throws SocksException If a SOCKS protocol error occurred.
     * @throws IOException    If an I/O error occurred.
     */
    void write(byte[] bytes, int offset, int length) throws SocksException, IOException;

    /**
     * Writes <code>Message</code> in output stream.
     *
     * @param message {@link WritableMessage} instance.
     * @throws SocksException If a SOCKS protocol error occurred.
     * @throws IOException    If an I/O error occurred.
     */
    void write(WritableMessage message) throws SocksException, IOException;

    /**
     * Read a buffer.
     *
     * @param bytes Buffer which read in.
     * @return Read length
     * @throws SocksException If a SOCKS protocol error occurred.
     * @throws IOException    If an I/O error occurred.
     */
    int read(byte[] bytes) throws SocksException, IOException;

    /**
     * Reads a message.
     *
     * @param message a readable message.
     * @return Read bytes size.
     * @throws SocksException If a SOCKS protocol error occurred.
     * @throws IOException    If an I/O error occurred.
     */
    int read(ReadableMessage message) throws SocksException, IOException;

    /**
     * Gets session ID.
     *
     * @return session ID.
     */
    long getId();


    /**
     * Closes connection and removes itself from managed sessions.
     */
    void close();

    /**
     * Gets input stream.
     *
     * @return Input stream.
     */
    InputStream getInputStream();

    /**
     * Gets output stream.
     *
     * @return Output stream.
     */
    OutputStream getOutputStream();


    /**
     * Gets all sessions that be managed.
     *
     * @return All sessions.
     */
    Map<Long, Session> getManagedSessions();

    /**
     * Get remote host's IP address and port.
     *
     * @return Remote host's IP address and port.
     */
    SocketAddress getClientAddress();

    void setAttribute(Object key, Object value);

    Object getAttribute(Object key);

    /**
     * Returns all attributes.
     *
     * @return All attributes.
     */
    Map<Object, Object> getAttributes();

    /**
     * Clear all attributes in session.
     */
    void clearAllAttributes();

    /**
     * Returns <code>true</code> if the session is closed.
     *
     * @return If the session is closed, it returns <code>true</code>.
     */
    boolean isClose();

    /**
     * Returns <code>true</code> if the session is connected.
     *
     * @return If the session is connected returns <code>true</code>.
     */
    boolean isConnected();

    NetworkMonitor getNetworkMonitor();
}
