package monakhv.samlib.data;
import monakhv.samlib.db.AuthorController;
import monakhv.samlib.db.SQLController;
import monakhv.samlib.db.entity.Author;
import monakhv.samlib.db.entity.Book;
import monakhv.samlib.db.entity.SamLibConfig;
import monakhv.samlib.log.Log;
import java.io.*;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/*
* Copyright 2015 Dmitry Monakhov
*
* 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.
*
* 15.07.15.
*/
public abstract class AbstractDataExportImport {
private static final String DEBUG_TAG = "AbstractDataExportImport";
private static final String DATE_FORMAT = "dd-MM-yyyy";
public static final String DB_EXT = SQLController.DB_EXT;
public static final String DB_PREFIX = SQLController.DB_NAME;
private static final String TXT_PREFIX = "Authors";
private static final String TXT_EXT = ".txt";
private static final String HTM_EXT = ".htm";
private static final String HTML_EXT = ".html";
private AbstractSettings settings;
private File backupDIR;
public AbstractDataExportImport(AbstractSettings settings) {
this.settings = settings;
backupDIR=settings.getDataDirectory();
}
public abstract File getDataBase();
/**
* Test whether file for the book is fresh enought
*
* @return true if we need update file
*/
public boolean needUpdateFile(Book book) {
File ff = settings.getBookFile4Read(book, book.getFileType());
switch (book.getFileType()) {
case HTML:
return ff == null || !ff.exists() || ff.lastModified() < book.getModifyTime();
case FB2:
if (ff!= null) {
return ff.lastModified() < book.getModifyTime();
} else {
book.setFileType(AbstractSettings.FileType.HTML);
ff = settings.getBookFile4Read(book, book.getFileType());
return ff == null || !ff.exists() || ff.lastModified() < book.getModifyTime();
}
default:
throw new UnsupportedOperationException();
}
}
public String exportDB() {
return exportDB(backupDIR);
}
/**
* Export current database
* @param directory destination directory to export database to
* @return tru if the import is successful
*/
public String exportDB(File directory){
String backupDBPath = null;
try {
if (directory.canWrite()) {
backupDBPath = DB_PREFIX + "_" + getTimesuffix() + DB_EXT;
File currentDB = getDataBase();
File backupDB = new File(directory, backupDBPath);
Log.d(DEBUG_TAG, "Copy to: " + directory.getAbsolutePath() + " Can write: " + directory.canWrite());
fileCopy(currentDB, backupDB);
}
else {
Log.e(DEBUG_TAG, "Can not write to "+directory.toString() );
}
} catch (Exception e) {
Log.e(DEBUG_TAG, "Error to Copy DB: ", e);
return null;
}
return backupDBPath;
}
/**
* Just copy file <b>src</b> to file <b>dst</b>
*
* @param srcFile source file
* @param dstFile target file
*
* @throws IOException
*/
private static void fileCopy(File srcFile, File dstFile) throws IOException {
if (srcFile.exists()) {
FileChannel src=null;
FileChannel dst=null;
try {
src = new FileInputStream(srcFile).getChannel();
dst = new FileOutputStream(dstFile).getChannel();
dst.transferFrom(src, 0, src.size());
}
finally {
close(src);
close(dst);
}
}
}
private static void close(Closeable closeable){
if (closeable != null){
try {
closeable.close();
} catch (IOException e) {
Log.e(DEBUG_TAG,"Close error",e);
}
}
}
private static String getTimesuffix() {
SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
Date date = Calendar.getInstance().getTime();
return df.format(date);
}
/**
* Scan directory and return all files can be used to import DB from
*
*
* @return arrays of file names
*/
@SuppressWarnings("UnusedParameters")
public String[] getFilesToImportDB() {
List<String> files = new ArrayList<>();
@SuppressWarnings("UnusedDeclaration")
boolean re = backupDIR.mkdir();
for (String file : backupDIR.list()) {
if (file.startsWith(DB_PREFIX) && file.endsWith(DB_EXT)) {
files.add(file);
}
}
String[] res = new String[files.size()];
return files.toArray(res);
}
@SuppressWarnings("UnusedParameters")
public String[] getFilesToImportTxt() {
List<String> files = new ArrayList<>();
@SuppressWarnings("UnusedDeclaration")
boolean re = backupDIR.mkdir();
for (String file : backupDIR.list()) {
if (file.endsWith(TXT_EXT) || file.endsWith(HTM_EXT)|| file.endsWith(HTML_EXT) ) {
files.add(file);
}
}
String[] res = new String[files.size()];
return files.toArray(res);
}
/**
* Copy list of author's URLs to file and return the file name
*
*
* @return File Name where the list of urls is stored
*/
public String exportAuthorList(AuthorController authorController,File dir) {
String backupTxtPath = null;
BufferedWriter bw =null;
try {
if (dir.canWrite()) {
backupTxtPath = TXT_PREFIX + "_" + getTimesuffix() + TXT_EXT;
File backupTxt = new File(dir, backupTxtPath);
bw = new BufferedWriter(new FileWriter(backupTxt));
for (String u : getAuthorUrls(authorController)) {
bw.write(u);
bw.newLine();
}
bw.flush();
}
} catch (Exception e) {
Log.e(DEBUG_TAG, "Error export author urls: ", e);
return null;
}
finally {
close(bw);
}
return backupTxtPath;
}
public String exportAuthorList(AuthorController authorController) {
return exportAuthorList(authorController,backupDIR);
}
public List<String> getAuthorUrls(AuthorController sql){
List<String> res = new ArrayList<>();
List<Author> authors = sql.getAll();
for (Author a : authors) {
res.add(a.getUrlForBrowser(settings));
}
return res;
}
/**
* Replace working DB by DM from backup
*
*
* @param fileToImport backup db used to import from
* @return true if success
*/
public boolean importDB( String fileToImport) {
File backupDB = new File(backupDIR, fileToImport);
return importDB(backupDB);
}
/**
* Import database
*
* @param backupDB database file to import
* @return true if he import is successful
*/
public boolean importDB(File backupDB ) {
File currentDB = getDataBase();
try {
fileCopy(backupDB, currentDB);
} catch (FileNotFoundException ex) {
Log.e(DEBUG_TAG, "Error to Import DB: ", ex);
return false;
} catch (IOException ex) {
Log.e(DEBUG_TAG, "Error to Import DB: ", ex);
return false;
}
return true;
}
/**
* Delete books with expired LifeTime if it is restricted
*/
public void findDeleteBookFile() {
findDeleteBookFile( new File(backupDIR, AbstractSettings.BOOKS_DIR) );
}
private void findDeleteBookFile( File dir){
File[] files =dir.listFiles();
if (files == null){
return;
}
for (File file : files){
if ( file.isDirectory()){
findDeleteBookFile( file);
}
else {
settings.checkDeleteBook(file);
}
}
}
public ArrayList<String> importAuthorList(String fileToImport) {
File backupTxt = new File(backupDIR, fileToImport);
return importAuthorList(backupTxt);
}
public static ArrayList<String> importAuthorList( File backupTxt) {
ArrayList<String> urls = new ArrayList<>();
BufferedReader in=null;
try {
in = new BufferedReader(new FileReader(backupTxt));
String inputLine = in.readLine();
while (inputLine != null) {
String resstr = SamLibConfig.getParsedUrl(inputLine);
if (resstr != null){
urls.add(resstr);
}
inputLine = in.readLine();
}
} catch (FileNotFoundException ex) {
Log.e(DEBUG_TAG, "Error Import URL list", ex);
return null;
} catch (IOException ex) {
Log.e(DEBUG_TAG, "Error Import URL list ", ex);
return null;
}
finally {
close(in);
}
return urls;
}
}