/*
 * Copyright (c) 2016 Andoni del Olmo
 *
 * 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 org.ado.musicdroid.service;

import com.avconv4java.core.AVCommand;
import com.avconv4java.core.AVRootOptions;
import com.avconv4java.option.AVAudioOptions;
import com.avconv4java.util.process.ProcessInfo;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import org.ado.musicdroid.common.Mp3Utils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.vidstige.jadb.JadbDevice;
import se.vidstige.jadb.JadbException;
import se.vidstige.jadb.RemoteFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static org.ado.musicdroid.common.AppConstants.ANDROID_MUSIC_BASE_DIRECTORY;
import static org.ado.musicdroid.common.AppConstants.EXPORT_DIRECTORY;
import static org.apache.commons.lang3.Validate.notNull;

/**
 * Class description here.
 *
 * @author andoni
 * @since 06.09.2014
 */
public class MediaConverterService extends Service<File> {

    private final Logger LOGGER = LoggerFactory.getLogger(MediaConverterService.class);

    private JadbDevice jadbDevice;
    private File[] songFiles;

    public void setJadbDevice(final JadbDevice jadbDevice) {
        notNull(jadbDevice, "jadbDevice cannot be null");
        this.jadbDevice = jadbDevice;
    }

    public void setSongFiles(final Collection<File> songFiles) {
        notNull(songFiles, "songFiles cannot be null");
        this.songFiles = songFiles.toArray(new File[songFiles.size()]);
    }

    @Override
    protected Task<File> createTask() {
        return new Task<File>() {
            private final List<String> albumCoverProcessedList = new ArrayList<>();

            @Override
            protected File call() throws Exception {
                for (final File songFile : songFiles) {
                    updateValue(songFile);
                    copyAlbumCoverIfNeeded(songFile);
                    jadbDevice.push(convertSong(songFile), new RemoteFile(getRemoteLocation(songFile)));
                }
                return null;
            }

            private void copyAlbumCoverIfNeeded(File songFile) throws JadbException, IOException {
                final String albumName = getAlbumRelativePath(songFile);
                if (!albumCoverProcessedList.contains(albumName)) {
                    final InputStream inputStream = Mp3Utils.getAlbumCover(songFile);
                    if (inputStream != null) {
                        final File tempFile = File.createTempFile("cover", "image");
                        FileUtils.copyInputStreamToFile(inputStream, tempFile);
                        jadbDevice.push(tempFile,
                                new RemoteFile(
                                        getAlbumCoverRemoteLocation(songFile,
                                                MimeTypeMapping.getFileExtension(Mp3Utils.getAlbumCoverMimeType(songFile)))));
                    }
                    albumCoverProcessedList.add(albumName);
                }
            }

            private String getAlbumCoverRemoteLocation(File songFile, String fileExtension) {
                return ANDROID_MUSIC_BASE_DIRECTORY + getAlbumRelativePath(songFile) + "cover." + fileExtension;
            }

            private String getAlbumRelativePath(File songFile) {
                final String s = songFile.getAbsolutePath().substring(System.getenv("MUSIC_HOME").length());
                return s.substring(0, s.lastIndexOf("/") + 1);
            }

            private File convertSong(final File songFile) throws Exception {
                final AVRootOptions options =
                        AVRootOptions.create(songFile.getAbsolutePath(), getExportDirectory(songFile))
                                .builders(
                                        AVAudioOptions.create().audioBitRate(128)
                                );
                final AVCommand command = new AVCommand()
                        .setDebug(true)
                        .setTimeout(10 * 60 * 60 * 1000L);

                LOGGER.info("Convert song [" + songFile.getAbsolutePath() + "]");
                final ProcessInfo processInfo = command.run(options);
                final String outputFile = options.getOutputFile();

                LOGGER.info(String.format("Output file: %s, return code: %d", outputFile, processInfo.getStatusCode()));
                if (processInfo.getStatusCode() != 0) {
                    LOGGER.error(processInfo.toString());
                }
                return new File(outputFile);
            }

            private String getExportDirectory(File songFile) {
                final File exportFile = new File(EXPORT_DIRECTORY, songFile.getAbsolutePath().substring(System.getenv("MUSIC_HOME").length()));
                final File exportDirectory = new File(FilenameUtils.getFullPath(exportFile.getAbsolutePath()));
                if (!exportDirectory.exists()) {
                    try {
                        FileUtils.forceMkdir(exportDirectory);
                    } catch (IOException e) {
                        // ignore
                    }
                }
                return exportFile.getAbsolutePath();
            }

            private String getRemoteLocation(File file) {
                return ANDROID_MUSIC_BASE_DIRECTORY + file.getAbsolutePath().substring(System.getenv("MUSIC_HOME").length());
            }
        };
    }
}
@@ -872,16 +872,67 @@
 t.Task;%0A
+import org.ado.musicdroid.common.AppConfiguration;%0A
 import o
@@ -962,24 +962,24 @@
 n.Mp3Utils;%0A
-
 import org.a
@@ -1600,29 +1600,66 @@
 %0A * 
-Class description her
+Service to convert and copy song files to an android devic
 e.%0A 
@@ -4156,44 +4156,96 @@
 th()
-.substring(System.getenv(%22MUSIC_HOME
+%0A                        .substring(AppConfiguration.getConfigurationProperty(%22music.dir
 %22).l
@@ -4919,19 +4919,21 @@
 t song %5B
-%22 +
+%7B%7D%5D%22,
  songFil
@@ -4955,14 +4955,8 @@
 th()
- + %22%5D%22
 );%0A 
@@ -5124,22 +5124,8 @@
 nfo(
-String.format(
 %22Out
@@ -5138,10 +5138,10 @@
 le: 
-%25s
+%7B%7D
 , re
@@ -5155,10 +5155,10 @@
 de: 
-%25d
+%7B%7D
 %22, o
@@ -5196,17 +5196,16 @@
 sCode())
-)
 ;%0A      
@@ -5492,16 +5492,40 @@
 rtFile =
+%0A                       
  new Fil
@@ -5543,16 +5543,48 @@
 RECTORY,
+%0A                               
  songFil
@@ -5617,33 +5617,60 @@
 ing(
-System.getenv(%22MUSIC_HOME
+AppConfiguration.getConfigurationProperty(%22music.dir
 %22).l
@@ -6227,16 +6227,40 @@
 IRECTORY
+%0A                       
  + file.
@@ -6291,33 +6291,60 @@
 ing(
-System.getenv(%22MUSIC_HOME
+AppConfiguration.getConfigurationProperty(%22music.dir
 %22).l

remove system environment music path.