/**
 * $URL$
 * DAAND
 * Copyright (C) 2004 - 2013, INSIDE Secure BV.  All rights reserved.
 */
package com.insidesecure.drm.android.reference;

import java.io.*;
import java.net.*;
import java.util.*;

import android.content.*;
import android.util.Log;
import com.insidesecure.drm.android.reference.entitlements.SamplePlayReadyEntitlementDelegate;
import com.insidesecure.drmagent.*;
import com.insidesecure.drmagent.utils.Base64;
import org.json.JSONArray;

public class LicenseAcquisitionHelper
{
    public static final String TAG = LicenseAcquisitionHelper.class.getSimpleName();
    public static String LA_URL_TEMPLATE = "http://essdrmproducts-eu.insidesecure.com/test-portal/device/triggerGenerator.form?contentDistributorID=eval&rightsIssuerID=PR1&dotwopass=true&technologyType=MS-DRM-PLAYREADY&cid=%s&device=anonymous&acknowledgeLicenseInstall=%b";

    public static boolean canDoWebInitiator(final Context context, final DRMContentInfo drmContentInfo)
    {
        if (drmContentInfo.mWebInitiatorURL != null)
        {
            Log.d(TAG,"Found web initiator URL, we can do request");
            return true;
        }
        final String laURL = drmContentInfo.getDRMContent(context).getMetaData(DRMMetaData.RI_URL_SILENT);
        Log.d(TAG, "Validating URL: " + laURL);
        return isTTS(laURL);
    }

    private static boolean isTTS(final String laURL)
    {
        //note: laURL can be null as an example for wmrheader 4.1.0.0 for live tv
        //      laURL can start with http://playready-license/ for cff headerless-content
        final boolean b = laURL == null || laURL.startsWith("http://playready-license/") || laURL.startsWith("http://essdrmproducts-eu.insidesecure.com/test-portal/") ||
                laURL.startsWith("http://essdrmproducts-eu.insidesecure.com:80/test-portal/") ||
                laURL.startsWith("http://essdrmproducts.insidesecure.com/safenet-test-portal/") ||
                laURL.startsWith("http://essdrmproducts.insidesecure.com:80/safenet-test-portal/");
        Log.d(TAG, "Web Initiator: " + (b ? "supported" : "not supported"));
        return b;
    }

    public static boolean retrieveAndInstallWebInitiator(final Context context, final DRMContentInfo drmContentInfo,
                                                         final String webInitiatorUrl)
    {
        final DRMAgent drmAgentInstance = DRMAgentDelegate.getDRMAgentInstance(context);
        URL url;

        try
        {
            final SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.PREFERENCES_FILENAME, Context.MODE_PRIVATE);

            if (webInitiatorUrl != null)
            {
                Log.d(TAG, "Web initiator URL available: " + webInitiatorUrl);
                //web initiator url available
                url = new URL(webInitiatorUrl);
            }
            else
            {
                final String keyID = Tools.toGUID(Base64.decode(drmContentInfo.getDRMContent(context).getMetaData(DRMMetaData.CONTENT_ID)));

                if (!LicenseAcquisitionHelper.canDoWebInitiator(context, drmContentInfo))
                {
                    throw new RuntimeException("LA URL points to server other than http://essdrmproducts-eu.insidesecure.com/test-portal/... - this is currently not supported");
                }

                final boolean forceLicenseAcknowledgement = sharedPreferences.getBoolean(Constants.PREFERENCES_FORCE_ACKNOWLEDGEMENT_LICENSE_FOR_CONTENT, false);

                Log.d(TAG, "Retrieving web initiator");

                final String s = createRights(context);

                String rights = "&rights=" + Tools.toHex(s);

                url = new URL(String.format(LA_URL_TEMPLATE, keyID, forceLicenseAcknowledgement) + rights);
            }

            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            Log.d(TAG, "Making request for web initiator: " + url);

            try
            {
                urlConnection.connect();
                final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                InputStream inputStream = urlConnection.getInputStream();
                try
                {
                    Tools.copyStream(inputStream, outputStream);
                    Log.d(TAG, "Data received: " + new String(outputStream.toByteArray()));

                    InstallEntitlementRequest installEntitlementRequest = new InstallEntitlementRequest(InstallEntitlementRequest.InstallEntitlementRequestType.PR_INITIATOR, new ByteArrayInputStream(outputStream.toByteArray()));
                    installEntitlementRequest.setCustomData("InstallEntitlementRequest custom data");

                    final boolean useWebInitiatorLicenseAcquisitionHandler = sharedPreferences.getBoolean(Constants.PREFERENCES_USE_WEB_INITIATOR_LA_HANDLER, false);

                    if (useWebInitiatorLicenseAcquisitionHandler)
                    {
                        installEntitlementRequest.setEntitlementDelegate(new SamplePlayReadyEntitlementDelegate());
                    }
                    else
                    {
                        drmAgentInstance.setEntitlementDelegate(new SamplePlayReadyEntitlementDelegate());
                    }
                    drmAgentInstance.installEntitlement(installEntitlementRequest);

                    Log.d(TAG, "Web initiator successfully installed");

                    return true;
                }
                finally
                {
                    inputStream.close();
                }
            }
            finally
            {
                urlConnection.disconnect();
            }
        }
        catch (Exception e)
        {
            Log.e(TAG,"Error while loading web initiator: " + e.getMessage(),e);
            return false;
        }
    }

    private static String createRights(final Context context)
    {
        final SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.PREFERENCES_FILENAME, Context.MODE_PRIVATE);
        final boolean forceTimeBasedLicense = sharedPreferences.getBoolean(Constants.PREFERENCES_FORCE_TIMEBASED_LICENSE_FOR_CONTENT, false);
        final boolean forceOPLBasedLicense = sharedPreferences.getBoolean(Constants.PREFERENCES_FORCE_OPL_LICENSE_FOR_CONTENT, false);
        final boolean forceIntervalLicense = sharedPreferences.getBoolean(Constants.PREFERENCES_FORCE_INTERVAL_LICENSE_FOR_CONTENT, false);
        int intervalSeconds = sharedPreferences.getInt(Constants.PREFERENCES_INTERVAL_LICENSE_NUM_SECONDS, 30);

        int numMinutes = sharedPreferences.getInt(Constants.PREFERENCES_TIMEBASED_LICENSE_NUM_MINUTES, 5);
        int oplLevel = sharedPreferences.getInt(Constants.PREFERENCES_OPL_LICENSE_LEVEL, 100);

        final boolean forceLicenseAcknowledgement = sharedPreferences.getBoolean(Constants.PREFERENCES_FORCE_ACKNOWLEDGEMENT_LICENSE_FOR_CONTENT, false);

        String playEnablers = "";

        Calendar timeBasedDate;

        try
        {
            JSONArray storedData = new JSONArray(sharedPreferences.getString(Constants.PREFERENCES_PLAY_ENABLERS, "[]"));

            for (int i = 0; i < storedData.length(); i ++)
            {
                playEnablers = storedData.getString(i) + (playEnablers.length() == 0 ? "" : ",") + playEnablers;
            }
        }

        catch (Exception exception)
        {
            exception.printStackTrace();
            Log.e(TAG, "Unexpected error " + exception.toString());
        }

        Log.d(TAG, "Force time-based license: " + (forceTimeBasedLicense ? "Yes" : "No"));
        Log.d(TAG, "Number of Minutes: " + numMinutes);
        Log.d(TAG, "Force OPL license: " + (forceOPLBasedLicense ? "Yes" : "No"));
        Log.d(TAG, "OPL Level: " + oplLevel);
        Log.d(TAG, "Force Interval license: " + (forceIntervalLicense ? "Yes" : "No"));
        Log.d(TAG, "Number of Second: " + intervalSeconds);
        Log.d(TAG, "Play enablers: " + playEnablers);
        Log.d(TAG, "Force Acknowledgement: " + (forceLicenseAcknowledgement ? "Yes" : "No"));

        String rawRights = "PlayRight=1";

        if (forceLicenseAcknowledgement)
        {
            rawRights += "&acknowledgeLicenseInstall=true";
        }

        if (forceTimeBasedLicense)
        {
            try
            {
                timeBasedDate = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

                timeBasedDate.add(Calendar.getInstance(TimeZone.getTimeZone("UTC")).MINUTE, -(Math.max(1,numMinutes)));
                rawRights += "&BeginDate=" + String.format(Constants.CONFIGURATION_MMDDYYHHMMSS_DATE_FORMAT, timeBasedDate).replaceAll(" ", URLEncoder.encode(" ", "UTF-8"));

                // Multiply by two to make sure we are really adding to the date
                timeBasedDate.add(Calendar.getInstance(TimeZone.getTimeZone("UTC")).MINUTE, Math.max(1, numMinutes*2));
                rawRights += "&Expiration=" + String.format(Constants.CONFIGURATION_MMDDYYHHMMSS_DATE_FORMAT, timeBasedDate).replaceAll(" ", URLEncoder.encode(" ", "UTF-8"));
            }

            catch (Exception exception)
            {
                exception.printStackTrace();
                Log.e(TAG, "Unexpected error " + exception.toString());
            }

        }

        if (forceIntervalLicense)
        {
            rawRights += "&FirstPlayExpiration=" + intervalSeconds;
        }

        if (forceOPLBasedLicense)
        {
            rawRights += "&UncompressedDigitalVideoOPL=" + oplLevel;
        }

        if (playEnablers.length() != 0)
        {
            rawRights += "&PlayEnablers=" + playEnablers;
        }

        return rawRights;
    }

    public static String performURLRewrite(final Context context, final String laURL)
    {
        final SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.PREFERENCES_FILENAME, Context.MODE_PRIVATE);
        final boolean useUrlFromHeader = sharedPreferences.getBoolean(Constants.PREFERENCES_USE_URL_FROM_HEADER, false);
        Log.d(TAG, "License Acquisition URL from header: " + laURL);
        if (!useUrlFromHeader && isTTS(laURL) )
        {
            Log.d(TAG, "Detected the TTS license server, will reconstruct the LA_URL accordingly");
            try
            {
                final String newLaURL = "http://essdrmproducts-eu.insidesecure.com/test-portal/device/portal?" + createRights(context);
                Log.d(TAG, "New URL: " + newLaURL);
                return newLaURL;
            }
            catch (Exception e)
            {
                Log.e(TAG, "Error while constructing URL based on: " + laURL);
                throw new RuntimeException("Error while constructing URL from: " + laURL);
            }
        }
        Log.d(TAG, "Returning unmodified LA URL (from header or mLaURLOverride): " + laURL);
        return laURL;
    }

}
