package com.viaccessorca.voplayerdemo.mediamgt;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

import com.viaccessorca.exceptions.VOException;
import com.viaccessorca.voplayer.VOPlayer;
import com.viaccessorca.voplayerdemo.AppConfig;
import com.viaccessorca.voplayerdemo.Constants;
import com.viaccessorca.voplayerdemo.Utils;
import com.viaccessorca.voplayerdemo.database.DatabaseInfo;
import com.viaccessorca.voplayerdemo.database.MediaMetaInfoDB;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class LocalMediasFinder implements MediaFinderInterface {

    private static final String TAG = "LocalMediasFinder";

    private static final String[] SUBTITLE_EXTENSIONS = {"srt", "smi", "vtt", "ttml"};

    private static final String[] LOCAL_FILE_EXTENSIONS = {"wmv", "asf", "mp4"};

    public static final String[] consideredDirectories = {
        Environment.getExternalStorageDirectory().getAbsolutePath() + "/qp3_medias",
        Environment.getExternalStorageDirectory().getAbsolutePath() + "/vop_medias" };

    private String certFilePathSdcardStorage = null;

    protected List<MediaItem> mediaItems;

    protected Context context;

    protected static LocalMediasFinder instance;

    protected LocalMediasFinder(Context context) {
        this.context = context;
        mediaItems = new ArrayList<MediaItem>();
    }

    public static LocalMediasFinder getInstance(Context ctx) {
        if(null == instance) {
            instance = new LocalMediasFinder(ctx);
        }
        return instance;
    }

    /**
     * Retrieves the list of files to display in the browser
     * @return  the status of the retrieving (OK, SDcard error, no file found)
     */
    private int fillMediaList() {

        mediaItems.clear();

        addEmbeddedMediaItems();

        Log.d(TAG, "retrieveFilesListAndInfos - storage state:" + Environment.getExternalStorageState());

        // browse all the considered directories for files
        for(String directory : consideredDirectories) {

            //Log.d(TAG, "retrieveFilesListAndInfos - browse directory: " + directory);
            File dir = new File(directory);
            if(!dir.exists()) {
                continue;
            }

            File[] files = dir.listFiles();
            // if the selected folder is empty, switch to next one
            if(null == files) {
                continue;
            }
            processFilesList(files, false);
        }
        filterMediaByDRMSupport();

        int totalMedias = mediaItems.size();
        if(0 == totalMedias) {
            return -1;
        }
        else {
            return 0;
        }
    }

    // goes through the list of all medias and remove the one that are not supported by the VO Player SDK embedded in the app
    private void filterMediaByDRMSupport() {
        boolean vmxSDK   = false;
        boolean plrSDK   = false;
        boolean voDrmSDK = false;
        try {
            String sdkVersion = VOPlayer.getSdkVersion(context);
            vmxSDK   = sdkVersion.contains("_VMX")|| sdkVersion.contains("_vmx");
            plrSDK   = sdkVersion.contains("_PR_") || sdkVersion.contains("_WVPR_") || sdkVersion.contains("_PRWV_") || sdkVersion.contains("_plr_");
            voDrmSDK = sdkVersion.contains("VODRM");
        } catch (VOException e){ }
        int nbItems = mediaItems.size();
        for(int i=nbItems-1; i>=0; i--) {
            MediaItem item = mediaItems.get(i);
            if(item instanceof  StreamingMediaItem) {
                StreamingMediaItem sItem = (StreamingMediaItem) item;
                if(null != sItem.getBootAddress() && !vmxSDK) {
                    mediaItems.remove(i);
                    continue;
                }
                else if(Constants.DRM_AGENT_TYPE_PLAYREADY.equals(sItem.getDrmAgentType()) && !plrSDK ) {
                    mediaItems.remove(i);
                    continue;
                }
                else if(Constants.DRM_AGENT_TYPE_VODRM.equals(sItem.getDrmAgentType()) && !voDrmSDK ) {
                    mediaItems.remove(i);
                    continue;
                }
            }
        }
    }

    private void processFilesList(File files[], boolean includeSubFolders) {

        if(0 == files.length) {
            return;
        }

        MediaMetaInfoDB database = MediaMetaInfoDB.getInstance(context);

        for(File file : files)
        {
            if(file.isDirectory()) {
                if(includeSubFolders) {
                    File subList[] = file.listFiles();
                    if(null != subList) {
                        processFilesList(subList, includeSubFolders);
                    }
                }
                continue;
            }

            String lowCaseExtension;
            try {
                lowCaseExtension = Utils.getFileLowerCaseExtension(file.getAbsolutePath());
            } catch (Exception e) {
                continue;
            }

            //Log.d(TAG, "lowcase extension: " + lowCaseExtension);
            // if the file is an http streaming description file and we uses them
            if(lowCaseExtension.equals("qp35")) {

                try {
                    StreamingMediaItem mediaItem = readHLSMediaItemFromQP35File(file);
                    DatabaseInfo dbInfo = database.getAssociatedDataForMedia(mediaItem.getMediaId());
                    mediaItem.setAssociatedDBInfo(dbInfo);
                    addMediaInList(mediaItem);
                    //Log.d(TAG, "added");
                } catch (Exception e) {
                    e.printStackTrace();
                }
                continue;
            }

            // Get stream specific parameters from .op files
            if(lowCaseExtension.equals("vop") || lowCaseExtension.equals("op")) {
                try {
                    MediaItem mediaItem = readHLSMediaItemFromOPFile(file);
                    if(null == mediaItem) {
                        Log.w(TAG, "Invalid .vop/.op file: " + file.getAbsolutePath());
                        continue;
                    }
                    if (MediaItem.MediaType.MEDIA_PLAYLIST == mediaItem.getMediaType()) {
                        DatabaseInfo dbInfo = database.getAssociatedDataForMedia(mediaItem.getMediaId());
                        mediaItem.setAssociatedDBInfo(dbInfo);
                        addMediaInList(mediaItem);
                    }
                    else {
                        DatabaseInfo dbInfo = database.getAssociatedDataForMedia(mediaItem.getMediaId());
                        mediaItem.setAssociatedDBInfo(dbInfo);
                        addMediaInList(mediaItem);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                continue;
            }

            // Get the path of certificates between "qp3_medias" directories
            if(lowCaseExtension.equals("pem") && null == certFilePathSdcardStorage) {
                String absolutePath = file.getAbsolutePath();
                certFilePathSdcardStorage = absolutePath.substring(0,absolutePath.lastIndexOf(File.separator));
                continue;
            }

            boolean subtitleExtenstion = isExtentionSubtitle(lowCaseExtension);
            if(subtitleExtenstion) {
                SubtitleMediaItem subtitleItem = new SubtitleMediaItem(Utils.getMD5Hash(file.getName()), file.getAbsolutePath(), file.getName());
                addMediaInList(subtitleItem);
                continue;
            }

            boolean localFile = Utils.isStringInList(lowCaseExtension, LOCAL_FILE_EXTENSIONS);
            if(localFile) {
                LocalFileMediaItem locaItem = new LocalFileMediaItem(Utils.getMD5Hash(file.getName()), file.getAbsolutePath(), file.getName());
                DatabaseInfo dbInfo = database.getAssociatedDataForMedia(locaItem.getMediaId());
                locaItem.setAssociatedDBInfo(dbInfo);
                addMediaInList(locaItem);
                continue;
            }
        }
    }

    private void addMediaInList(MediaItem mediaItem) {
        mediaItems.add(mediaItem);
    }

    private boolean isExtentionSubtitle(String extension) {
        for(String testExt : SUBTITLE_EXTENSIONS) {
            if(extension.equals(testExt)) {
                return true;
            }
        }
        return false;
    }


    private void addEmbeddedMediaItems() {
        AppConfig appConfig = AppConfig.getInstance(context);
        mediaItems.addAll(appConfig.getEmbeddedStreams());
    }

    private MediaItem readHLSMediaItemFromOPFile(File descriptionFile)  throws Exception {

        Log.v(TAG, "readHLSMediaItemFromOPFile " + descriptionFile.getName());
        String mediaId = descriptionFile.getName().substring(0, descriptionFile.getName().lastIndexOf('.'));
        return MediaDescriptionParser.readMediaItemFromXMLDesc(mediaId, new FileInputStream(descriptionFile), certFilePathSdcardStorage);
    }

    private StreamingMediaItem readHLSMediaItemFromQP35File(File descriptionFile) throws IOException {

        FileReader fileReader = new FileReader(descriptionFile);
        BufferedReader buffer = new BufferedReader(fileReader);

        String strUrl = buffer.readLine();

        buffer.close();
        fileReader.close();

        if(null != strUrl) {
            strUrl = strUrl.trim();
            String displayName = descriptionFile.getName().substring(0, descriptionFile.getName().lastIndexOf('.'));

            StreamingMediaItem mediaItem = new StreamingMediaItem(Utils.getMD5Hash(displayName), strUrl, displayName, false);
            mediaItem.setDescriptionFilePath(descriptionFile.getAbsolutePath());

            return mediaItem;
        }
        else {
            Log.w(TAG, "readHLSMediaItemFromQP35File Error when reading file " + descriptionFile.getAbsolutePath());
            throw new UnknownError();
        }
    }

    @Override
    public Collection<MediaItem> getMedias() {
        return this.mediaItems;
    }

    @Override
    public void refresh() {
        fillMediaList();
    }
}
