/*
* This file is part of Fim - File Integrity Manager
*
* Copyright (C) 2017 Etienne Vrignaud
*
* Fim is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fim is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Fim. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fim.internal.hash;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.fim.model.Context;
import org.fim.util.Logger;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import static org.fim.model.HashMode.dontHash;
import static org.fim.util.FileUtil.byteCountToDisplaySize;
public class HashProgress {
public static final int PROGRESS_DISPLAY_FILE_COUNT = 10;
private static final List<Pair<Character, Integer>> progressChars = Arrays.asList(
Pair.of('.', 0),
Pair.of('o', 20_000_000),
Pair.of('8', 50_000_000),
Pair.of('O', 100_000_000),
Pair.of('@', 200_000_000),
Pair.of('#', 1000_000_000)
);
private final Context context;
private long summedFileLength;
private int fileCount;
private int hashProgressWidth;
private CountDownLatch hashIndicator;
public HashProgress(Context context) {
this.context = context;
this.hashProgressWidth = getHashProgressWidth();
this.hashIndicator = new CountDownLatch(2);
}
public void hashStarted() {
hashIndicator.countDown();
}
public boolean isHashStarted() {
return hashIndicator.getCount() == 1;
}
public void noMoreFileToHash() {
hashIndicator.countDown();
}
public void waitAllFilesToBeHashed() {
try {
hashIndicator.await();
} catch (InterruptedException e) {
// Ok. Just get out
}
}
public synchronized void outputInit() {
summedFileLength = 0;
fileCount = 0;
}
synchronized void updateOutput(long fileSize) {
fileCount++;
if (isProgressDisplayed()) {
summedFileLength += fileSize;
if (fileCount % PROGRESS_DISPLAY_FILE_COUNT == 0) {
Logger.out.print(getProgressChar(summedFileLength));
summedFileLength = 0;
}
}
if (fileCount % (hashProgressWidth * PROGRESS_DISPLAY_FILE_COUNT) == 0) {
if (isProgressDisplayed()) {
Logger.newLine();
}
}
}
public String hashLegend() {
StringBuilder sb = new StringBuilder();
for (int progressIndex = progressChars.size() - 1; progressIndex >= 0; progressIndex--) {
Pair<Character, Integer> progressPair = progressChars.get(progressIndex);
char marker = progressPair.getLeft();
sb.append(marker);
int fileLength = progressPair.getRight();
if (fileLength == 0) {
sb.append(" otherwise");
} else {
sb.append(" > ").append(byteCountToDisplaySize(fileLength));
}
sb.append(", ");
}
String legend = sb.toString();
legend = legend.substring(0, legend.length() - 2);
return legend;
}
char getProgressChar(long fileLength) {
int progressIndex;
for (progressIndex = progressChars.size() - 1; progressIndex >= 0; progressIndex--) {
Pair<Character, Integer> progressPair = progressChars.get(progressIndex);
if (fileLength >= progressPair.getRight()) {
return progressPair.getLeft();
}
}
return ' ';
}
public synchronized void outputStop() {
if (isProgressDisplayed()) {
if (fileCount >= PROGRESS_DISPLAY_FILE_COUNT) {
Logger.newLine();
}
}
}
public boolean isProgressDisplayed() {
return context.isVerbose() && context.getHashMode() != dontHash;
}
private int getHashProgressWidth() {
int width = 100;
if (!SystemUtils.IS_OS_WINDOWS) {
try {
String result = System.getenv("TERMINAL_COLUMNS");
int terminalColumns = Integer.parseInt(result);
if (terminalColumns > 0) {
width = (int) (terminalColumns * 0.9);
}
} catch (Exception e) {
// Never mind use the default value
}
}
return width;
}
}