/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt'
 * which is part of this source code package
 */

package com.scytl.slogger.policy;

import java.io.File;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * This policy will log to the given file while the rolled log files will be named with a sequential
 * numerical suffix starting with 0. (e.g. active file: file.log older files: file-5.log,
 * file-4.log,... oldest file: file-0.log.
 */
public class RollingSequentialFileNamePolicy extends LogFileNamePolicy {

  private static final String DOT = ".";

  private static final String SEPARATOR = "-";

  private final String baseFilePrefix;

  private final String baseFileSuffix;

  /**
   * Constructor.
   *
   * @param file The file to use for logging
   */
  public RollingSequentialFileNamePolicy(final File file) {
    super(file);

    String fileStr = getBaseFileName().getAbsolutePath();
    int index = fileStr.lastIndexOf(DOT);
    if (index < 0) {
      baseFilePrefix = fileStr;
      baseFileSuffix = "";
    } else {
      baseFilePrefix = fileStr.substring(0, index);
      baseFileSuffix = fileStr.substring(index);
    }
  }

  @Override
  public void closeCurrentFile() throws LogFileNamePolicyException {

    if (getBaseFileName().exists()) {
      int index = lastLogFileIndex();
      File target = new File(baseFilePrefix + SEPARATOR + (index + 1) + baseFileSuffix);
      rollOver(getBaseFileName(), target);
    }
  }

  @Override
  public File currentLogFile() {
    return getBaseFileName();
  }

  @Override
  public File lastLogFile() throws LogFileNamePolicyException {

    int index = lastLogFileIndex();

    if (index < 0) {
      return null;
    } else {
      return new File(baseFilePrefix + SEPARATOR + index + baseFileSuffix);
    }
  }

  @Override
  public Iterator<File> logFiles() throws LogFileNamePolicyException {

    return new Iterator<File>() {

      private int index;

      private boolean baseFileReached;

      @Override
      public boolean hasNext() {

        File file = new File(baseFilePrefix + SEPARATOR + index + baseFileSuffix);

        // if the indexed file doesn't exist try with the baseFile
        if (!file.exists() && !baseFileReached) {
          file = getBaseFileName();
        }

        return file.exists();
      }

      @Override
      public File next() {

        File file = new File(baseFilePrefix + SEPARATOR + index + baseFileSuffix);

        if (!file.exists()) {
          // try with the baseFile if not already given
          if (baseFileReached) {
            throw new NoSuchElementException();
          } else {
            file = getBaseFileName();
            baseFileReached = true;
          }
        }

        index++;
        return file;
      }

      @Override
      public void remove() {
        throw new UnsupportedOperationException();
      }

    };

  }

  @Override
  public File nextLogFile() throws LogFileNamePolicyException {

    return getBaseFileName();
  }

  /**
   * Rolls the files over.
   *
   * @param file the source file
   * @param target the target file
   * @throws LogFileNamePolicyException failed to roll the file over.
   */
  public void rollOver(final File file, final File target) throws LogFileNamePolicyException {

    if (!file.renameTo(target)) {
      throw new LogFileNamePolicyException(
          "Can not rename the rolling log file:" + file.getAbsolutePath());
    }
  }

  private int lastLogFileIndex() {
    int index = 0;
    String currentFile = baseFilePrefix + SEPARATOR + index + baseFileSuffix;
    while (new File(currentFile).exists()) {
      index++;
      currentFile = baseFilePrefix + SEPARATOR + index + baseFileSuffix;
    }

    return index - 1;
  }
}
