content: /*
   *
   * Copyright (c) 2008, All Rights Reserved.
   *
   * 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 zemberek.core.io;
  
  import com.google.common.base.Preconditions;
  import java.io.BufferedOutputStream;
  import java.io.BufferedWriter;
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.net.URL;
  import java.nio.charset.Charset;
  import java.util.Arrays;
  import java.util.Collection;
  
  /**
   * SimpleTextWriter is generally used for writing information to the files easily.
   * <p/>
   * This class will close the file internally after the operation is done by default. However, if it
   * is initiated using the Builder and keepOpen() or static "keepOpen" factories are used, Writer
   * needs to be defined in an ARM block.
   */
  public final class SimpleTextWriter implements AutoCloseable {
  
    private final String encoding;
    private final boolean keepOpen;
    private final BufferedWriter writer;
    private final OutputStream os;
    private boolean addNewLineBeforeClose;
  
  
    private SimpleTextWriter(
        BufferedWriter writer,
        OutputStream os,
        String encoding,
        boolean keepOpen,
        boolean addNewLineBeforeClose) {
      this.writer = writer;
      this.os = os;
      this.encoding = encoding;
      this.keepOpen = keepOpen;
      this.addNewLineBeforeClose = addNewLineBeforeClose;
    }
  
    /**
     * Creates a SimpleFileWriter using default encoding. it does not append to the File by default
     * and it closes the underlying output stream once any class method is called by default. If a
     * different behavior is required, SimpleFileWriter.Builder class needs to be used. Please note
     * that this constructor throws a runtime exception if file is not found instead of a
     * FileNotFoundException
     *
     * @param fileName name of the file to be written.
     * @throws java.io.IOException if a problem occurs while creating file.
     */
    public SimpleTextWriter(String fileName) throws IOException {
      this(fileName, Charset.defaultCharset().name());
    }
  
  
    /**
     * Creates a SimpleFileWriter using default encoding. it does not append to the File by default
     * and it closes the underlying output stream once any class method is called by default. If a
     * different behavior is required, SimpleFileWriter.Builder class needs to be used. Please note
     * that this constructor throws a runtime exception if file is not found instead of a
     * FileNotFoundException
     *
     * @param fileName name of the file to be written.
     * @param encoding encoding
     * @throws java.io.IOException if an error occurs while accessing fileName
     */
    public SimpleTextWriter(String fileName, String encoding) throws IOException {
      Preconditions.checkNotNull(fileName, "File name cannot be null..");
      this.os = new BufferedOutputStream(new FileOutputStream(fileName));
      this.writer = IOs.getBufferedWriter(os, encoding);
      this.encoding = encoding;
      keepOpen = false;
    }
  
    /**
     * Creates a SimpleFileWriter using given encoding. it does not append to the File by default and
     * it closes the underlying output stream once any of the method is called by default. If a
     * different behavior is required, SimpleFileWriter.Builder class needs to be used. Please note
     * that this constructor throws a runtime exception if file is not found instead of a
     * FileNotFoundException
     *
     * @param file : file to be written.
     * @param encoding encoding.
     * @throws java.io.IOException if an error occurs while accessing fileName
     */
    public SimpleTextWriter(File file, String encoding) throws IOException {
      Preconditions.checkNotNull(file, "File cannot be null..");
      this.os = new BufferedOutputStream(new FileOutputStream(file));
      this.writer = IOs.getBufferedWriter(os, encoding);
      this.encoding = encoding;
      keepOpen = false;
    }
  
    /**
     * Creates a SimpleFileWriter using default encoding. it does not append to the File by default
     * and it closes the underlying output stream once any of the method is called by default. If a
     * different behavior is required, SimpleFileWriter.Builder class needs to be used. Please note
     * that this constructor throws a runtime exception if file is not found instead of a
     * FileNotFoundException
     *
     * @param file : file to be written.
     * @throws java.io.IOException if an error occurs while accessing fileName
     */
    public SimpleTextWriter(File file) throws IOException {
      this(file, Charset.defaultCharset().name());
    }
  
    public static Builder builder(File file) throws IOException {
      return new Builder(file);
    }
  
    public static Builder utf8Builder(File file) throws IOException {
      return new Builder(file).encoding("UTF-8");
    }
  
    /**
     * creates a one shot writer, meaning that writer will be closed automatically after any wrte
     * method call.
     *
     * @param file file to write
     * @return a SimpleTextWriter
     * @throws java.io.IOException if a problem occurs while creating file.
     */
    public static SimpleTextWriter oneShotUTF8Writer(File file) throws IOException {
      return new Builder(file).encoding("utf-8").build();
    }
  
    /**
     * creates a one shot writer, meaning that writer will be closed automatically after any write
     * method call.
     *
     * @param file file to write
     * @return a SimpleTextWriter
     * @throws java.io.IOException if a problem occurs while creating file.
     */
    public static SimpleTextWriter keepOpenUTF8Writer(File file) throws IOException {
      return new Builder(file).encoding("utf-8").keepOpen().build();
    }
  
    /**
     * creates a one shot writer, meaning that writer will be closed automatically after any wrte
     * method call.
     *
     * @param os output stream
     * @param encoding encoding. if null, default encoding is used.
     * @return a SimpleTextWriter
     * @throws java.io.IOException if a problem occurs while creating file.
     */
    public static SimpleTextWriter keepOpenWriter(OutputStream os, String encoding)
        throws IOException {
      return new Builder(os).encoding(encoding).keepOpen().build();
    }
  
    /**
     * creates a one shot writer, meaning that writer will be closed automatically after any wrte
     * method call.
     *
     * @param os output stream
     * @param encoding encoding. if null, default encoding is used.
     * @return a SimpleTextWriter
     * @throws java.io.IOException if a problem occurs while creating file.
     */
    public static SimpleTextWriter oneShotWriter(OutputStream os, String encoding)
        throws IOException {
      return new Builder(os).encoding(encoding).build();
    }
  
    /**
     * creates a one shot writer, meaning that writer will be closed automatically after any wrte
     * method call. Uses the default character encoding
     *
     * @param os output stream
     * @return a SimpleTextWriter
     * @throws java.io.IOException if a problem occurs while creating file.
     */
    public static SimpleTextWriter keepOpenWriter(OutputStream os) throws IOException {
      return new Builder(os).keepOpen().build();
    }
  
    /**
     * returns the current encoding.
     *
     * @return current encoding.
     */
    public String getEncoding() {
      return encoding;
    }
  
    public boolean isKeepOpen() {
      return keepOpen;
    }
  
    /**
     * Writes value of each String in a collection to
     *
     * @param lines : lines to write, null entries produce blank lines
     * @return returns the current instance. keep in mind that if instance is not constructed with
     * keepopen, chaining other write methods will throw an exception.
     * @throws java.io.IOException if an I/O error occurs
     */
    public SimpleTextWriter writeLines(Collection<String> lines) throws IOException {
      try {
        IOs.writeLines(lines, writer);
        return this;
      } finally {
        if (!keepOpen) {
          close();
        }
      }
    }
  
    /**
     * Writes the value of each item in a String Array with the writer.
     *
     * @param lines : lines to write, null entries produce blank lines
     * @return returns the current instance. keep in mind that if instance is not constructed with
     * keepopen, chaining other write methods will throw an exception.
     * @throws java.io.IOException if an I/O error occurs
     */
    public SimpleTextWriter writeLines(String... lines) throws IOException {
      return writeLines(Arrays.asList(lines));
    }
  
    /**
     * Writes the <code>toString()</code> value of each item in a collection
     *
     * @param objects : lines to write, null entries produce blank lines
     * @return returns the current instance. keep in mind that if instance is not constructed with
     * keepopen, chaining other write methods will throw an exception.
     * @throws java.io.IOException if an I/O error occurs
     */
    public SimpleTextWriter writeToStringLines(Collection<?> objects) throws IOException {
      try {
        IOs.writeToStringLines(objects, writer);
        return this;
      } finally {
        if (!keepOpen) {
          close();
        }
      }
    }
  
    /**
     * Writes a String to the file.
     *
     * @param s : string to write.
     * @return returns the current instance. keep in mind that if instance is not constructed with
     * keepOpen(), chaining other write methods will throw an exception.
     * @throws java.io.IOException if an I/O error occurs
     */
    public SimpleTextWriter write(String s) throws IOException {
      try {
        if (s == null || s.length() == 0) {
          return this;
        }
        writer.write(s);
        return this;
      } finally {
        if (!keepOpen) {
          close();
        }
      }
    }
  
    /**
     * Writes a String to the file after appending a line separator to it.
     *
     * @param s : string to write.
     * @return returns the current instance. keep in mind that if instance is not constructed with
     * keepOpen(), chaining other write methods will throw an exception.
     * @throws java.io.IOException if an I/O error occurs
     */
    public SimpleTextWriter writeLine(String s) throws IOException {
      return write(s + IOs.LINE_SEPARATOR);
    }
  
    /**
     * Writes a LINE_SEPERATOR.
     *
     * @return returns the current instance.
     * @throws java.io.IOException if an I/O error occurs
     */
    public SimpleTextWriter writeLine() throws IOException {
      return write("" + IOs.LINE_SEPARATOR);
    }
  
    /**
     * Writes toString() of an object the file after appending a line separator to it.
     *
     * @param obj : object to write.
     * @return returns the current instance. keep in mind that if instance is not constructed with
     * keepOpen(), chaining other write methods will throw an exception.
     * @throws java.io.IOException if an I/O error occurs
     */
    public SimpleTextWriter writeLine(Object obj) throws IOException {
      return write(obj.toString() + IOs.LINE_SEPARATOR);
    }
  
    /**
     * copies an input stream contents to the writer target.
     *
     * @param is input stream
     * @return the text writer.
     * @throws java.io.IOException if an I/O error occurs
     */
    public SimpleTextWriter copyFromStream(InputStream is) throws IOException {
      IOs.copy(is, os, keepOpen);
      return this;
    }
  
    /**
     * copies an input stream contents to the writer target.
     *
     * @param urlStr URL string.
     * @return this
     * @throws java.io.IOException if an I/O errro occurs.
     */
    public SimpleTextWriter copyFromURL(String urlStr) throws IOException {
      URL url = new URL(urlStr);
      IOs.copy(url.openStream(), os, keepOpen);
      return this;
    }
  
    /**
     * closes the output stream opened for this writer. if the stream is already closed, it returns
     * silently.
     */
    public void close() throws IOException {
      if (addNewLineBeforeClose) {
        writer.newLine();
      }
      writer.flush();
      IOs.closeSilently(writer);
    }
  
    /**
     * This class provides a flexible way of constructing a SimpleFileWriter instance. Caller can set
     * the encoding, if write operations will append to the file or if the underlying output stream
     * needs to be kept open after operations. build() method will create a SimpleFileWriter with the
     * set parameters.
     */
    public static class Builder {
  
      private String _encoding;
      private boolean _keepOpen;
      private BufferedWriter _writer;
      private OutputStream _os;
      private boolean _addNewLineBeforeClose;
  
      public Builder(String fileName) throws IOException {
        Preconditions.checkNotNull(fileName, "File name cannot be null..");
        _encoding = Charset.defaultCharset().name();
        _os = new BufferedOutputStream(new FileOutputStream(fileName));
        this._writer = IOs.getBufferedWriter(_os, _encoding);
      }
  
      public Builder(OutputStream os) {
        Preconditions.checkNotNull(os, "File name cannot be null..");
        _encoding = Charset.defaultCharset().name();
        this._os = os;
        this._writer = IOs.getBufferedWriter(os, _encoding);
      }
  
      public Builder(File file) throws IOException {
        Preconditions.checkNotNull(file, "File name cannot be null..");
        _encoding = Charset.defaultCharset().name();
        _os = new BufferedOutputStream(new FileOutputStream(file));
        this._writer = IOs.getBufferedWriter(_os, _encoding);
      }
  
      public Builder encoding(String encoding) {
        if (encoding == null) {
          this._encoding = Charset.defaultCharset().name();
        }
        this._encoding = encoding;
        return this;
      }
  
      public Builder addNewLineBeforClose() {
        _addNewLineBeforeClose = true;
        return this;
      }
  
      public Builder keepOpen() {
        this._keepOpen = true;
        return this;
      }
  
      public SimpleTextWriter build() {
        return new SimpleTextWriter(_writer, _os, _encoding, _keepOpen, _addNewLineBeforeClose);
      }
    }
  
  }
  