/*
 *
 *     Copyright (C) 2015 Ingo Fuchs
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License along
 *     with this program; if not, write to the Free Software Foundation, Inc.,
 *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * /
 */

package freed.settings;

import android.text.TextUtils;

import androidx.collection.LongSparseArray;

import com.troop.freedcam.BuildConfig;
import com.troop.freedcam.R;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import freed.FreedApplication;
import freed.dng.CustomMatrix;
import freed.dng.DngProfile;
import freed.dng.ToneMapProfile;
import freed.jni.OpCode;
import freed.utils.Log;
import freed.utils.VideoMediaProfile;

/**
 * Created by troop on 19.08.2014.
 */
public class SettingsManager extends SettingKeys implements SettingsManagerInterface {

    public static final int JPEG= 0;
    public static final int RAW = 1;
    public static final int DNG = 2;

    public static final int SHUTTER_HTC =0;
    public static final int SHUTTER_LG = 1;
    public static final int SHUTTER_MTK = 2;
    public static final int SHUTTER_QCOM_MILLISEC = 3;
    public static final int SHUTTER_QCOM_MICORSEC = 4;
    public static final int SHUTTER_MEIZU = 5;
    public static final int SHUTTER_KRILLIN = 6;
    public static final int SHUTTER_SONY = 7;
    public static final int SHUTTER_G2PRO = 8;
    public static final int SHUTTER_ZTE = 9;

    public static final int NIGHTMODE_XIAOMI = 0;
    public static final int NIGHTMODE_ZTE = 1;

    public static final int HDR_MORPHO = 0;
    public static final int HDR_AUTO = 1;
    public static final int HDR_LG = 2;
    public static final int HDR_MOTO = 3;

    public static final int ISOMANUAL_QCOM = 0;
    public static final int ISOMANUAL_SONY =1;
    public static final int ISOMANUAL_MTK =2;
    public static final int ISOMANUAL_KRILLIN =3;
    public static final int ISOMANUAL_LG =4;
    public static final int ISOMANUAL_Xiaomi =5;

    public static final String TIMELAPSEFRAME = "timelapseframe";
    public static final String API_1 = "camera1";
    public static final String API_2 = "camera2";

    public List<OpCodeUrl> opcodeUrlList;

    private final String TAG = SettingsManager.class.getSimpleName();

    private HashMap<String, CustomMatrix> matrixes;
    private HashMap<String, ToneMapProfile> tonemapProfiles;
    private HashMap<String, VideoToneCurveProfile> videoToneCurveProfiles;
    private LongSparseArray<DngProfile> dngProfileHashMap;
    private OpCode opCode;
    private static volatile boolean isInit =false;
    private SettingsStorage settingsStorage;

    //private static SettingsManager settingsManager = new SettingsManager();



    public SettingsManager()
    {

    }

    /*public static SettingsManager getInstance()
    {
        return settingsManager;
    }*/

    public void save()
    {
        if (settingsStorage != null)
            settingsStorage.save();
        new VideoToneCurveXmlParserWriter().saveToneCurveProfiles(videoToneCurveProfiles, getAppDataFolder());
    }

    public <T> T get(Key<T> key)
    {
        if (key instanceof GlobalKey)
            return getGlobal(key);
        else if (key instanceof ApiKey)
            return getApi(key);
        return key.getType().cast(settingsStorage.get(key));
    }

    public <T> T getGlobal(Key<T> key)
    {
        return key.getType().cast(settingsStorage.getGlobal(key));
    }

    public <T> T getApi(Key<T> key)
    {
        return key.getType().cast(settingsStorage.getApiSetting(key));
    }

    public void init()
    {
        //check if its not already init while a other task waited for it
        if (isInit)
            return;
        isInit = true;
        File ext = FreedApplication.getContext().getExternalFilesDir(null);
        if (ext != null && ext.exists())
            settingsStorage = new SettingsStorage(ext);
        else
            settingsStorage = new SettingsStorage(FreedApplication.getContext().getFilesDir());

        Log.d(TAG, "load Settings");
        settingsStorage.load();
        videoToneCurveProfiles = new VideoToneCurveXmlParserWriter().getToneCurveProfiles(getAppDataFolder());
        //loadOpCodes();
        parseXml();
    }

    public void release()
    {
        //settingsmap.clear();
        isInit = false;
        settingsStorage.reset();
    }

    public boolean isInit()
    {
        return isInit;
    }

    public File getAppDataFolder()
    {
        return  settingsStorage.appdataFolder;
    }

    private void parseXml() {
        XmlParserWriter parser = new XmlParserWriter();
        //first time init
        matrixes = parser.getMatrixes(FreedApplication.getContext().getResources(),settingsStorage.appdataFolder);

        tonemapProfiles = parser.getToneMapProfiles(settingsStorage.appdataFolder);
        videoToneCurveProfiles = new VideoToneCurveXmlParserWriter().getToneCurveProfiles(settingsStorage.appdataFolder);
        if (settingsStorage.getDevice() == null || TextUtils.isEmpty(settingsStorage.getDevice()))
        {
            Log.d(TAG, "Lookup PreDefinedConfigFile");
            parser.parseAndFindSupportedDevice(FreedApplication.getContext().getResources(),matrixes,settingsStorage.appdataFolder);
            Log.d(TAG, "Lookup PreDefinedConfigFile done");
        }
        dngProfileHashMap = parser.getDngProfiles(matrixes,settingsStorage.appdataFolder);
        opcodeUrlList = new ArrayList<>();
        loadOpCodes();
    }

    private void loadOpCodes()
    {
        new Thread(() -> {
            try {
                File op2 = new File(settingsStorage.appdataFolder.getAbsolutePath()+"/"+settingsStorage.getActiveCamera()+"opc2.bin");
                File op3 = new File(settingsStorage.appdataFolder.getAbsolutePath()+"/"+settingsStorage.getActiveCamera()+"opc3.bin");
                if (op2.exists() || op3.exists())
                    opCode = new OpCode(op2,op3);
                else
                    opCode = null;
            }
            catch (NullPointerException ex)
            {
                Log.WriteEx(ex);
            }



        }).start();
    }

    public synchronized void RESET()
    {
        settingsStorage.reset();
        //settings.edit().clear().commit();
        parseXml();
        settingsStorage.save();
    }

    public boolean appVersionHasChanged()
    {
        return BuildConfig.VERSION_CODE != getAppVersion();
    }

    public LongSparseArray<DngProfile> getDngProfilesMap()
    {
        return dngProfileHashMap;
    }

    public HashMap<String, CustomMatrix> getMatrixesMap()
    {
        return matrixes;
    }

    public HashMap<String, ToneMapProfile> getToneMapProfiles()
    {
        return tonemapProfiles;
    }

    public HashMap<String, VideoToneCurveProfile> getVideoToneCurveProfiles()
    {
        return videoToneCurveProfiles;
    }

    public void saveVideoToneCurveProfile(VideoToneCurveProfile videoToneCurveProfile)
    {
        videoToneCurveProfiles.put(videoToneCurveProfile.name, videoToneCurveProfile);
    }


    public boolean isZteAe()
    {
        return settingsStorage.isZteAE();
    }

    public void setZteAe(boolean legacy)
    {
        settingsStorage.setIsZteAE(legacy);
    }


    public void setsOverrideDngProfile(boolean legacy)
    {
        settingsStorage.setOverrideDngProfile(legacy);
    }

    public boolean getOverrideDngProfile()
    {
        return settingsStorage.overrideDngProfile();
    }

    public int getAppVersion()
    {
        return settingsStorage.getAppVersion();
    }

    public void setAppVersion(int version)
    {
        settingsStorage.setAppVersion(version);
    }

    public void setCamApi(String api) {
        settingsStorage.setApi(api);
    }

    public String getCamApi() {
        return settingsStorage.getApi();
    }

    public long getCamera2MaxExposureTime()
    {
        return settingsStorage.getCameraMaxExposureTime();
    }

    public void setCamera2MaxExposureTime(long max)
    {
        settingsStorage.setCameraMaxExposureTime(max);
    }

    public void setCamera2MinExposureTime(long min)
    {
        settingsStorage.setCameraMinExposureTime(min);
    }
    public long getCamera2MinExposureTime()
    {
        return settingsStorage.getCameraMinExposureTime();
    }

    public int getCamera2MaxIso()
    {
        return settingsStorage.getCameraMaxIso();
    }

    public void setCamera2MaxIso(int max)
    {
        settingsStorage.setCameraMaxIso(max);
    }

    public void setCamera2MinFocusPosition(float pos)
    {
        settingsStorage.setCameraMinFocus(pos);
    }

    public float getCamera2MinFocusPosition()
    {
        return settingsStorage.getCameraMinFocus();
    }

    public void setDevice(String device) {
        settingsStorage.setDevice(device);
    }

    public String getDeviceString() {
        return settingsStorage.getDevice();
    }

    public void setshowHelpOverlay(boolean value) {
        settingsStorage.setShowHelpOverlayOnStart(value);
    }

    public boolean getShowHelpOverlay() {
        return settingsStorage.showHelpOverlayOnStart();
    }

    public void SetBaseFolder(String uri) {
        settingsStorage.setExtSDFolderUri(uri);
    }

    public String GetBaseFolder() {
        return settingsStorage.getExtSDFolderUri();
    }

    public void SetCurrentCamera(int currentcamera) {
        settingsStorage.setActiveCamera(currentcamera);
        loadOpCodes();
    }

    public int GetCurrentCamera() {
        return settingsStorage.getActiveCamera();
    }

    public void setCameraIds(int[] cameras)
    {
        Log.d(TAG, "set camera ids");
        settingsStorage.setActiveCameraIds(cameras);
    }

    public int[] getCameraIds()
    {
        return settingsStorage.getActiveCameraIds();
    }

    public void SetCurrentModule(String modulename) {
        get(SettingKeys.MODULE).set(modulename);
    }

    public String GetCurrentModule()
    {
        if (TextUtils.isEmpty(get(SettingKeys.MODULE).get()))
            return FreedApplication.getStringFromRessources(R.string.module_picture);
        return get(SettingKeys.MODULE).get();
    }


    public boolean GetWriteExternal() {
        return settingsStorage.writeToExternalSD();
    }

    public void SetWriteExternal(boolean write) {
        settingsStorage.setWriteToExternalSD(write);
    }

    public void setHasCamera2Features(boolean value) {
        settingsStorage.setHasCamera2Features(value);
    }

    public boolean hasCamera2Features() {
        return settingsStorage.hasCamera2Features();
    }

    public HashMap<String,VideoMediaProfile> getMediaProfiles()
    {
        return settingsStorage.getApiVideoMediaProfiles();
    }

    public void saveMediaProfiles(HashMap<String,VideoMediaProfile> mediaProfileHashMap)
    {
        settingsStorage.setApiVideoMediaProfiles(mediaProfileHashMap);
    }

    public void setFramework(Frameworks frameWork)
    {
        settingsStorage.setFramework(frameWork);
    }

    public Frameworks getFrameWork()
    {
        return settingsStorage.getFramework();
    }

    public void setIsFrontCamera(boolean isFront)
    {
        settingsStorage.setIsFrontCamera(isFront);
    }

    public boolean getIsFrontCamera()
    {
        return settingsStorage.isFrontCamera();
    }

    public void setAreFeaturesDetected(boolean isFront)
    {
        settingsStorage.setFeaturesAreDetected(isFront);
    }

    public boolean getAreFeaturesDetected()
    {
        return settingsStorage.areFeaturesDetected();
    }

    public boolean getCamIsFrontCamera(int id)
    {
        return settingsStorage.isFrontCamera(id);
    }

    public OpCode getOpCode() {
        return opCode;
    }

    ///XML STUFF



}
