/*
 * Twitch Android App
 * Copyright (c) 2012-2014 Twitch Interactive, Inc.
 */

package tv.twitch.api;

import android.content.Context;

import tv.twitch.volley.AuthFailureError;
import tv.twitch.volley.DefaultRetryPolicy;
import tv.twitch.volley.NetworkResponse;
import tv.twitch.volley.Request;
import tv.twitch.volley.RequestQueue;
import tv.twitch.volley.Response;
import tv.twitch.volley.toolbox.HttpHeaderParser;
import tv.twitch.volley.toolbox.StringRequest;
import tv.twitch.volley.toolbox.Volley;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import com.unity3d.player.*;

/**
 * Adapted by loohill on 05/02/18
 * Last sync: 05/03/18
 * Source: twitch-android/Twitch/src/main/java/tv/twitch/android/api/DownloadManager.java
 * Changes:
 *** Uses UnityPlayer.currentActivity.getApplication() as Context for SingletonHolder instead of TwitchApplication.get();
 */

public class DownloadManager {

    public static class SimpleRequest extends StringRequest {
        private Priority mPriority = Priority.NORMAL;
        private HashMap<String, String> mHeaders = new HashMap<>();

        public SimpleRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
            super(url, listener, errorListener);
            setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS, 3, 1));
        }

        public SimpleRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
            super(method, url, listener, errorListener);
            setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS, 3, 1));
        }

        public void addHeader(String name, String value) {
            mHeaders.put(name, value);
        }

        @Override
        public Priority getPriority(){
            return mPriority;
        }
        public void setPriority(Priority priority){
            this.mPriority = priority;
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            return mHeaders;
        }

        @Override
        protected Response<String> parseNetworkResponse(NetworkResponse response) {
            // assume utf-8
            String parsed;
            try {
                parsed = new String(response.data, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                parsed = new String(response.data);
            }
            return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
        }
    }

    private final RequestQueue mGlobalRequestQueue;
    private final WeakHashMap<String, RequestQueue> mScratchQueues = new WeakHashMap<>();
    private boolean mIsActive;

    private RequestQueue.RequestFilter mCancelFilter = new RequestQueue.RequestFilter() {
        @Override
        public boolean apply(Request<?> request) {
            return true;
        }
    };

    public static DownloadManager getInstance() {
        return SingletonHolder.Instance;
    }

    //NOTE: if using multi-dex, be wary of NoClassDefError: https://code.google.com/p/android/issues/detail?id=162774
    private static final class SingletonHolder {
        private static final DownloadManager Instance = new DownloadManager(UnityPlayer.currentActivity.getApplication());
    }

    private DownloadManager(Context context) {
        mGlobalRequestQueue = Volley.newRequestQueue(context);
        mGlobalRequestQueue.start();
        setActive(true);
    }

    public boolean isActive() {
        return mIsActive;
    }

    public void setActive(boolean active) {
        mIsActive = active;
    }

    /**
     * Requests that all requests are canceled in all queues.
     */
    public void shutdown() {
        cancelAllGlobalRequests();
        synchronized (mScratchQueues) {
            Set<String> identifiers = mScratchQueues.keySet();
            for (String s : identifiers) {
                cancelScratchRequests(s);
            }
        }
        mScratchQueues.clear();
    }

    public void scheduleGlobalRequest(Request request) {
        synchronized (mGlobalRequestQueue) {
            mGlobalRequestQueue.add(request);
        }
    }

    public void cancelAllGlobalRequests() {
        synchronized (mGlobalRequestQueue) {
            mGlobalRequestQueue.cancelAll(mCancelFilter);
        }
    }

    public void cancelScratchRequests(String identifier) {
        synchronized (mScratchQueues) {
            if (mScratchQueues.containsKey(identifier)) {
                RequestQueue queue = mScratchQueues.get(identifier);
                queue.cancelAll(mCancelFilter);
                queue.stop();
                mScratchQueues.remove(identifier);
            }
        }
    }
}
