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

import java.util.concurrent.*;

import android.annotation.TargetApi;
import android.graphics.*;
import android.os.*;
import android.text.*;
import android.text.style.*;
import android.util.Log;
import android.widget.TextView;
import com.insidesecure.drmagent.mediaplayer.MediaPlayer;
import com.insidesecure.drmagent.subtitles.*;

@TargetApi(16)
public class SubtitleHandler implements Runnable
{
    private static final String TAG = SubtitleHandler.class.getSimpleName();

    private MediaPlayer mMediaPlayer;
    private final TextView mSubtitleTextView;
    private boolean mKeepRunning = true;
    private BlockingQueue<Subtitle> mQueuedSubtitles;
    private Handler mHandler;
    private Thread mThread;

    public SubtitleHandler(final MediaPlayer mMediaPlayer, final TextView subtitleTextView)
    {
        this.mMediaPlayer = mMediaPlayer;
        mSubtitleTextView = subtitleTextView;
        mQueuedSubtitles = new ArrayBlockingQueue<Subtitle>(20);
        mHandler = new Handler(Looper.getMainLooper());
    }

    public void start()
    {
        mThread = new Thread(this);
        mThread.start();
    }

    public void shutdown()
    {
        mKeepRunning = false;
        Thread thread = mThread;
        if (thread != null)
        {
            mThread = null;
            thread.interrupt();
            try
            {
                thread.join();
            }
            catch (InterruptedException e)
            {
                // Now what?
            }
        }
    }

    public void run()
    {
        while (true)
        {
            try
            {
                final Subtitle subtitle = mQueuedSubtitles.poll(1000, TimeUnit.MILLISECONDS);
                if (subtitle != null)
                {
                    Log.d(TAG, "Received subtitle: " + subtitle);
                    if (subtitle != Subtitle.NO_SUBTITLE)
                    {
                        if (mMediaPlayer != null && mMediaPlayer.isPlaying())
                        {
                            long currentPosition = mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : -1;

                            final Interval interval = subtitle.getInterval();
                            if (interval.before(0))
                            {
                                setSubtitleText(subtitle);
                            }
                            else
                            {
                                if (interval.contains(currentPosition))
                                {
                                    setSubtitleText(subtitle);
                                    while (interval.contains(currentPosition))
                                    {
                                        Thread.sleep(300);
                                        currentPosition = mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : -1;
                                    }
                                    setSubtitleText(Subtitle.NO_SUBTITLE);
                                }
                            }
                        }
                    }
                    else
                    {
                        // Lets clear the current sub-title
                        setSubtitleText(subtitle);
                    }
                }
            }
            catch (InterruptedException e)
            {
                if (mKeepRunning)
                {
                    Thread.interrupted();
                    setSubtitleText(null);
                    continue;
                }
                else
                {
                    break;
                }
            }
            catch (Exception e)
            {
                Log.e(TAG, "Error while processing subtitle: " + e.getMessage(), e);
            }
        }
    }

    private void setSubtitleText(final Subtitle subtitle)
    {
        mHandler.post(new Runnable()
        {
            public void run()
            {
                if (subtitle == Subtitle.NO_SUBTITLE)
                {
                    mSubtitleTextView.setText("");
                }
                else
                {
                    setupTextView(mSubtitleTextView, subtitle);
                }
            }
        });
    }

    private void setupTextView(final TextView txtSubtitle, final Subtitle subtitle)
    {
        SpannableStringBuilder ssb = subtitle.getSpannableStringBuilder();
        if (ssb != null)
        {
            txtSubtitle.setText(ssb);
        }
        else
        {
            ssb = new SpannableStringBuilder();
            String subtitleText = subtitle.getFullText();
            if (subtitleText != null)
            {
                ssb.append(subtitleText);
            }

            int start = 0;

            for (TextFragment textFragment : subtitle.getTextFragments())
            {
                final int length = textFragment.getText().length();
                // Take into account additional spaces which may be present in the full text but not in the fragment, due to new lines
                final int end = start + length + (textFragment.isNewLine() ? 1 : 0);
                Style style = textFragment.getStyle();
                if (style != null)
                {
                    boolean bold = false;
                    boolean italic = false;

                    if (style.mFontStyle != null)
                    {
                        switch (style.mFontStyle)
                        {
                            case ITALIC:
                                italic = true;
                                break;
                            case NORMAL:
                            default:
                        }
                    }

                    if (style.mFontWeight != null)
                    {
                        switch (style.mFontWeight)
                        {
                            case BOLD:
                                bold = true;
                                break;
                            case NORMAL:
                            default:
                                break;
                        }
                    }

                    if (bold || italic)
                    {
                        ssb.setSpan(new StyleSpan(bold ? (italic ? Typeface.BOLD_ITALIC : Typeface.BOLD) : (italic ? Typeface.ITALIC : Typeface.NORMAL)), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
                    }

                    if (style.mTextDecoration != null && !style.mTextDecoration.isEmpty())
                    {
                        for (Style.TextDecoration textDecoration : style.mTextDecoration)
                        {
                            switch (textDecoration)
                            {
                                case LINE_THROUGH:
                                    ssb.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                                    break;
                                case UNDERLINE:
                                    ssb.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                                    break;
                                case OVERLINE:
                                    ssb.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                                    break;
                                case NO_UNDERLINE:
                                case NO_LINETHROUGH:
                                case NO_OVERLINE:
                                case NONE:
                                    break;
                            }
                        }
                    }

                    if (style.mFontSize != null)
                    {
                        // Depending on what we get in the size field (px,pt,relative?) we need to apply a different span here
                        if (style.mFontSize.endsWith("px"))
                        {
                            try
                            {
                                int size = Integer.parseInt(style.mFontSize.substring(0, style.mFontSize.length() - 2));
                                ssb.setSpan(new AbsoluteSizeSpan(size, true), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);

                            }
                            catch (NumberFormatException e)
                            {
                                Log.e(TAG, "Error converting pixel fontSize to integer: " + style.mFontSize);
                            }
                        }
                    }

                    if (style.mFontFamily != null)
                    {
                        // May need to translate between font family and what is supported on Android here
                    }

                    if (style.mColor != null)
                    {
                        int color = getAndroidColor(style.mColor);
                        ssb.setSpan(new ForegroundColorSpan(color), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                    }

                    if (style.mBackgroundColor != null)
                    {
                        int color = getAndroidColor(style.mBackgroundColor);
                        ssb.setSpan(new BackgroundColorSpan(color), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                    }

                }

                start += length;

            }
            txtSubtitle.setText(ssb);
        }

    }


    public static int getAndroidColor(final String colorStr)
    {
        if (colorStr.startsWith("rgba("))
        {
            // Parse out the components
            String subStr = colorStr.substring(5, colorStr.length());
            String[] parts = subStr.split(",");
            return Color.argb(Integer.parseInt(parts[3]), Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2]));
        }

        int color = 0;
        try
        {
            color = Color.parseColor(colorStr);
        }
        catch (Exception e)
        {
            // Try some manual conversion?
            if ("transparent".equals(color))
            {
                return Color.TRANSPARENT;
            }
        }

        return color;
    }

    public void addSubtitle(final Subtitle subtitle)
    {
        mQueuedSubtitles.add(subtitle);
    }
}