/*
 * Decompiled with CFR 0.152.
 */
package org.apache.logging.log4j.core.net.server;

import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.OptionalDataException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.net.server.AbstractSocketServer;
import org.apache.logging.log4j.core.net.server.JsonInputStreamLogEventBridge;
import org.apache.logging.log4j.core.net.server.LogEventBridge;
import org.apache.logging.log4j.core.net.server.ObjectInputStreamLogEventBridge;
import org.apache.logging.log4j.core.net.server.XmlInputStreamLogEventBridge;

public class TcpSocketServer<T extends InputStream>
extends AbstractSocketServer<T> {
    private final ConcurrentMap<Long, SocketHandler> handlers = new ConcurrentHashMap<Long, SocketHandler>();
    private final ServerSocket serverSocket;

    public static TcpSocketServer<InputStream> createJsonSocketServer(int port) throws IOException {
        return new TcpSocketServer<InputStream>(port, new JsonInputStreamLogEventBridge());
    }

    public static TcpSocketServer<ObjectInputStream> createSerializedSocketServer(int port) throws IOException {
        return new TcpSocketServer<ObjectInputStream>(port, new ObjectInputStreamLogEventBridge());
    }

    public static TcpSocketServer<InputStream> createXmlSocketServer(int port) throws IOException {
        return new TcpSocketServer<InputStream>(port, new XmlInputStreamLogEventBridge());
    }

    public static void main(String[] args) throws Exception {
        String line;
        if (args.length < 1 || args.length > 2) {
            System.err.println("Incorrect number of arguments");
            TcpSocketServer.printUsage();
            return;
        }
        int port = Integer.parseInt(args[0]);
        if (port <= 0 || port >= 65534) {
            System.err.println("Invalid port number");
            TcpSocketServer.printUsage();
            return;
        }
        if (args.length == 2 && args[1].length() > 0) {
            ConfigurationFactory.setConfigurationFactory(new AbstractSocketServer.ServerConfigurationFactory(args[1]));
        }
        TcpSocketServer<ObjectInputStream> socketServer = TcpSocketServer.createSerializedSocketServer(port);
        Thread serverThread = new Thread(socketServer);
        serverThread.start();
        Charset enc = Charset.defaultCharset();
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, enc));
        while (!((line = reader.readLine()) == null || line.equalsIgnoreCase("Quit") || line.equalsIgnoreCase("Stop") || line.equalsIgnoreCase("Exit"))) {
        }
        socketServer.shutdown();
        serverThread.join();
    }

    private static void printUsage() {
        System.out.println("Usage: ServerSocket port configFilePath");
    }

    public TcpSocketServer(int port, LogEventBridge<T> logEventInput) throws IOException {
        this(port, logEventInput, new ServerSocket(port));
    }

    public TcpSocketServer(int port, LogEventBridge<T> logEventInput, ServerSocket serverSocket) throws IOException {
        super(port, logEventInput);
        this.serverSocket = serverSocket;
    }

    @Override
    public void run() {
        while (this.isActive()) {
            if (this.serverSocket.isClosed()) {
                return;
            }
            try {
                Socket clientSocket = this.serverSocket.accept();
                clientSocket.setSoLinger(true, 0);
                SocketHandler handler = new SocketHandler(clientSocket);
                this.handlers.put(handler.getId(), handler);
                handler.start();
            }
            catch (IOException ioe) {
                if (this.serverSocket.isClosed()) {
                    return;
                }
                System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
                ioe.printStackTrace();
            }
        }
        for (Map.Entry entry : this.handlers.entrySet()) {
            SocketHandler handler = (SocketHandler)entry.getValue();
            handler.shutdown();
            try {
                handler.join();
            }
            catch (InterruptedException ie) {}
        }
    }

    public void shutdown() throws IOException {
        this.setActive(false);
        Thread.currentThread().interrupt();
        this.serverSocket.close();
    }

    private class SocketHandler
    extends Thread {
        private final T inputStream;
        private volatile boolean shutdown = false;

        public SocketHandler(Socket socket) throws IOException {
            this.inputStream = TcpSocketServer.this.logEventInput.wrapStream(socket.getInputStream());
        }

        /*
         * WARNING - Removed try catching itself - possible behaviour change.
         */
        @Override
        public void run() {
            boolean closed = false;
            try {
                try {
                    while (!this.shutdown) {
                        TcpSocketServer.this.logEventInput.logEvents(this.inputStream, TcpSocketServer.this);
                    }
                }
                catch (EOFException e) {
                    closed = true;
                }
                catch (OptionalDataException e) {
                    TcpSocketServer.this.logger.error("OptionalDataException eof=" + e.eof + " length=" + e.length, (Throwable)e);
                }
                catch (IOException e) {
                    TcpSocketServer.this.logger.error("IOException encountered while reading from socket", (Throwable)e);
                }
                if (!closed) {
                    try {
                        ((InputStream)this.inputStream).close();
                    }
                    catch (Exception exception) {
                        // empty catch block
                    }
                }
            }
            finally {
                TcpSocketServer.this.handlers.remove(this.getId());
            }
        }

        public void shutdown() {
            this.shutdown = true;
            this.interrupt();
        }
    }
}
