<commit_before>package fr.bouyguestelecom.tv.bboxapi;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.ConditionVariable;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxApplication;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxDisplayToast;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetApplicationIcon;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetApplications;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetChannelListOnBox;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetChannels;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetCurrentChannel;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetEpgChannelNumber;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetOpenedChannels;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetSessionId;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetToken;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetVolume;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxMedia;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxMessage;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxRegisterApp;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxSendMessage;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxSetVolume;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxStartApplication;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxStopApplication;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxSubscribe;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxUnsubscribe;
import fr.bouyguestelecom.tv.bboxapi.model.Channel;
import fr.bouyguestelecom.tv.bboxapi.util.ListenerList;
import fr.bouyguestelecom.tv.bboxapi.util.Parser;
import fr.bouyguestelecom.tv.bboxapi.ws.WebSocket;

public class Bbox implements IBbox {
    public interface DiscoveryListener {
        public void bboxFound(Bbox bbox);
    }

    private static final String TAG = Bbox.class.getSimpleName();
    private static final String VERSION = "v1.3";

    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    private static final String URL_API_TOKEN = "https://api.bbox.fr/" + VERSION + "/security/token";
    private static final String URL_GET_CHANNELS = "https://api.bbox.fr/" + VERSION + "/media/channels";

    private static final String URL_API_BOX = "http://@IP:@PORT/api.bbox.lan/v0";
    private static final String URL_SESSION_ID = URL_API_BOX + "/security/sessionId";
    private static final String URL_GET_APPLICATIONS = URL_API_BOX + "/applications";
    private static final String LOCAL_URL_GET_CHANNELS = URL_API_BOX + "/media/tvchannellist";
    // private static final String LOCAL_URL_GET_TODAY_EPG = URL_API_BOX + "/media/programs";
    //  private static final String LOCAL_URL_GET_EPG_BY_ID = URL_API_BOX + "/media/program";
    private static final String URL_GET_CURRENT_CHANNEL = URL_API_BOX + "/media";
    private static final String URL_REGISTER_APP = URL_API_BOX + "/applications/register";
    private static final String URL_NOTIFICATION = URL_API_BOX + "/notification";

    private static final String URL_START_APP = URL_API_BOX + "/applications";

    private static final String URL_DISPLAY_TOAST = URL_API_BOX + "/userinterface/toast";
    private static final String URL_VOLUME = URL_API_BOX + "/userinterface/volume";

    private static Bbox instance;
    private static final ConditionVariable instanceLock = new ConditionVariable();

    private final String ip;
    private final int httpPort;
    private int wsPort;
    private final String appId;
    private final String appSecret;
    private OkHttpClient mClient;
    private WebSocket mWebSocket;
    private String mSessionId;
    private String mToken;
    private Long mValidityToken = (long) -1;
    private Long mValiditySessionId = (long) -1;
    private boolean hasSecurity = true;
    private ListenerList<IBboxMedia> notifMedia = new ListenerList<>();
    private ListenerList<IBboxApplication> notifApps = new ListenerList<>();
    private ListenerList<IBboxMessage> notifMsg = new ListenerList<>();

    private Bbox(String appId, String appSecret, String ip, int httpPort, int wsPort) {
        this.ip = ip;
        this.httpPort = httpPort;
        this.wsPort = wsPort;
        this.appId = appId;
        this.appSecret = appSecret;
        mClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(15, TimeUnit.SECONDS).readTimeout(15, TimeUnit.SECONDS)
                .connectionPool(new ConnectionPool(1, 5, TimeUnit.MINUTES))
                .build();
    }

    public static Bbox getInstance(boolean wait) {
        if (instance == null && wait) {
            if (!instanceLock.block(30000)) {
                Log.w(TAG, "Cannot find Bbox in 30 seconds", new TimeoutException("Cannot find Bbox in 30 seconds"));
            }
        }
        return instance;
    }

    public String getIp() {
        return ip;
    }

    public Call getToken(final IBboxGetToken iBboxGetToken) {
        if (mValidityToken == -1 || mValidityToken <= System.currentTimeMillis()) {
            RequestBody body = RequestBody.create(JSON, buildJsonRequestToken(appId, appSecret));
            Request request = new Request.Builder()
                    .url(URL_API_TOKEN)
                    .post(body)
                    .build();

            Call call = mClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e(TAG, "Get token failed", e);
                    iBboxGetToken.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response.code() == HttpURLConnection.HTTP_NO_CONTENT
                            && response.headers().get("x-token") != null
                            && !response.headers().get("x-token").isEmpty()) {
                        String tokenCloud = response.headers().get("x-token");
                        iBboxGetToken.onResponse(tokenCloud);
                        mValidityToken = System.currentTimeMillis() + 24 * 60 * 60 * 1000;
                        mToken = tokenCloud;
                    } else {
                        iBboxGetToken.onFailure(call.request(), response.code());
                        Log.e(TAG, "Get token failed: " + response.code());
                    }

                    response.body().close();
                }
            });

            return call;
        } else {
            iBboxGetToken.onResponse(mToken);
            return null;
        }
    }

    public void getSessionId(final IBboxGetSessionId iBboxGetSessionId) {
        if (hasSecurity) {
            getToken(new IBboxGetToken() {
                @Override
                public void onResponse(String token) {
                    Long currentTimeMillis = System.currentTimeMillis();

                    if (mValiditySessionId == -1 || mValiditySessionId <= currentTimeMillis) {
                        try {
                            RequestBody body = RequestBody.create(JSON, new JSONObject().put("token", token).toString());
                            Request request = new Request.Builder()
                                    .url(URL_SESSION_ID.replace("@IP", ip).replace("@PORT", Integer.toString(httpPort)))
                                    .post(body)
                                    .build();
                            //Log.d(TAG, "url =  : " + URL_SESSION_ID.replace("@IP", ip));
                            Call call = mClient.newCall(request);
                            call.enqueue(new Callback() {
                                @Override
                                public void onFailure(Call call, IOException e) {
                                    Log.e(TAG, "Get sessionId failed", e);
                                    iBboxGetSessionId.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                                }

                                @Override
                                public void onResponse(Call call, Response response) throws IOException {
                                    if (response.code() == HttpURLConnection.HTTP_NO_CONTENT
                                            && response.headers().get("x-sessionid") != null
                                            && !response.headers().get("x-sessionid").isEmpty()) {
                                        mSessionId = response.headers().get("x-sessionid");
                                        mValiditySessionId = System.currentTimeMillis() + 60 * 1000;
                                        iBboxGetSessionId.onResponse(mSessionId);
                                    } else {
                                        int responseCode = response.code();
                                        Log.w(TAG, "Cannot obtain bboxapi sessionId: " + responseCode);
                                        mSessionId = null;
                                        mValiditySessionId = (long) -1;
                                        iBboxGetSessionId.onFailure(call.request(), response.code());
                                    }

                                    response.body().close();
                                }
                            });
                        } catch (JSONException e) {
                            Log.e(TAG, "Cannot build getSessionId() request", e);
                            iBboxGetSessionId.onFailure(null, 500);
                        }
                    } else {
                        iBboxGetSessionId.onResponse(mSessionId);
                    }
                }

                @Override
                public void onFailure(Request request, int errorCode) {
                    mSessionId = null;
                    mValiditySessionId = (long) -1;
                    iBboxGetSessionId.onFailure(request, errorCode);
                }
            });
        } else {
            mSessionId = "855e4aa2f043550045c298e589220eca46769be82294f2bdda8345bffc160754";
            mValiditySessionId = System.currentTimeMillis() + 60 * 1000;
            iBboxGetSessionId.onResponse(mSessionId);
        }
    }

    @Override
    public void getLocalChannels(final IBboxGetChannels iBboxGetChannels) {
        getSessionId(new IBboxGetSessionId() {
            @Override
            public void onResponse(String sessionId) {
                final Request request = new Request.Builder()
                        .url(LOCAL_URL_GET_CHANNELS.replace("@IP", ip).replace("@PORT", Integer.toString(httpPort)))
                        .header("x-sessionid", sessionId)
                        .build();

                Call mCall = mClient.newCall(request);
                mCall.enqueue(new Callback() {
                    public void onFailure(Call call, IOException e) {
                        iBboxGetChannels.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                    }

                    public void onResponse(Call call, Response response) throws IOException {
                        Log.i(TAG, "Get channels success");
                        if (response.code() == HttpURLConnection.HTTP_OK) {
                            List<Channel> channels = Parser.parseJsonChannels(response);
                            String logoUrlPrefix = URL_API_BOX.replace("@IP", ip);
                            for (Channel channel : channels) {
                                channel.setLogo(logoUrlPrefix + "/media/" + channel.getPositionId() + "/image");
                            }
                            iBboxGetChannels.onResponse(channels);
                        } else {
                            iBboxGetChannels.onFailure(response.request(), response.code());
                        }

                        response.body().close();
                    }
                });
            }

            @Override
            public void onFailure(Request request, int errorCode) {
                iBboxGetChannels.onFailure(request, errorCode);
            }
        });
    }

    @Override
    public void getApps(final IBboxGetApplications iBboxGetApplications) {
        getSessionId(new IBboxGetSessionId() {
            public void onResponse(final String sessionId) {
                Request.Builder requestBuilder = new Request.Builder()
                        .url(URL_GET_APPLICATIONS.replace("@IP", ip).replace("@PORT", Integer.toString(httpPort)));
                if (sessionId != null) {
                    requestBuilder.header("x-sessionid", sessionId);
                }
                final Request request = requestBuilder.build();
                Call mCall = mClient.newCall(request);
                mCall.enqueue(new Callback() {
                    public void onFailure(Call call, IOException e) {
                        iBboxGetApplications.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                    }

                    public void onResponse(Call call, Response response) throws IOException {
                        if (response.code() == HttpURLConnection.HTTP_OK)
                            iBboxGetApplications.onResponse(Parser.parseJsonApplications(URL_API_BOX.replace("@IP", ip), response));

                        else
                            iBboxGetApplications.onFailure(call.request(), response.code());

                        response.body().close();
                    }
                });
            }

            public void onFailure(Request request, int errorCode) {
                iBboxGetApplications.onFailure(request, errorCode);
            }
        });
    }

    @Override
    public void getCurrentChannel(final IBboxGetCurrentChannel iBboxGetCurrentChannel) {
        getSessionId(new IBboxGetSessionId() {
            public void onResponse(final String sessionId) {
                final Request request = new Request.Builder()
                        .url(URL_GET_CURRENT_CHANNEL.replace("@IP", ip).replace("@PORT", Integer.toString(httpPort)))
                        .header("x-sessionid", sessionId)
                        .build();

                Call mCall = mClient.newCall(request);

                mCall.enqueue(new Callback() {
                    public void onFailure(Call call, IOException e) {
                        iBboxGetCurrentChannel.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                    }

                    public void onResponse(final Call call, final Response response) throws IOException {
                        if (response.code() == HttpURLConnection.HTTP_OK) {
                            final Channel bboxChannel = Parser.parseJsonChannel(response.body().byteStream());

                            getChannel(mToken, bboxChannel.getName(), "adsl", new IBboxGetEpgChannelNumber() {
                                @Override
                                public void onResponse(int epgChannelNumber) {
                                    bboxChannel.setEpgChannelNumber(epgChannelNumber);
                                    iBboxGetCurrentChannel.onResponse(bboxChannel);
                                }

                                @Override
                                public void onFailure(Request request, int errorCode) {
                                    iBboxGetCurrentChannel.onFailure(call.request(), response.code());
                                }
                            });
                        }
                        else
                            iBboxGetCurrentChannel.onFailure(call.request(), response.code());

                        response.body().close();
                    }
                });
            }

            public void onFailure(Request request, int errorCode) {
                iBboxGetCurrentChannel.onFailure(request, errorCode);
            }
        });
    }


    private void getChannel(final String token, String name, final String profil, final IBboxGetEpgChannelNumber iBboxGetEpgChannelNumber) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(URL_GET_CHANNELS).newBuilder();
        urlBuilder.addQueryParameter("profil", profil);<commit_msg>Fix amount as string instead of int<commit_after>package fr.bouyguestelecom.tv.bboxapi;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.ConditionVariable;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxApplication;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxDisplayToast;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetApplicationIcon;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetApplications;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetChannelListOnBox;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetChannels;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetCurrentChannel;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetEpgChannelNumber;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetOpenedChannels;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetSessionId;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetToken;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxGetVolume;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxMedia;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxMessage;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxRegisterApp;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxSendMessage;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxSetVolume;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxStartApplication;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxStopApplication;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxSubscribe;
import fr.bouyguestelecom.tv.bboxapi.callback.IBboxUnsubscribe;
import fr.bouyguestelecom.tv.bboxapi.model.Channel;
import fr.bouyguestelecom.tv.bboxapi.util.ListenerList;
import fr.bouyguestelecom.tv.bboxapi.util.Parser;
import fr.bouyguestelecom.tv.bboxapi.ws.WebSocket;

public class Bbox implements IBbox {
    public interface DiscoveryListener {
        public void bboxFound(Bbox bbox);
    }

    private static final String TAG = Bbox.class.getSimpleName();
    private static final String VERSION = "v1.3";

    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    private static final String URL_API_TOKEN = "https://api.bbox.fr/" + VERSION + "/security/token";
    private static final String URL_GET_CHANNELS = "https://api.bbox.fr/" + VERSION + "/media/channels";

    private static final String URL_API_BOX = "http://@IP:@PORT/api.bbox.lan/v0";
    private static final String URL_SESSION_ID = URL_API_BOX + "/security/sessionId";
    private static final String URL_GET_APPLICATIONS = URL_API_BOX + "/applications";
    private static final String LOCAL_URL_GET_CHANNELS = URL_API_BOX + "/media/tvchannellist";
    // private static final String LOCAL_URL_GET_TODAY_EPG = URL_API_BOX + "/media/programs";
    //  private static final String LOCAL_URL_GET_EPG_BY_ID = URL_API_BOX + "/media/program";
    private static final String URL_GET_CURRENT_CHANNEL = URL_API_BOX + "/media";
    private static final String URL_REGISTER_APP = URL_API_BOX + "/applications/register";
    private static final String URL_NOTIFICATION = URL_API_BOX + "/notification";

    private static final String URL_START_APP = URL_API_BOX + "/applications";

    private static final String URL_DISPLAY_TOAST = URL_API_BOX + "/userinterface/toast";
    private static final String URL_VOLUME = URL_API_BOX + "/userinterface/volume";

    private static Bbox instance;
    private static final ConditionVariable instanceLock = new ConditionVariable();

    private final String ip;
    private final int httpPort;
    private int wsPort;
    private final String appId;
    private final String appSecret;
    private OkHttpClient mClient;
    private WebSocket mWebSocket;
    private String mSessionId;
    private String mToken;
    private Long mValidityToken = (long) -1;
    private Long mValiditySessionId = (long) -1;
    private boolean hasSecurity = true;
    private ListenerList<IBboxMedia> notifMedia = new ListenerList<>();
    private ListenerList<IBboxApplication> notifApps = new ListenerList<>();
    private ListenerList<IBboxMessage> notifMsg = new ListenerList<>();

    private Bbox(String appId, String appSecret, String ip, int httpPort, int wsPort) {
        this.ip = ip;
        this.httpPort = httpPort;
        this.wsPort = wsPort;
        this.appId = appId;
        this.appSecret = appSecret;
        mClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(15, TimeUnit.SECONDS).readTimeout(15, TimeUnit.SECONDS)
                .connectionPool(new ConnectionPool(1, 5, TimeUnit.MINUTES))
                .build();
    }

    public static Bbox getInstance(boolean wait) {
        if (instance == null && wait) {
            if (!instanceLock.block(30000)) {
                Log.w(TAG, "Cannot find Bbox in 30 seconds", new TimeoutException("Cannot find Bbox in 30 seconds"));
            }
        }
        return instance;
    }

    public String getIp() {
        return ip;
    }

    public Call getToken(final IBboxGetToken iBboxGetToken) {
        if (mValidityToken == -1 || mValidityToken <= System.currentTimeMillis()) {
            RequestBody body = RequestBody.create(JSON, buildJsonRequestToken(appId, appSecret));
            Request request = new Request.Builder()
                    .url(URL_API_TOKEN)
                    .post(body)
                    .build();

            Call call = mClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e(TAG, "Get token failed", e);
                    iBboxGetToken.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response.code() == HttpURLConnection.HTTP_NO_CONTENT
                            && response.headers().get("x-token") != null
                            && !response.headers().get("x-token").isEmpty()) {
                        String tokenCloud = response.headers().get("x-token");
                        iBboxGetToken.onResponse(tokenCloud);
                        mValidityToken = System.currentTimeMillis() + 24 * 60 * 60 * 1000;
                        mToken = tokenCloud;
                    } else {
                        iBboxGetToken.onFailure(call.request(), response.code());
                        Log.e(TAG, "Get token failed: " + response.code());
                    }

                    response.body().close();
                }
            });

            return call;
        } else {
            iBboxGetToken.onResponse(mToken);
            return null;
        }
    }

    public void getSessionId(final IBboxGetSessionId iBboxGetSessionId) {
        if (hasSecurity) {
            getToken(new IBboxGetToken() {
                @Override
                public void onResponse(String token) {
                    Long currentTimeMillis = System.currentTimeMillis();

                    if (mValiditySessionId == -1 || mValiditySessionId <= currentTimeMillis) {
                        try {
                            RequestBody body = RequestBody.create(JSON, new JSONObject().put("token", token).toString());
                            Request request = new Request.Builder()
                                    .url(URL_SESSION_ID.replace("@IP", ip).replace("@PORT", Integer.toString(httpPort)))
                                    .post(body)
                                    .build();
                            //Log.d(TAG, "url =  : " + URL_SESSION_ID.replace("@IP", ip));
                            Call call = mClient.newCall(request);
                            call.enqueue(new Callback() {
                                @Override
                                public void onFailure(Call call, IOException e) {
                                    Log.e(TAG, "Get sessionId failed", e);
                                    iBboxGetSessionId.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                                }

                                @Override
                                public void onResponse(Call call, Response response) throws IOException {
                                    if (response.code() == HttpURLConnection.HTTP_NO_CONTENT
                                            && response.headers().get("x-sessionid") != null
                                            && !response.headers().get("x-sessionid").isEmpty()) {
                                        mSessionId = response.headers().get("x-sessionid");
                                        mValiditySessionId = System.currentTimeMillis() + 60 * 1000;
                                        iBboxGetSessionId.onResponse(mSessionId);
                                    } else {
                                        int responseCode = response.code();
                                        Log.w(TAG, "Cannot obtain bboxapi sessionId: " + responseCode);
                                        mSessionId = null;
                                        mValiditySessionId = (long) -1;
                                        iBboxGetSessionId.onFailure(call.request(), response.code());
                                    }

                                    response.body().close();
                                }
                            });
                        } catch (JSONException e) {
                            Log.e(TAG, "Cannot build getSessionId() request", e);
                            iBboxGetSessionId.onFailure(null, 500);
                        }
                    } else {
                        iBboxGetSessionId.onResponse(mSessionId);
                    }
                }

                @Override
                public void onFailure(Request request, int errorCode) {
                    mSessionId = null;
                    mValiditySessionId = (long) -1;
                    iBboxGetSessionId.onFailure(request, errorCode);
                }
            });
        } else {
            mSessionId = "855e4aa2f043550045c298e589220eca46769be82294f2bdda8345bffc160754";
            mValiditySessionId = System.currentTimeMillis() + 60 * 1000;
            iBboxGetSessionId.onResponse(mSessionId);
        }
    }

    @Override
    public void getLocalChannels(final IBboxGetChannels iBboxGetChannels) {
        getSessionId(new IBboxGetSessionId() {
            @Override
            public void onResponse(String sessionId) {
                final Request request = new Request.Builder()
                        .url(LOCAL_URL_GET_CHANNELS.replace("@IP", ip).replace("@PORT", Integer.toString(httpPort)))
                        .header("x-sessionid", sessionId)
                        .build();

                Call mCall = mClient.newCall(request);
                mCall.enqueue(new Callback() {
                    public void onFailure(Call call, IOException e) {
                        iBboxGetChannels.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                    }

                    public void onResponse(Call call, Response response) throws IOException {
                        Log.i(TAG, "Get channels success");
                        if (response.code() == HttpURLConnection.HTTP_OK) {
                            List<Channel> channels = Parser.parseJsonChannels(response);
                            String logoUrlPrefix = URL_API_BOX.replace("@IP", ip);
                            for (Channel channel : channels) {
                                channel.setLogo(logoUrlPrefix + "/media/" + channel.getPositionId() + "/image");
                            }
                            iBboxGetChannels.onResponse(channels);
                        } else {
                            iBboxGetChannels.onFailure(response.request(), response.code());
                        }

                        response.body().close();
                    }
                });
            }

            @Override
            public void onFailure(Request request, int errorCode) {
                iBboxGetChannels.onFailure(request, errorCode);
            }
        });
    }

    @Override
    public void getApps(final IBboxGetApplications iBboxGetApplications) {
        getSessionId(new IBboxGetSessionId() {
            public void onResponse(final String sessionId) {
                Request.Builder requestBuilder = new Request.Builder()
                        .url(URL_GET_APPLICATIONS.replace("@IP", ip).replace("@PORT", Integer.toString(httpPort)));
                if (sessionId != null) {
                    requestBuilder.header("x-sessionid", sessionId);
                }
                final Request request = requestBuilder.build();
                Call mCall = mClient.newCall(request);
                mCall.enqueue(new Callback() {
                    public void onFailure(Call call, IOException e) {
                        iBboxGetApplications.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                    }

                    public void onResponse(Call call, Response response) throws IOException {
                        if (response.code() == HttpURLConnection.HTTP_OK)
                            iBboxGetApplications.onResponse(Parser.parseJsonApplications(URL_API_BOX.replace("@IP", ip), response));

                        else
                            iBboxGetApplications.onFailure(call.request(), response.code());

                        response.body().close();
                    }
                });
            }

            public void onFailure(Request request, int errorCode) {
                iBboxGetApplications.onFailure(request, errorCode);
            }
        });
    }

    @Override
    public void getCurrentChannel(final IBboxGetCurrentChannel iBboxGetCurrentChannel) {
        getSessionId(new IBboxGetSessionId() {
            public void onResponse(final String sessionId) {
                final Request request = new Request.Builder()
                        .url(URL_GET_CURRENT_CHANNEL.replace("@IP", ip).replace("@PORT", Integer.toString(httpPort)))
                        .header("x-sessionid", sessionId)
                        .build();

                Call mCall = mClient.newCall(request);

                mCall.enqueue(new Callback() {
                    public void onFailure(Call call, IOException e) {
                        iBboxGetCurrentChannel.onFailure(call.request(), HttpURLConnection.HTTP_BAD_REQUEST);
                    }

                    public void onResponse(final Call call, final Response response) throws IOException {
                        if (response.code() == HttpURLConnection.HTTP_OK) {
                            final Channel bboxChannel = Parser.parseJsonChannel(response.body().byteStream());

                            getChannel(mToken, bboxChannel.getName(), "adsl", new IBboxGetEpgChannelNumber() {
                                @Override
                                public void onResponse(int epgChannelNumber) {
                                    bboxChannel.setEpgChannelNumber(epgChannelNumber);
                                    iBboxGetCurrentChannel.onResponse(bboxChannel);
                                }

                                @Override
                                public void onFailure(Request request, int errorCode) {
                                    iBboxGetCurrentChannel.onFailure(call.request(), response.code());
                                }
                            });
                        } else {
                            Log.e(TAG, "Cannot get current channel: " + response.body().string());
                            iBboxGetCurrentChannel.onFailure(call.request(), response.code());
                        }
                        response.body().close();
                    }
                });
            }

            public void onFailure(Request request, int errorCode) {
                iBboxGetCurrentChannel.onFailure(request, errorCode);
            }
        });
    }


    private void getChannel(final String token, String name, final String profil, final IBboxGetEpgChannelNumber iBboxGetEpgChannelNumber) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(URL_GET_CHANNELS).newBuilder();
        urlBuilder.addQueryParameter("profil", profil);
{'fraction_non_alphanumeric': 0.08974954965425068, 'fraction_numerical': 0.006101458539136498, 'mean_word_length': 1.8122395620557235, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 17, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 50, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1562892', 'n_tokens_mistral': 9129, 'n_tokens_neox': 8649, 'n_words': 1706}