package com.stardust.scriptdroid.script;

import android.os.Environment;

import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.util.FileSorter;
import com.stardust.util.LimitedHashMap;

import org.greenrobot.eventbus.EventBus;

import java.util.Map;

/**
 * Created by Stardust on 2017/3/31.
 */

public class StorageScriptProvider {


    public static class DirectoryChangeEvent {

        public ScriptFile directory;

        public DirectoryChangeEvent(ScriptFile directory) {
            this.directory = directory;
        }
    }

    public static final String DEFAULT_DIRECTORY_PATH = Environment.getExternalStorageDirectory() + App.getApp().getString(R.string.folder_name);
    public static final ScriptFile DEFAULT_DIRECTORY = new ScriptFile(DEFAULT_DIRECTORY_PATH);


    private static StorageScriptProvider defaultProvider = new StorageScriptProvider();

    public static StorageScriptProvider getDefault() {
        return defaultProvider;
    }

    private static StorageScriptProvider externalStorageProvider;

    public static StorageScriptProvider getExternalStorageProvider() {
        if (externalStorageProvider == null) {
            externalStorageProvider = new StorageScriptProvider(Environment.getExternalStorageDirectory().getPath(), 5);
        }
        return externalStorageProvider;
    }

    private EventBus mDirectoryEventBus = new EventBus();
    private LimitedHashMap<String, ScriptFile[]> mScriptFileCache;
    private ScriptFile mInitialDirectory;
    private ScriptFile[] mInitialDirectoryScriptFiles;

    public StorageScriptProvider(String path, int cacheSize) {
        this(new ScriptFile(path), cacheSize);
    }

    public StorageScriptProvider(ScriptFile initialDirectory, int cacheSize) {
        mInitialDirectory = initialDirectory;
        mScriptFileCache = new LimitedHashMap<>(cacheSize);
    }

    public StorageScriptProvider() {
        this(DEFAULT_DIRECTORY, 10);
    }

    public void notifyDirectoryChanged(ScriptFile directory) {
        if (directory.equals(mInitialDirectory)) {
            mInitialDirectoryScriptFiles = getInitialDirectoryScriptFilesInner();
        } else {
            clearCache(directory);
        }
        mDirectoryEventBus.post(new DirectoryChangeEvent(directory));
    }

    public void notifyStoragePermissionGranted() {
        mScriptFileCache.clear();
        mInitialDirectoryScriptFiles = null;
        mDirectoryEventBus.post(new DirectoryChangeEvent(mInitialDirectory));
    }

    @SuppressWarnings("unchecked")
    public void refreshAll() {
        Map<String, ScriptFile> files = (Map<String, ScriptFile>) mScriptFileCache.clone();
        mScriptFileCache.clear();
        mInitialDirectoryScriptFiles = null;
        mDirectoryEventBus.post(new DirectoryChangeEvent(mInitialDirectory));
        for (Map.Entry<String, ScriptFile> file : files.entrySet()) {
            mDirectoryEventBus.post(new DirectoryChangeEvent(new ScriptFile(file.getKey())));
        }
    }

    public ScriptFile getInitialDirectory() {
        return mInitialDirectory;
    }

    public ScriptFile[] getInitialDirectoryScriptFiles() {
        if (mInitialDirectoryScriptFiles == null) {
            mInitialDirectoryScriptFiles = getInitialDirectoryScriptFilesInner();
        }
        return mInitialDirectoryScriptFiles;
    }

    private ScriptFile[] getInitialDirectoryScriptFilesInner() {
        return listAndSortFiles(mInitialDirectory);
    }

    public ScriptFile[] getDirectoryScriptFiles(ScriptFile directory) {
        if (directory.equals(mInitialDirectory)) {
            return getInitialDirectoryScriptFiles();
        }
        ScriptFile[] scriptFiles = getScriptFilesFromCache(directory);
        if (scriptFiles == null) {
            scriptFiles = getScriptFiles(directory);
        }
        return scriptFiles;
    }

    public void clearCacheExceptInitialDirectory() {
        mScriptFileCache.clear();
    }

    private void clearCache(ScriptFile directory) {
        mScriptFileCache.remove(directory.getPath());
    }


    private ScriptFile[] getScriptFiles(ScriptFile directory) {
        ScriptFile[] scriptFiles = listAndSortFiles(directory);
        mScriptFileCache.put(directory.getPath(), scriptFiles);
        return scriptFiles;
    }

    private ScriptFile[] listAndSortFiles(ScriptFile directory) {
        ScriptFile[] scriptFiles = directory.listFiles();
        if (scriptFiles == null)
            scriptFiles = new ScriptFile[0];
        else
            FileSorter.sort(scriptFiles);
        return scriptFiles;
    }

    private ScriptFile[] getScriptFilesFromCache(ScriptFile directory) {
        return mScriptFileCache.get(directory.getPath());
    }


    public void registerDirectoryChangeListener(Object subscriber) {
        if (!mDirectoryEventBus.isRegistered(subscriber))
            mDirectoryEventBus.register(subscriber);
    }

    public void unregisterDirectoryChangeListener(Object subscriber) {
        mDirectoryEventBus.unregister(subscriber);
    }

}
