/**
* Copyright (c) 2015 unfoldingWord
* http://creativecommons.org/licenses/MIT/
* See LICENSE file for details.
* Contributors:
* PJ Fechner <pj@actsmedia.com>
*/
package services;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
import com.github.peejweej.androidsideloading.utilities.FileUtilities;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import model.DaoDBHelper;
import model.DataFileManager;
import model.daoModels.AudioBook;
import model.daoModels.AudioChapter;
import model.daoModels.Book;
import model.daoModels.Language;
import model.daoModels.Project;
import model.daoModels.Version;
import model.parsers.AudioBookParser;
import model.parsers.BookParser;
import model.parsers.LanguageParser;
import model.parsers.MediaType;
import model.parsers.ProjectParser;
import model.parsers.VersionParser;
import runnables.UpdateAndVerifyBookRunnable;
import utils.FileNameHelper;
import utils.FileUtil;
import utils.UWPreferenceDataManager;
/**
* Created by PJ Fechner
* Service for adding a version through SideLoading
*/
public class UWSideLoaderService extends UWUpdaterService {
private static final String TAG = "UWPreLoader";
public static final String SIDE_LOAD_TEXT_PARAM = "SIDE_LOAD_TEXT_PARAM";
public static final String BROAD_CAST_SIDE_LOAD_SUCCESSFUL = "org.unfoldingword.mobile.BROAD_CAST_SIDE_LOAD_SUCCESSFUL";
private String sideLoadText;
private Uri filesDir;
private boolean isLoadingAudio = false;
private boolean isLoadingVideo = false;
private int bitrate = -1;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Uri fileUri = intent.getData();
filesDir = DataFileManager.uncompressSideLoadedFiles(getApplicationContext(), new File(fileUri.getPath()));
startWithFilesDir(filesDir);
return START_STICKY;
}
private void startWithFilesDir(Uri dir) {
File textFile = null;
File directory = new File(dir.getPath());
File[] files = directory.listFiles();
if (files != null){
for (File file : files) {
String fileName = file.getName();
if (fileName.contains("json")) {
textFile = file;
} else if (fileName.contains(FileNameHelper.AUDIO_FILE_PREFIX)) {
isLoadingAudio = true;
bitrate = FileNameHelper.getBitrateFromFileName(file.getName());
} else if (fileName.contains(FileNameHelper.VIDEO_FILE_PREFIX)) {
isLoadingVideo = true;
}
}
}
if(textFile != null){
loadVersion(textFile);
}
}
private void loadVersion(File versionFile){
byte[] decompressedBytes = FileUtilities.getBytesFromFile(versionFile);
if(decompressedBytes != null) {
try {
sideLoadText = new String(decompressedBytes, "UTF-8");
addRunnable(new SideVersionsRunnable());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
stopService();
}
}
}
@Override
protected void stopService() {
getApplicationContext().sendBroadcast(new Intent(BROAD_CAST_SIDE_LOAD_SUCCESSFUL));
this.stopSelf();
}
class SideVersionsRunnable implements Runnable {
@Override
public void run() {
loadVersion();
runnableFinished();
}
private void loadVersion(){
try {
JSONObject jsonObject = new JSONObject(sideLoadText);
List<Book> books = sideLoadProject(jsonObject.getJSONObject("top"));
JSONObject sources = jsonObject.getJSONObject("sources");
for(Book book : books) {
try {
String signature = sources.getString(book.getSignatureUrl());
byte[] text = sources.getString(book.getSourceUrl()).getBytes("UTF-8");
DataFileManager.saveDataForBook(getApplicationContext(), book, text, MediaType.MEDIA_TYPE_TEXT, book.getSourceUrl());
DataFileManager.saveSignatureForBook(getApplicationContext(), book, signature.getBytes(), MediaType.MEDIA_TYPE_TEXT, book.getSignatureUrl());
// saveFile(text, book.getSourceUrl());
// saveFile(signature.getBytes("UTF-8"), book.getSignatureUrl());
UpdateAndVerifyBookRunnable runnable = new UpdateAndVerifyBookRunnable(book, getThis(), text, signature);
addRunnable(runnable, book.getVersion(), MediaType.MEDIA_TYPE_TEXT);
} catch (IOException e) {
e.printStackTrace();
}
}
}
catch (JSONException e){
e.printStackTrace();
}
}
}
private List<Book> sideLoadProject(JSONObject json){
Project model = new Project();
model = (Project) model.setupModelFromJson(json);
Project oldModel = Project.getModelForUniqueSlug(model.getUniqueSlug(),
DaoDBHelper.getDaoSession(getApplicationContext()));
if(oldModel != null){
model = oldModel;
}
else {
model.insertModel(DaoDBHelper.getDaoSession(getApplicationContext()));
}
List<Book> books = new ArrayList<Book>();
try {
JSONArray versionJson = json.getJSONArray(ProjectParser.LANGUAGES_JSON_KEY);
for(int i = 0; i < versionJson.length(); i++){
JSONObject bookJson = versionJson.optJSONObject(i);
books.addAll(sideLoadLanguage(bookJson, model));
}
}
catch (JSONException e){
e.printStackTrace();
}
return books;
}
private List<Book> sideLoadLanguage(JSONObject json, Project parent){
Language model = new Language();
model = (Language) model.setupModelFromJson(json, parent);
Language oldModel = Language.getModelForUniqueSlug(model.getUniqueSlug(),
DaoDBHelper.getDaoSession(getApplicationContext()));
if(oldModel != null){
model = oldModel;
}
else {
model.insertModel(DaoDBHelper.getDaoSession(getApplicationContext()));
}
List<Book> books = new ArrayList<Book>();
try {
JSONArray versionJson = json.getJSONArray(LanguageParser.VERSION_JSON_KEY);
for(int i = 0; i < versionJson.length(); i++){
JSONObject bookJson = versionJson.optJSONObject(i);
books.addAll(sideLoadVersion(bookJson, model));
}
}
catch (JSONException e){
e.printStackTrace();
}
return books;
}
private List<Book> sideLoadVersion(JSONObject json, Language parent){
Version model = new Version();
model = (Version) model.setupModelFromJson(json, parent);
Version oldModel = Version.getModelForUniqueSlug(model.getUniqueSlug(),
DaoDBHelper.getDaoSession(getApplicationContext()));
if(oldModel != null){
oldModel.updateWithModel(model);
UWPreferenceDataManager.willDeleteVersion(getApplicationContext(), oldModel);
model = oldModel;
}
else {
model.insertModel(DaoDBHelper.getDaoSession(getApplicationContext()));
}
List<Book> books = new ArrayList<Book>();
try {
JSONArray booksJson = json.getJSONArray(VersionParser.BOOKS_JSON_KEY);
for(int i = 0; i < booksJson.length(); i++){
JSONObject bookJson = booksJson.optJSONObject(i);
books.add(sideLoadBook(getApplicationContext(), bookJson, model));
}
}
catch (JSONException e){
e.printStackTrace();
}
return books;
}
private Book sideLoadBook(Context context, JSONObject json, Version parent){
Book model = new Book();
model = (Book) model.setupModelFromJson(json, parent);
Book oldModel = Book.getModelForUniqueSlug(model.getUniqueSlug(),
DaoDBHelper.getDaoSession(getApplicationContext()));
if(oldModel != null){
oldModel.updateWithModel(model);
oldModel.deleteBookContent(context);
model = oldModel;
}
else {
model.insertModel(DaoDBHelper.getDaoSession(getApplicationContext()));
}
try {
JSONObject mediaJson = json.getJSONObject(BookParser.MEDIA_JSON_KEY);
JSONObject audioJson = mediaJson.getJSONObject(BookParser.AUDIO_JSON_KEY);
sideLoadAudioBook(audioJson, model);
}
catch (JSONException e){
e.printStackTrace();
}
return model;
}
private AudioBook sideLoadAudioBook(JSONObject json, Book parent){
AudioBook model = new AudioBook();
model = (AudioBook) model.setupModelFromJson(json, parent);
if (model == null){
return null;
}
AudioBook oldModel = AudioBook.getModelForUniqueSlug(model.getUniqueSlug(),
DaoDBHelper.getDaoSession(getApplicationContext()));
if(oldModel != null){
oldModel.updateWithModel(model);
model = oldModel;
}
else {
model.insertModel(DaoDBHelper.getDaoSession(getApplicationContext()));
}
try {
JSONArray chapters = json.getJSONArray(AudioBookParser.SOURCE_LIST_JSON_KEY);
for(int i = 0; i < chapters.length(); i++){
JSONObject bookJson = chapters.optJSONObject(i);
sideLoadAudioChapter(bookJson, model);
}
}
catch (JSONException e){
e.printStackTrace();
}
return model;
}
private AudioChapter sideLoadAudioChapter(JSONObject json, AudioBook parent){
AudioChapter model = new AudioChapter();
model = (AudioChapter) model.setupModelFromJson(json, parent);
AudioChapter oldModel = AudioChapter.getModelForUniqueSlug(model.getUniqueSlug(),
DaoDBHelper.getDaoSession(getApplicationContext()));
if(oldModel != null){
oldModel.updateWithModel(model);
model = oldModel;
}
else {
model.insertModel(DaoDBHelper.getDaoSession(getApplicationContext()));
}
if(isLoadingAudio)
saveAudioFiles(model);
return model;
}
private void saveAudioFiles(AudioChapter audioChapter){
File sourceFile = new File(filesDir.getPath(), FileNameHelper.getShareAudioFileName(audioChapter, bitrate));
// File signatureFile = new File(filesDir.getPath(), FileNameHelper.getShareAudioSignatureFileName(audioChapter, bitrate));
if(sourceFile.exists()) {
DataFileManager.saveDataForBook(getApplicationContext(), audioChapter.getAudioBook().getBook(),
FileUtil.getBytesFromFile(sourceFile), MediaType.MEDIA_TYPE_AUDIO, audioChapter.getAudioUrl(bitrate));
// DataFileManager.saveSignatureForBook(getApplicationContext(), audioChapter.getAudioBook().getBook(),
// FileUtil.getBytesFromFile(signatureFile), MediaType.MEDIA_TYPE_AUDIO, audioChapter.getSignatureUrl(bitrate));
}
}
private void saveFile(byte[] bytes, String url){
try{
FileOutputStream fos = getApplicationContext().openFileOutput(FileNameHelper.getSaveFileNameFromUrl(url), Context.MODE_PRIVATE);
fos.write(bytes);
fos.close();
Log.i(TAG, "USFM File Saved");
}
catch (IOException e){
e.printStackTrace();
Log.e(TAG, "Error when saving USFM");
}
}
}