package com.insidesecure.drm.android.reference.activities;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.*;
import com.insidesecure.drm.android.reference.*;
import com.insidesecure.drm.android.reference.xoplayer.R;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Map;
import java.util.concurrent.Exchanger;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.xml.XMLConstants;

import com.insidesecure.drmagent.*;
import org.xmlpull.v1.*;

/**
 * Simple activity to ask the user to input a
 *
 * @author INSIDE Secure
 */
public class AddURLActivity extends Activity
{
    private static final String TAG = "AddURLActivity";

    private static final String SHARED_PREFERENCES_FOR_ADD_CONTENT = "SHARED_PREFERENCES_FOR_ADD_CONTENT";

    private static final String LABEL_SMOOTH_STREAMING_FORMAT = "Smooth Streaming";
    private static final String LABEL_HLS_FORMAT = "HLS";
    private static final String LABEL_PIFF_FORMAT = "PIFF";
    private static final String LABEL_MPEG_DASH_FORMAT = "MPEG-DASH";
    private static final String LABEL_CFF_FORMAT = "CFF";

    private static final String XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";

    private static final String XML_TAG_DESCRIPTOR = "Descriptor";

    private static final String XML_NAMESPACE_XSD_PREFIX = "xmlns:xsd";
    private static final String XML_NAMESPACE_XSI_PREFIX = "xmlns:xsi";

    private static final String XML_TEXT_TITLE = "$title";
    private static final String XML_TEXT_URL = "$url";
    private static final String XML_TEXT_PROTECTION = "$protection";
    private static final String XML_TEXT_STREAM_TYPE = "$stream_type";
    private static final String XML_TEXT_SHORT_DESCRIPTION = "$short_description";
    private static final String XML_TEXT_LONG_DESCRIPTION = "$long_description";


    private AutoCompleteTextView textView;
    private SharedPreferences mPreferences;
    private SharedPreferences.Editor mEditor;
    private int mMaxUrlToStore = 10;
    private String mKeyPrefix = "";
    private RadioButton radioButton;
    private boolean isNativeMediaPlayerUsed;
    private Spinner spinner;
    private EditText editText;
    private Dialog dialog;
    private String contentDescriptorTemplate;

    private void setSpinnerSelection(String selectionLabel)
    {
        ArrayAdapter arrayAdapter;

        arrayAdapter = (ArrayAdapter) spinner.getAdapter();

        for (int i = 0; i < arrayAdapter.getCount(); i++)
        {
            if (((String) arrayAdapter.getItem(i)).compareTo(selectionLabel) == 0)
            {
                spinner.setSelection(i);
                break;
            }
        }
    }

    private boolean setDrmContentFormat()
    {
        String contentDescriptorUrl;

        contentDescriptorUrl = textView.getText().toString();

        if (contentDescriptorUrl.endsWith(".ism") ||
                contentDescriptorUrl.endsWith(".isml"))
        {
            //Set format to Smooth Streaming
            setSpinnerSelection(LABEL_SMOOTH_STREAMING_FORMAT);
            return true;
        }

        if (contentDescriptorUrl.endsWith(".m3u8"))
        {
            //Set format to HLS
            setSpinnerSelection(LABEL_HLS_FORMAT);
            return true;
        }

        if (contentDescriptorUrl.endsWith(".ismv"))
        {
            //Set format to PIFF
            setSpinnerSelection(LABEL_PIFF_FORMAT);
            return true;
        }

        if (contentDescriptorUrl.endsWith(".mpd") &&
                isNativeMediaPlayerUsed)
        {
            //Set format to MPEG-DASH
            setSpinnerSelection(LABEL_MPEG_DASH_FORMAT);
            return true;
        }

        if (contentDescriptorUrl.endsWith(".uvu"))
        {
            //Set format to CFF
            setSpinnerSelection(LABEL_CFF_FORMAT);
            return true;
        }

        return false;
    }

    private boolean isUrlValid(final String url)
    {
        final AtomicBoolean valid = new AtomicBoolean(false);

        Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    InputStream inputStream = new URL(url).openStream();
                    try
                    {
                        valid.set(true);
                    }
                    finally
                    {
                        inputStream.close();
                    }
                }
                catch (Exception exception)
                {
                    Log.e(TAG, "Error validating URL: " + exception.toString(), exception);
                    valid.set(false);
                }
            }
        });
        t.start();
        try
        {
            t.join();
        }
        catch (InterruptedException e)
        {
            // Safe to ignore at this point
        }
        return valid.get();
    }

    private String getDrmContentFormat(String drmContentFormatLabel)
    {
        String[] drmContentFormatsLabelsSet;

        drmContentFormatsLabelsSet = getResources().getStringArray(R.array.formats);

        for (int i = 0; i < drmContentFormatsLabelsSet.length; i++)
        {
            if (drmContentFormatsLabelsSet[i].compareTo(drmContentFormatLabel) == 0)
            {
                switch (i)
                {
                    case 0:
                        return "" + DRMContentFormat.SMOOTH_STREAMING;
                    case 1:
                        return "" + DRMContentFormat.HTTP_LIVE_STREAMING;
                    case 2:
                        return "" + DRMContentFormat.PIFF;
                    case 3:
                        return "" + DRMContentFormat.MPEG_DASH;
                }
            }
        }

        return null;
    }

    private void createContentDescriptor()
    {
        final String contentDescriptorUrl = textView.getText().toString();
        final String contentDescriptorTitle = editText.getText().toString();

        if (!isUrlValid(contentDescriptorUrl))
        {
            Toast.makeText(this, "\nError accessing URL\n", Toast.LENGTH_SHORT).show();
            return;
        }

        final AtomicBoolean valid = new AtomicBoolean(false);
        Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    String contentDescriptor = contentDescriptorTemplate;
                    contentDescriptor = contentDescriptor.replace(XML_TEXT_TITLE, contentDescriptorTitle.length() == 0 ? "User added title" : contentDescriptorTitle);
                    contentDescriptor = contentDescriptor.replace(XML_TEXT_URL, contentDescriptorUrl);
                    if (findViewById(R.id.add_url_schema).getVisibility() == View.GONE)
                    {
                        contentDescriptor = contentDescriptor.replace(XML_TEXT_PROTECTION, "" + DRMScheme.CLEARTEXT);
                    }
                    else
                    {
                        contentDescriptor = contentDescriptor.replace(XML_TEXT_PROTECTION, "" + (radioButton.isChecked() ? DRMScheme.PLAYREADY : DRMScheme.CLEARTEXT));
                    }
                    contentDescriptor = contentDescriptor.replace(XML_TEXT_STREAM_TYPE, getDrmContentFormat((String) spinner.getSelectedItem()));
                    contentDescriptor = contentDescriptor.replace(XML_TEXT_SHORT_DESCRIPTION, "User added short description");
                    contentDescriptor = contentDescriptor.replace(XML_TEXT_LONG_DESCRIPTION, "User added long description");

                    final FileWriter fileWriter = new FileWriter(Constants.CONFIGURATION_CDESC_PATH + "custom_content_descriptor_" +
                            String.format(Constants.CONFIGURATION_MMDDYYHHMMSS_DATE_FORMAT, Calendar.getInstance()).replaceAll("/", "").replaceAll(" ", "").replaceAll(":", "") + ".cdesc");

                    try
                    {
                        fileWriter.write(XML_DECLARATION);
                        fileWriter.write("\n");
                        fileWriter.write(contentDescriptor);
                        fileWriter.flush();
                    }
                    finally
                    {
                        fileWriter.close();
                    }
                    valid.set(true);
                }
                catch (IOException e)
                {
                    Log.e(TAG, "Error occurred while flushing content descriptor to disk: " + e.getMessage(), e);
                    valid.set(false);
                }
            }
        });
        t.start();
        try
        {
            t.join();
        }
        catch (InterruptedException e)
        {
            // Safe to ignore for now
        }

        if (valid.get())
        {
            Toast.makeText(this, "\nContent created\n", Toast.LENGTH_LONG).show();
        }
        else
        {
            Toast.makeText(this, "\nError creating content descriptor\n", Toast.LENGTH_LONG).show();
        }

    }


    private String loadContentDescriptorTemplate()
    {
        final Exchanger<String> exchanger = new Exchanger<String>();

        final Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                String contentDescriptorTemplate = null;
                try
                {
                    XmlPullParser xmlPullParser = getResources().getXml(R.xml.cdesc);

                    StringBuilder stringBuilder = new StringBuilder();

                    int eventType = xmlPullParser.getEventType();

                    while (eventType != XmlPullParser.END_DOCUMENT)
                    {
                        switch (eventType)
                        {
                            case XmlPullParser.START_TAG:
                                String eventData = xmlPullParser.getName();
                                stringBuilder.append("<" + eventData);
                                if (eventData.compareTo(XML_TAG_DESCRIPTOR) == 0)
                                {
                                    stringBuilder.append(" " + XML_NAMESPACE_XSD_PREFIX + "=\"" + XMLConstants.W3C_XML_SCHEMA_NS_URI + "\"" +
                                            " " + XML_NAMESPACE_XSI_PREFIX + "=\"" + XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI + "\"" +
                                            ">\n");
                                }
                                else
                                {
                                    stringBuilder.append(">");
                                }
                                break;
                            case XmlPullParser.END_TAG:
                                stringBuilder.append("</" + xmlPullParser.getName() + ">\n");
                                break;
                            case XmlPullParser.TEXT:
                                stringBuilder.append(xmlPullParser.getText());
                                break;
                        }
                        eventType = xmlPullParser.next();
                    }
                    contentDescriptorTemplate = stringBuilder.toString();
                }
                catch (Exception exception)
                {
                    Log.e(TAG, "Error while loading content descriptor template: " + exception.getMessage(), exception);
                    contentDescriptorTemplate = null;
                }

                try
                {
                    exchanger.exchange(contentDescriptorTemplate);
                }
                catch (InterruptedException e)
                {
                    // Safe to ignore at this point
                }
            }
        });
        t.start();

        String exchange = null;
        try
        {
            exchange = exchanger.exchange(null);
        }
        catch (InterruptedException e)
        {
            // Safe to ignore
        }

        if (exchange == null)
        {
            Toast.makeText(this, "\nError getting content descriptor template\n", Toast.LENGTH_LONG).show();
        }
        return exchange;
    }


    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        contentDescriptorTemplate = loadContentDescriptorTemplate();

        setContentView(R.layout.add_url);
        mPreferences = getSharedPreferences(SHARED_PREFERENCES_FOR_ADD_CONTENT, Context.MODE_PRIVATE);
        mEditor = mPreferences.edit();

        textView = (AutoCompleteTextView) findViewById(R.id.add_url);

        //retrieve saved urls + set adapter
        setTextViewAdapter(getSavedURLs());

        textView.setOnFocusChangeListener(new View.OnFocusChangeListener()
        {
            public void onFocusChange(View v, boolean hasFocus)
            {
                if (hasFocus)
                {
                    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
                }
            }
        });

        textView.setValidator(new AutoCompleteTextView.Validator()
        {
            public boolean isValid(final CharSequence charSequence)
            {
                try
                {
                    Uri.parse(charSequence.toString());
                    return true;
                }
                catch (Exception e)
                {
                    return false;
                }
            }

            public CharSequence fixText(final CharSequence charSequence)
            {
                return null;
            }
        });

        Button button = (Button) findViewById(R.id.btn_create_cdesc);
        button.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(final View view)
            {
                //store the url
                storeURL(textView.getText().toString());

                if (!setDrmContentFormat())
                {
                    if (spinner.getSelectedItemPosition() == 0)
                    {
                        Toast.makeText(AddURLActivity.this, "\nFormat not set\n", Toast.LENGTH_SHORT).show();
                    }
                    else
                    {
                        dialog.show();
                    }
                }
                else
                {
                    createContentDescriptor();
                }
            }
        });

        //Add URL schema control
        radioButton = (RadioButton) findViewById(R.id.add_url_schema_playready);
        radioButton.setChecked(true);

        isNativeMediaPlayerUsed = DRMFusionAgentReferenceApplication.sUsesNativePlayer;

        ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(getResources().getStringArray(R.array.formats)));
        arrayList.add(0, "<Select format>");
        if (!isNativeMediaPlayerUsed)
        {
            //Remove MPEG-DASH format from available options, since it is not supported
            arrayList.remove(4);
        }

        //Add URL formats control
        spinner = (Spinner) findViewById(R.id.add_url_format_spinner);
        spinner.setAdapter(new CustomSpinnerAdapter(this, arrayList));

        //Add URL title control
        editText = (EditText) findViewById(R.id.add_url_title);

        OnClickListener positiveListener = new OnClickListener()
        {
            public void onClick(DialogInterface dialogInterface,
                                int i)
            {

                createContentDescriptor();
                dialog.dismiss();
            }
        };

        OnClickListener negativeListener = new OnClickListener()
        {


            public void onClick(DialogInterface dialogInterface,
                                int i)
            {

                dialog.dismiss();
            }
        };

        dialog = Tools.createAlertDialog(this,
                "WARNING",
                "File extension not recognized. Proceed with selected format?",
                false,
                "OK",
                positiveListener,
                "Cancel",
                negativeListener);

        setTitle(getResources().getString(R.string.dialog_title));
    }

    private void setTextViewAdapter(String[] savedURLs)
    {
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_dropdown_item_1line, savedURLs);

        textView.setAdapter(adapter);
    }

    private String[] getSavedURLs()
    {
        Map<String, ?> items = mPreferences.getAll();
        String[] retVal = new String[items.size()];

        int x = 0;
        for (String s : items.keySet())
        {
            retVal[x] = items.get(s).toString();
            x++;
        }
        return retVal;
    }

    private void storeURL(String urlToStore)
    {
        int indexToUse = 0;

        if (urlAlreadyExist(textView.getText().toString()))
        {
            return;
        }
        else
        {
            if (mPreferences.getAll().size() == mMaxUrlToStore)
            {
                removeOldestUrl();

                indexToUse = mMaxUrlToStore - 1;
            }
            else
            {
                indexToUse = mPreferences.getAll().size();
            }

            //store the url
            mEditor.putString(mKeyPrefix + indexToUse, textView.getText().toString());
            mEditor.commit();
            //refresh
            setTextViewAdapter(getSavedURLs());
        }
    }

    private boolean urlAlreadyExist(String urlToStore)
    {
        String[] storedUrl = getSavedURLs();
        int storedUrlLength = storedUrl.length;
        if (storedUrlLength == 0)
        {
            return false;
        }
        for (int i = 0; i < storedUrlLength; i++)
        {
            if (storedUrl[i].compareToIgnoreCase(urlToStore) == 0)
            {
                return true;
            }
        }
        return false;
    }

    private void removeOldestUrl()
    {
        for (int i = 1; i < mMaxUrlToStore; i++)
        {
            mEditor.putString(mKeyPrefix + (i - 1), mPreferences.getString(mKeyPrefix + i, ""));
        }
        mEditor.commit();
    }
}