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.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.logging.log4j.core.config.ConfigurationFactory;

public class TcpSocketServer<T extends InputStream> extends AbstractSocketServer<T> {
   private final ConcurrentMap<Long, TcpSocketServer<T>.SocketHandler> handlers;
   private final ServerSocket serverSocket;

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

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

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

   public static void main(String[] args) throws Exception {
      if (args.length >= 1 && args.length <= 2) {
         int port = Integer.parseInt(args[0]);
         if (port > 0 && port < 65534) {
            if (args.length == 2 && args[1].length() > 0) {
               ConfigurationFactory.setConfigurationFactory(new AbstractSocketServer.ServerConfigurationFactory(args[1]));
            }

            TcpSocketServer<ObjectInputStream> socketServer = createSerializedSocketServer(port);
            Thread serverThread = new Thread(socketServer);
            serverThread.start();
            Charset enc = Charset.defaultCharset();
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, enc));

            String line;
            do {
               line = reader.readLine();
            } while(line != null && !line.equalsIgnoreCase("Quit") && !line.equalsIgnoreCase("Stop") && !line.equalsIgnoreCase("Exit"));

            socketServer.shutdown();
            serverThread.join();
         } else {
            System.err.println("Invalid port number");
            printUsage();
         }
      } else {
         System.err.println("Incorrect number of arguments");
         printUsage();
      }
   }

   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.handlers = new ConcurrentHashMap();
      this.serverSocket = serverSocket;
   }

   public void run() {
      while(this.isActive()) {
         if (this.serverSocket.isClosed()) {
            return;
         }

         try {
            Socket clientSocket = this.serverSocket.accept();
            clientSocket.setSoLinger(true, 0);
            TcpSocketServer<T>.SocketHandler handler = new TcpSocketServer.SocketHandler(clientSocket);
            this.handlers.put(handler.getId(), handler);
            handler.start();
         } catch (IOException var6) {
            if (this.serverSocket.isClosed()) {
               return;
            }

            System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
            var6.printStackTrace();
         }
      }

      Iterator i$ = this.handlers.entrySet().iterator();

      while(i$.hasNext()) {
         Entry<Long, TcpSocketServer<T>.SocketHandler> entry = (Entry)i$.next();
         TcpSocketServer<T>.SocketHandler handler = (TcpSocketServer.SocketHandler)entry.getValue();
         handler.shutdown();

         try {
            handler.join();
         } catch (InterruptedException var5) {
         }
      }

   }

   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());
      }

      public void run() {
         boolean closed = false;

         try {
            try {
               while(!this.shutdown) {
                  TcpSocketServer.this.logEventInput.logEvents(this.inputStream, TcpSocketServer.this);
               }
            } catch (EOFException var10) {
               closed = true;
            } catch (OptionalDataException var11) {
               TcpSocketServer.this.logger.error((String)("OptionalDataException eof=" + var11.eof + " length=" + var11.length), (Throwable)var11);
            } catch (IOException var12) {
               TcpSocketServer.this.logger.error((String)"IOException encountered while reading from socket", (Throwable)var12);
            }

            if (!closed) {
               try {
                  this.inputStream.close();
               } catch (Exception var9) {
               }
            }
         } finally {
            TcpSocketServer.this.handlers.remove(this.getId());
         }

      }

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