package org.apache.logging.log4j.core.appender;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.core.Layout;

public class RandomAccessFileManager extends OutputStreamManager {
   static final int DEFAULT_BUFFER_SIZE = 262144;
   private static final RandomAccessFileManager.RandomAccessFileManagerFactory FACTORY = new RandomAccessFileManager.RandomAccessFileManagerFactory();
   private final boolean isImmediateFlush;
   private final String advertiseURI;
   private final RandomAccessFile randomAccessFile;
   private final ByteBuffer buffer;
   private final ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal();

   protected RandomAccessFileManager(RandomAccessFile file, String fileName, OutputStream os, boolean immediateFlush, int bufferSize, String advertiseURI, Layout<? extends Serializable> layout) {
      super(os, fileName, layout);
      this.isImmediateFlush = immediateFlush;
      this.randomAccessFile = file;
      this.advertiseURI = advertiseURI;
      this.isEndOfBatch.set(Boolean.FALSE);
      this.buffer = ByteBuffer.allocate(bufferSize);
   }

   public static RandomAccessFileManager getFileManager(String fileName, boolean append, boolean isFlush, int bufferSize, String advertiseURI, Layout<? extends Serializable> layout) {
      return (RandomAccessFileManager)getManager(fileName, new RandomAccessFileManager.FactoryData(append, isFlush, bufferSize, advertiseURI, layout), FACTORY);
   }

   public Boolean isEndOfBatch() {
      return (Boolean)this.isEndOfBatch.get();
   }

   public void setEndOfBatch(boolean isEndOfBatch) {
      this.isEndOfBatch.set(isEndOfBatch);
   }

   protected synchronized void write(byte[] bytes, int offset, int length) {
      super.write(bytes, offset, length);
      boolean var4 = false;

      do {
         if (length > this.buffer.remaining()) {
            this.flush();
         }

         int chunk = Math.min(length, this.buffer.remaining());
         this.buffer.put(bytes, offset, chunk);
         offset += chunk;
         length -= chunk;
      } while(length > 0);

      if (this.isImmediateFlush || this.isEndOfBatch.get() == Boolean.TRUE) {
         this.flush();
      }

   }

   public synchronized void flush() {
      this.buffer.flip();

      try {
         this.randomAccessFile.write(this.buffer.array(), 0, this.buffer.limit());
      } catch (IOException var3) {
         String msg = "Error writing to RandomAccessFile " + this.getName();
         throw new AppenderLoggingException(msg, var3);
      }

      this.buffer.clear();
   }

   public synchronized void close() {
      this.flush();

      try {
         this.randomAccessFile.close();
      } catch (IOException var2) {
         LOGGER.error("Unable to close RandomAccessFile " + this.getName() + ". " + var2);
      }

   }

   public String getFileName() {
      return this.getName();
   }

   public int getBufferSize() {
      return this.buffer.capacity();
   }

   public Map<String, String> getContentFormat() {
      Map<String, String> result = new HashMap(super.getContentFormat());
      result.put("fileURI", this.advertiseURI);
      return result;
   }

   private static class RandomAccessFileManagerFactory implements ManagerFactory<RandomAccessFileManager, RandomAccessFileManager.FactoryData> {
      private RandomAccessFileManagerFactory() {
      }

      public RandomAccessFileManager createManager(String name, RandomAccessFileManager.FactoryData data) {
         File file = new File(name);
         File parent = file.getParentFile();
         if (null != parent && !parent.exists()) {
            parent.mkdirs();
         }

         if (!data.append) {
            file.delete();
         }

         RandomAccessFileManager.DummyOutputStream os = new RandomAccessFileManager.DummyOutputStream();

         try {
            RandomAccessFile raf = new RandomAccessFile(name, "rw");
            if (data.append) {
               raf.seek(raf.length());
            } else {
               raf.setLength(0L);
            }

            return new RandomAccessFileManager(raf, name, os, data.immediateFlush, data.bufferSize, data.advertiseURI, data.layout);
         } catch (Exception var8) {
            AbstractManager.LOGGER.error("RandomAccessFileManager (" + name + ") " + var8);
            return null;
         }
      }

      // $FF: synthetic method
      RandomAccessFileManagerFactory(Object x0) {
         this();
      }
   }

   private static class FactoryData {
      private final boolean append;
      private final boolean immediateFlush;
      private final int bufferSize;
      private final String advertiseURI;
      private final Layout<? extends Serializable> layout;

      public FactoryData(boolean append, boolean immediateFlush, int bufferSize, String advertiseURI, Layout<? extends Serializable> layout) {
         this.append = append;
         this.immediateFlush = immediateFlush;
         this.bufferSize = bufferSize;
         this.advertiseURI = advertiseURI;
         this.layout = layout;
      }
   }

   static class DummyOutputStream extends OutputStream {
      public void write(int b) throws IOException {
      }

      public void write(byte[] b, int off, int len) throws IOException {
      }
   }
}
