package com.sharefaith.thesharefaithapp.base;

import android.app.Activity;
import android.app.Application;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.preference.PreferenceManager;
import androidx.core.content.FileProvider;
import androidx.multidex.MultiDex;

import android.util.Log;
import android.webkit.MimeTypeMap;
import android.widget.Toast;

import com.appideas.base.AiDb;
import com.appideas.base.AiSTr;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.messaging.FirebaseMessaging;
import com.sharefaith.thesharefaithapp.BuildConfig;
import com.sharefaith.thesharefaithapp.R;
import com.sharefaith.thesharefaithapp.SFMainActivity;
import com.sharefaith.thesharefaithapp.adapters.SFNavMenuAdapter;
import com.sharefaith.thesharefaithapp.adapters.SFPostAdapter;
import com.sharefaith.thesharefaithapp.adapters.SFSeriesListAdapter;
import com.sharefaith.thesharefaithapp.adapters.SFSermonAdapter;
import com.sharefaith.thesharefaithapp.models.SFBibleModel;
import com.sharefaith.thesharefaithapp.models.SFBookModel;
import com.sharefaith.thesharefaithapp.models.SFChapterModel;
import com.sharefaith.thesharefaithapp.models.SFNavMenuModel;
import com.sharefaith.thesharefaithapp.models.SFPostModel;
import com.sharefaith.thesharefaithapp.models.SFSermonModel;
import com.sharefaith.thesharefaithapp.models.SFSermonSeriesModel;
import com.sharefaith.thesharefaithapp.models.SFVideoStreamModel;
import com.sharefaith.thesharefaithapp.ui.SFDownloadsActivity;
import com.sharefaith.thesharefaithapp.ui.SFPlaylistActivity;
import com.sharefaith.thesharefaithapp.ui.SFSharedUIMethods;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.sentry.Sentry;
import io.sentry.android.AndroidSentryClientFactory;

/**
 * Created by sfwebsitedev on 1/26/16.
 * This class creates an instance of itself to hold global references throughout the apps lifecycle
 */
public class SFApplication extends Application
{
    /** SFApplication instances */
    private static SFApplication singleton;
    /** Database instance */
    private AiDb sfDb;
    /** holds a reference to the current activity */
    private Activity sfCurrentActivity;
    private String sfCurrentChurch;

    private OnSuccessListener myListener;

    //Navigation menu
    /** holds a reference to the navigation menu adapter */
    private SFNavMenuAdapter sfNavMenuAdapter;
    /** holds a reference to the connect metadata activity */
    private HashMap<String,String> sfConnectContentMeta;
    /** holds a reference to the navigation menu model */
    private SFNavMenuModel[] sfAppSections;

    //audio
    /** holds a reference to the mediaplayer */
    private MediaPlayer sfMediaPlayer;
    /** holds a reference to the last sermon played or currently playing */
    private SFSermonModel sfNowPlayingSermon;
    /** holds a reference to the audio manager */
    private AudioManager sfAudioManager;
    /** holds a reference to sfAudioManager listener for audio focus changes between other apps */
    private AudioManager.OnAudioFocusChangeListener sfOnAudioFocusChangeListener;

    //Adapters
    /** @deprecated */
    private SFPostAdapter sfPostAdapter;
    /** @deprecated */
    private SFSermonAdapter sfPlaylistsAdapter;
    /** @deprecated */
    private SFSeriesListAdapter sfSeriesListAdapter;

    //Models
    /** holds index of the last current or last Post */
    private SFPostModel sfCurrentPost;
    /** holds index of the last current or last Playlist */
    private SFSermonSeriesModel sfCurrentPlaylist;
    /** holds index of the last current or last Sermon */
    private SFSermonModel sfCurrentSermon;
    /** holds index of the last current or last VideoStream */
    public SFVideoStreamModel sfCurrentVideoStream;
    /** holds a reference to a Dialog */
    private Dialog sfDialog;

    //ids used for navigation
    /** holds index of the current Section */
    public int currentSectionPosition;
    /** holds index of the current Connect Section */
    public int currentConnectPosition;
    /** holds index of the current Bible Section */
    public int currentBiblePosition;
    /** holds index of the current Post Section */
    public int currentPostPosition;
    /** holds index of the current Inbox Section */
    public int currentInboxPosition;
    /** holds index of the current More Section */
    public int currentMorePosition;
    /** holds index of the current Playlist Section */
    public int currentPlaylistPosition;
    /** holds index of the current Calendar Section */
    public int currentCalendarPosition;
    /** holds index of the current Video Stream Section */
    public int currentVideoStreamPosition;
    /** holds index of the current Settings Section */
    public int currentSettingsPosition;

    // Global variables

    //booleans
    /** Is the database updating */
    public boolean isUpdatingDB = false;
    /** Is the app syncing */
    public boolean isSyncing = false;
    /** Is the app doing a full sync */
    public boolean isDoingFullSync = false;
    /** Is a Sermon Playing  */
    public boolean isSermonPlaying = false;
    /** Is the Sermon Paused */
    public boolean isSermonPaused = false;
    /** Is the audio stoped while app was in the background */
    public boolean wasStoppedInBackground = false;
    /** Is the Hashes table empty */
    public boolean isHashTableEmpty = false;
    /** Is the app in the forground */
    public boolean isInForground = false;
    /** Does the app have audio focus */
    public boolean haveAudioFocus = false;
    /** Is the Navigation menu open */
    public boolean isNavOpen = false;
    /** Are the Sermon details open */
    public boolean isSermonDetailsOpen = false;
    /** Should the ticker be stopped */
    public boolean stopUpdateTicker = false;
    /** Is the Bible menu open */
    public boolean isBibleMenuOpen = true;
    /** Is Bible Listening active */
    public boolean isListeningBible = false;
    /** Is the Bible audio playing */
    public boolean isBiblePlaying = false;
    /** Is the Bible audio paused */
    public boolean isBibleAudioPaused = false;
    /** Is the Bible scrolled to the bottom of the Chapter*/
    public boolean isAtBottomOfChapter = false;
    /** Is the footer audio controls open*/
    public boolean isMediaControlsFooterOpen = false;
    /** Is the audio elapse timer running */
    public boolean isElapseTimerRunning = false;
    /** Is the audio preload prepped */
    public boolean isAudioPreped = false;
    /** Is Audio loading */
    public boolean isAudioLoading = false;
    /** Is the Bible being downloaded */
    public boolean isDownloadingBible = false;
    /** Is the book selection menu open */
    public boolean isBookSelectOpen = false;
    /** Is the app restarting */
    public boolean isAppRestarting = false;
    /** Is the app have a push notification */
    public boolean mHavePush = false;
    /** @deprecated  */
    public boolean mOpenedFromNotification = false;
    /** For future versions */
    public boolean isFacebookShareEnabled = false;

    /** reference to the downloaded sermon opened */
    public int OpenDownloadSermon = 0;
    /** @deprecated  */
    public int mCurrentNotificationExternalId = 0;

    /** Holds font size in string to be used in html */
    private String fontSize;
    /** String of link to navigate to */
    public String currentLink;

    //bible data
    /** holds index of the current Bible */
    public int bibleIndex;
    /** holds index of the current Bible chapter */
    public int chapterIndex;
    /** holds index of the current Bible audio Chapter */
    public int audioChapterIndex;
    /** holds index of the current Bible book */
    public int bookIndex;
    /** holds a reference to the Bible Models */
    public SFBibleModel[] bibleModels;
    /** holds a reference to the Book Models */
    public SFBookModel[] bookModels;
    /** holds a reference to the Chapters */
    public SFChapterModel[] chapters;
    /** holds index of the open Bible book */
    public int positionOfOpenBook;

    //Strings
    //public final String PACKAGE_NAME = this.getPackageName();
    /** holds the tag of the current activity section */
    public String currentViewTag;

    //ints
    /** holds length of the current audio */
    public long totalDuration = -1;

    //Google play stuff
    public static final String PACKAGE_BASE = "com.sharefaith.churchapp.";
    public static String PACKAGE_NAME;
    public String regId;
    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    public static final String PROPERTY_REG_ID = "registration_id";
    private static final String PROPERTY_APP_VERSION = "appVersion";
    String SENDER_ID = SFConstants.GCM_SENDER_KEY;

    //Google Analytics stuff
    /** holds reference of Tracker for analytics */
    private Tracker mTracker;

    //Calendar vars
    /** holds index of the current Day */
    public int currentDayIndex;
    /** holds index of the current Month */
    public int currentMonthIndex;
    /** holds index of the current year */
    public int currentYearIndex;
    /** holds index of the lowest month to show  */
    public int minMonthIndex;
    /** holds index of the lowest year to show  */
    public int minYearIndex;
    /** holds index of the highest month to show  */
    public int maxMonthIndex;
    /** holds index of the highest year to show  */
    public int maxYearIndex;
    /** holds index of activated Day  */
    public int activeDayIndex;
    /** holds index of the activated Month  */
    public int activeMonthIndex;
    /** holds index of the activated Year  */
    public int activeYearIndex;

    /** holds list of churches **/
    public JSONObject churchList;

    private long lastTimelySync = 0;
    private ScreenBroadcastReceiver mScreenReceiver;

    /**
     * Creates an singleton instance of SFApplication to be used across the app
     * @return instance of SFApplication
     */
    public static SFApplication getInstance()
    {
        return  singleton;
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }

    //Getters and Setters

    /**
     * get a reference to the database
     * @return instance of Database
     */
    public AiDb getDb()
    {
        return sfDb;
    }

    /**
     * get a reference to the media player. Create one if one does not exist
     * @return instance of MediaPlayer
     */
    public MediaPlayer getSfMediaPlayer()
    {
        if( sfMediaPlayer == null )
        {
            sfMediaPlayer = new MediaPlayer();
        }
        return sfMediaPlayer;
    }

    /**
     * Returns a redirected url when the url redirects.
     * Useful for media
     * @param inputUrl
     * @return finalUrl
     * @throws IOException
     */
    public static String resolveRedirect(String inputUrl)
    {
        String finalUrl = inputUrl;

        try {
            URL url = new URL(inputUrl);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

            int responseCode = urlConnection.getResponseCode();

            if( responseCode == HttpURLConnection.HTTP_MOVED_PERM ||
                responseCode == HttpURLConnection.HTTP_MOVED_TEMP )
            {
                finalUrl = urlConnection.getHeaderField("Location");
            }
            urlConnection.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return finalUrl;
    }

    /**
     * get a reference of the currently playing sermon
     * @return sfNowPlayingSermon
     */
    public SFSermonModel getNowPlayingSermon()
    {
        return sfNowPlayingSermon;
    }

    /**
     * set the currently playing sermon
     * @param nowPlayingSermon
     */
    public void setNowPlayingSermon( SFSermonModel nowPlayingSermon )
    {
        this.sfNowPlayingSermon = nowPlayingSermon;
    }

    /**
     * get a reference to the current Activity
     * @return sfCurrentActivity
     */
    public Activity getCurrentActivity()
    {
        return sfCurrentActivity;
    }

    /**
     * Set the current Activity
     * @param currentActivity
     */
    public void setCurrentActivity( Activity currentActivity )
    {
        this.sfCurrentActivity = currentActivity;
    }

    /**
     * Set the current Church
     * @param currentChurch
     */
    public void setCurrentChurch( String currentChurch )
    {
        SFConstants constants = new SFConstants();
        String uaid = currentChurch.substring( 25 );
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = preferences.edit();
        editor.putString( "uaid", uaid );
        editor.commit();
        this.sfCurrentChurch = uaid;
        constants.UAID_KEY = constants.ANALYTICS_TAG = uaid;
        registerInBackground();
        Log.d( "tag", "setCurrentChurch: uaid" +sfCurrentChurch );
    }

    /**
     * Set the current Church from just uaid
     * @param currentChurchuaid
     */
    public void setCurrentChurchFromUAID( String currentChurchuaid )
    {
        SFConstants constants = new SFConstants();
        String uaid = currentChurchuaid;
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = preferences.edit();
        editor.putString( "uaid", uaid );
        editor.commit();
        this.sfCurrentChurch = uaid;
        constants.UAID_KEY = constants.ANALYTICS_TAG = uaid;
        registerInBackground();
        Log.d( "tag", "setCurrentChurch: uaid" +sfCurrentChurch );
    }

    /**
     * get uaid of current chosen church
     * @return sfCurrentChurch
     */
    public String getSfCurrentChurch()
    {
        if( this.sfCurrentChurch == null)
        {
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
            String currentChurch = preferences.getString( "uaid", "0" );
            this.sfCurrentChurch = currentChurch;
        }
        Sentry.getContext().addTag("uaid", this.sfCurrentChurch);
        return sfCurrentChurch;
    }

    /**
     * Get a reference to the Navigation menu adapter. Create one if doesn't already exist
     * @return sfNavMenuAdapter
     */
    public SFNavMenuAdapter getSfNavMenuAdapter()
    {
        if(sfNavMenuAdapter == null)
        {
            sfNavMenuAdapter = createNavMenuAdapter();
        }
        return sfNavMenuAdapter;
    }

    /**
     * Sets the Nav menu adapter to null
     */
    public void nullifyNavMenuAdapter()
    {
        sfNavMenuAdapter = null;
    }

    /**
     * Get a reference to the audio manager
     * @return sfAudioManager
     */
    public AudioManager getSfAudioManager()
    {
        return sfAudioManager;
    }
    /**
     * Get a reference to the audio manager change listener
     * @return sfOnAudioFocusChangeListener
     */
    public AudioManager.OnAudioFocusChangeListener getSfOnAudioFocusChangeListener()
    {
        return sfOnAudioFocusChangeListener;
    }

    /**
     * Get a reference to Connect Content Meta data
     * @param position
     * @return sfConnectContentMeta
     */
    public HashMap<String,String> getSFConnectContentMeta(int position)
    {
        populateConnectMeta( position );
        return sfConnectContentMeta;
    }

    /**
     * Get a reference to the current Post
     * @return sfCurrentPost
     */
    public SFPostModel getSfCurrentPost()
    {
        return sfCurrentPost;
    }

    /**
     * Set the Current Post
     * @param postModel
     */
    public void setSfCurrentPost( SFPostModel postModel )
    {
        sfCurrentPost = postModel;
    }

    /**
     * Get a reference to the current playlist
     * @return sfCurrentPlaylist
     */
    public SFSermonSeriesModel getSfCurrentPlaylist()
    {
        return sfCurrentPlaylist;
    }

    /**
     * Set the current playlist
     * @param playlistModel
     */
    public void setSfCurrentPlaylist(SFSermonSeriesModel playlistModel)
    {
        sfCurrentPlaylist = playlistModel;
    }

    /**
     * Get a reference to the current Sermon
     * @return sfCurrentSermon
     */
    public SFSermonModel getSfCurrentSermon()
    {
        return sfCurrentSermon;
    }

    /**
     * Set the current Sermon
     * @param sfCurrentSermon
     */
    public void setSfCurrentSermon( SFSermonModel sfCurrentSermon )
    {
        this.sfCurrentSermon = sfCurrentSermon;
    }

    /**
     * Get the current bible
     * @return bibleModels[bibleIndex]
     */
    public SFBibleModel getSfCurrentBible()
    {
        return bibleModels[bibleIndex];
    }

    /**
     * Get the array of book models
     * @return bookModels
     */
    public SFBookModel[] getBooks()
    {
        return bookModels;
    }

    /**
     * Get a reference to the current book
     * @return bookModels[bookIndex]
     */
    public SFBookModel getCurrentBook()
    {
        //Log.d( "mTag", "current book index = " + bookIndex + " and name = " + bookModels[bookIndex].mFullname  );
        return bookModels[bookIndex];
    }

    /**
     * Get the book at index in bookModels
     * @param index
     * @return bookModels[index]
     */
    public SFBookModel getBook(int index)
    {
        return bookModels[index];
    }

    /**
     * Set array of chapter models "chapters"
     * @param chapters
     */
    public void setChapters(SFChapterModel[] chapters)
    {
        this.chapters = chapters;
    }

    /**
     * Get the font size
     * @return fontSize
     */
    public String getFontSize()
    {
        return fontSize;
    }

    /**
     * Set the font Size
     * @param fontSize
     */
    public void setFontSize( String fontSize )
    {
        SFAppData appData = new SFAppData();
        this.fontSize = fontSize;
        appData.setFontSize( fontSize );
    }

    /**
     * Get reference to Dialog. Creates one if doesn't exist
     * @return sfDialog
     */
    public Dialog getSfDialog()
    {
        if(this.sfDialog == null )
        {
            this.sfDialog = new Dialog(this.getCurrentActivity());
        }
        return this.sfDialog;
    }

    /**
     * Better than a nullPointer... this SHOULD make it work in all those cases null value would cause exception.
     */
    public void forceSyncScreen()
    {
        SFAppData.saveSyncTime(0);
        this.isSyncing = false;

        Intent intent = new Intent(this, SFMainActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        sfCurrentActivity.overridePendingTransition(R.anim.sf_activity_slidein_right, R.anim.sf_activity_slideout_left);
    }

    /**
     * Sets sfDialog to null
     */
    public void releaseSfDialog()
    {
        this.sfDialog = null;
    }

    //End of Getters Setters

    /**
     * Creates singleton instance of itself. sets up the app
     */
    @Override
    public void onCreate()
    {
        super.onCreate();
        singleton = this;
        this.sfDb = new AiDb( this );
        //a listener for FCM tokens now:
        //this.myListener = new OnSuccessListener();

        // only uncomment this line while developing to make a fresh copy of the assets files or to copy test files form the assets folder onto a device
        //SFConfig.initialConfig();

        // if the database indicated that it had to be setup, let the config class know so that it can put things into place on the file system
        if( sfDb.neededSetup )
        {
            SFConfig.initialConfig();
            sfDb.neededSetup = false;
        }
        sfDb.doUpgrade();
        sfDb.CheckDatabaseForV2();

        SFAppData appData = new SFAppData();
        fontSize = appData.getFontSize();

        //set up the nav menu items
        //sfNavMenuAdapter = createNavMenuAdapter();

        // setup the audio manager
        wasStoppedInBackground = false;
        sfAudioManager = (AudioManager) getSystemService( Context.AUDIO_SERVICE );
        sfOnAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener()
        {
            @Override
            public void onAudioFocusChange(int focusChange)
            {
                switch (focusChange)
                {
                    case AudioManager.AUDIOFOCUS_GAIN:

                        haveAudioFocus = true;
                        break;

                    case AudioManager.AUDIOFOCUS_LOSS:

                        if( sfMediaPlayer!=null )
                        {
                            wasStoppedInBackground = true;
                            releaseMediaPlayer();
                            sfNowPlayingSermon = null;
                        }
                        sfAudioManager.abandonAudioFocus(sfOnAudioFocusChangeListener);
                        haveAudioFocus = false;
                        break;

                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                        if( sfMediaPlayer!=null )
                        {
                            wasStoppedInBackground = true;

                            releaseMediaPlayer();
                            sfNowPlayingSermon = null;

                        }

                        sfAudioManager.abandonAudioFocus(sfOnAudioFocusChangeListener);
                        haveAudioFocus = false;
                        break;

                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                        if( sfMediaPlayer!=null ) {
                            int volume = sfAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
                            int duckVolume = volume / 2;
                            sfMediaPlayer.setVolume(duckVolume, volume);
                        }
                        break;
                }
            }
        };

        //for registering for push notifications
        this.PACKAGE_NAME = PACKAGE_BASE + this.getSfCurrentChurch();
        if( this.checkPlayServices() )
        {
            // If this check succeeds, proceed with normal processing.
            // Otherwise, prompt user to get valid Play Services APK.
            this.regId = getRegistrationId();
            //System.out.println( "onCreate regId:" + regId );
            if( this.regId.isEmpty() && !this.getSfCurrentChurch().equals( "0" ))
            {
                registerInBackground();
            }
        }
        else {
            Log.e("error", "No valid Google Play Services APK found.");
        }

        Sentry.init("https://4d8bc7c94c46499eb3ab3efc91f1a62a:35651eeee9f54ed4a97851ca5ab2090a@sentry.io/272023",
        new AndroidSentryClientFactory( this.getApplicationContext() ) );

        /*final Handler handler = new Handler();
        Timer timer = new Timer();
        TimerTask asyncCheck = new TimerTask() {
            public void run()
            {
                handler.post(new Runnable()
                {
                    @SuppressWarnings("unchecked")
                    public void run()
                    {
                        setAppIcon(getSfCurrentChurch(), false);
                    }
                });
            }
        };
        timer.schedule(asyncCheck, 60*1000, 60*1000);
        That was messy, shortcut-already-created message popping up once a minute
        */

        IntentFilter screenStateFilter = new IntentFilter();
        //screenStateFilter.addAction(Intent.ACTION_SCREEN_ON);
        screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
        //Catch screen off events, not likely to see the toast unless screen is off and on quickly.
        this.mScreenReceiver = new ScreenBroadcastReceiver(this);
        registerReceiver(mScreenReceiver, screenStateFilter);
    }

    public void onDestroy()
    {
        unregisterReceiver(this.mScreenReceiver);
    }
    /**
     * SFNavMenuAdapter methods to create the navigation menu
     * @return SFNavMenuAdapter( this, getAppSections( true ) )
     */
    public SFNavMenuAdapter createNavMenuAdapter()
    {
        return new SFNavMenuAdapter( this, getAppSections( true ) );
    }

    private  String[] getAllChurchIds()
    {
        String[] churchList;
        String rawString = getChurchIds();
        if(rawString != null)
        {
            churchList = rawString.split( "," );
            return churchList;
        }
        return null;
    }

    private String getChurchIds()
    {
        String result = "";
        SFConfig config = new SFConfig();

        AssetManager assets = this.getAssets();

        try (InputStream inputStream = assets.open( "churchList.txt"))
        {
            try (BufferedReader bufferedReader = new BufferedReader( new InputStreamReader( inputStream ) ))
            {
                String line;
                while ((line = bufferedReader.readLine()) != null)
                {
                    result += line;
                }
            }
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        return result;
    }

    public void setAppIcon(String icon) {
        this.setAppIcon(icon, true);
    }

    public void setAppIcon(String icon, boolean doAll) {
        icon = icon.replace( "com.sharefaith.churchapp.","" );

        String[] iconIds = getAllChurchIds();
        PackageManager packageManager = getPackageManager();
        //Disable then enable?
        for (int i = 0; i<iconIds.length;i++)
        {
            if(!iconIds[i].equals( icon ) && doAll) {
                int enableSetting =  packageManager.getComponentEnabledSetting(new ComponentName(BuildConfig.APPLICATION_ID, "com.sharefaith.thesharefaithapp.SFMainActivity_" + iconIds[i]));
                try {
                    //int componentEnabledSetting = packageManager.getComponentEnabledSetting(
                    //        new ComponentName(BuildConfig.APPLICATION_ID, "com.sharefaith.thesharefaithapp.SFMainActivity-" + iconIds[i]));
                    packageManager.setComponentEnabledSetting(
                            new ComponentName(BuildConfig.APPLICATION_ID, "com.sharefaith.thesharefaithapp.SFMainActivity_" + iconIds[i]),
                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
                } catch (Exception e) {
                    e.getStackTrace();
                }
            }
        }
        for (int i = 0; i<iconIds.length;i++)
        {
            if(iconIds[i].equals( icon ))
            {
                try
                {
                    int componentEnabledSetting = packageManager.getComponentEnabledSetting(
                            new ComponentName(BuildConfig.APPLICATION_ID, "com.sharefaith.thesharefaithapp.SFMainActivity_" + icon));

                    if( componentEnabledSetting != PackageManager.COMPONENT_ENABLED_STATE_ENABLED ) {
                        packageManager.setComponentEnabledSetting(
                                new ComponentName(BuildConfig.APPLICATION_ID, "com.sharefaith.thesharefaithapp.SFMainActivity_" + icon),
                                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
                        //never gets here if icon removed. addShortcut( icon );
                    }
                    packageManager.setComponentEnabledSetting(
                            new ComponentName(BuildConfig.APPLICATION_ID, "com.sharefaith.thesharefaithapp.SFMainActivity_" + icon),
                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
                }catch (Exception iconNotFound)
                {
                    Log.e("ERROR", "Could not find icon, will try to set default");
                    try
                    {
                        packageManager.setComponentEnabledSetting(
                                new ComponentName( BuildConfig.APPLICATION_ID, "com.sharefaith.thesharefaithapp.SFMainActivity_default" ),
                                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP );
                    }catch (Exception e)
                    {
                        e.getStackTrace();
                    }
                }
            }
            else if( doAll )
            {
                //Very... very slow. Must unset ONLY the one that was previously set?
                //packageManager.getComponentEnabledSetting(new ComponentName(new Parcel("com.sharefaith.thesharefaithapp.SFMainActivity-" + iconIds[i]));
                /*try
                {
                    packageManager.setComponentEnabledSetting(
                            new ComponentName( BuildConfig.APPLICATION_ID, "com.sharefaith.thesharefaithapp.SFMainActivity_" + iconIds[i] ),
                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP );
                }catch (Exception e)
                {
                    e.getStackTrace();
                }*/
            }
        }

        //removeOldShortcut();
        addShortcut( icon ); //may make duplicate :(
    }

    public void addShortcut(String icon)
    {
        icon = icon.replace( "com.sharefaith.churchapp.","" );
        Intent shortcutIntent = new Intent(this, SFMainActivity.class);
        shortcutIntent.setAction( Intent.ACTION_MAIN );

        Intent addIntent = new Intent();
        addIntent.putExtra( Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent );
        addIntent.putExtra( Intent.EXTRA_SHORTCUT_NAME, getResources().getString( R.string.app_name ) );
        if(icon.equals("default"))
        {
            addIntent.putExtra( Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext( this, R.drawable.icon) );
        }
        else
        {
            try
            {
                addIntent.putExtra( Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext( this, getResources().getIdentifier( "sf" + icon, "drawable", getPackageName() ) ) );
            }catch (Exception iconMissing)
            {
                Log.e( "ERROR", "Could not find icon for shortcut, trying to set default" );
                try
                {
                    addIntent.putExtra( Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext( this, R.drawable.icon ) );
                }catch (Exception e)
                {
                    e.getStackTrace();
                }
            }
        }

        addIntent.setAction( "com.android.launcher.action.INSTALL_SHORTCUT" );
        addIntent.putExtra( "duplicate", false );
        this.sendBroadcast( addIntent );
    }

    public void removeOldShortcut()
    {
        Intent shortcutIntentDelete = new Intent(this, SFMainActivity.class);
        shortcutIntentDelete.setAction( Intent.ACTION_MAIN );

        Intent delIntent = new Intent();
        delIntent.putExtra( Intent.EXTRA_SHORTCUT_INTENT, shortcutIntentDelete );
        delIntent.putExtra( Intent.EXTRA_SHORTCUT_NAME, getResources().getString( R.string.app_name ) );
        delIntent.setAction( "com.android.launcher.action.UNINSTALL_SHORTCUT" );
        this.sendBroadcast( delIntent );
    }

    /**
     * Loads Audio in the background and calls  startMediaPlayer() after load
     */
    private void prepareAudio()
    {
        isAudioPreped = false;
        Thread t = new Thread(
                new Runnable()
                {
                    public void run()
                    {
                        String audioURL = "";
                        try
                        {
                            URL url = new URL( getString( R.string.sf_appbible_url )+
                                    SFConstants.UAID_KEY+"/audiourl/"+getSfCurrentBible().mAbreviation+"/"+
                                    getCurrentBook().mAbbreviation+(audioChapterIndex+1) );
                            BufferedReader in = new BufferedReader( new InputStreamReader( url.openConnection().getInputStream() ) );
                            String inputLine;

                            while ((inputLine = in.readLine()) != null)
                            {
                                audioURL += inputLine;
                            }
                            in.close();

                            //request audio focus from AudioManager
                            if( !haveAudioFocus ) {
                                int result = getSfAudioManager().requestAudioFocus(getSfOnAudioFocusChangeListener(), AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
                                if ( result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED )
                                {
                                    haveAudioFocus = true;
                                }
                            }
                            getSfMediaPlayer().setAudioStreamType( AudioManager.STREAM_MUSIC );
                            try
                            {
                                getSfMediaPlayer();
                                getSfMediaPlayer().setDataSource( audioURL );
                                getSfMediaPlayer().prepareAsync();
                                getSfMediaPlayer().setOnPreparedListener( new MediaPlayer.OnPreparedListener()
                                {
                                    @Override
                                    public void onPrepared( MediaPlayer mp )
                                    {
                                        isAudioPreped = true;
                                        startMediaPlayer();
                                        if( currentViewTag.equals( "downloads" ) )
                                        {
                                            SFDownloadsActivity activity = (SFDownloadsActivity) getCurrentActivity();
                                            activity.setupTitle();
                                            activity.setupPlayControls( null );
                                        }
                                    }
                                } );
                            }
                            catch (Exception e)
                            {
                                e.printStackTrace();
                            }

                        } catch (Exception e)
                        {
                            e.printStackTrace();
                        }

                    }
                }

        );
        t.start();
    }

    /**
     * Sets up the audio controls and starts the MediaPlayer
     */
    public void startMediaPlayer()
    {
        this.logEvent( "audio","play" );
        sfMediaPlayer.setOnCompletionListener( new MediaPlayer.OnCompletionListener()
        {
            @Override
            public void onCompletion( MediaPlayer mp )
            {
                if (sfNowPlayingSermon != null && isSermonPlaying)
                {
                    sfNowPlayingSermon.mCurrentAudioProgress = 0;
                    sfNowPlayingSermon.saveMembers();
                    releaseMediaPlayer();
                }
                if (!currentViewTag.equals( "downloads" ) && !currentViewTag.equals( "bible" ))
                {
                    SFSharedUIMethods.setAudioControls();
                }
                if( currentViewTag.equals( "downloads" ) && isSermonPlaying )
                {
                    SFDownloadsActivity activity = (SFDownloadsActivity) getCurrentActivity();
                    activity.setupPlayControls( getNowPlayingSermon() );
                }
                if(currentViewTag.equals( "sermondetail" ))
                {
                    SFPlaylistActivity activity = (SFPlaylistActivity) getCurrentActivity();
                    activity.setPlayButton();
                }
                if( isBiblePlaying )
                {
                    audioChapterIndex++;
                    if( audioChapterIndex < getCurrentBook().mNumChapters )
                    {
                        releaseMediaPlayer();
                        isBiblePlaying = true;
                        isBibleAudioPaused = false;
                        prepareAudio();
                    }
                    else
                    {
                        releaseMediaPlayer();
                    }
                }
            }
        } );
        sfMediaPlayer.start();
        SFSharedUIMethods.startElapseTimer();
    }

    /**
     * pause the mediaplayer
     */
    public void pauseMediaPlayer()
    {
        if( this.sfMediaPlayer != null )
        {
            this.sfMediaPlayer.pause();
            this.logEvent( "audio", "pause" );
        }
    }

    /**
     * Releases the Audio player
     */
    public void releaseMediaPlayer()
    {
        this.logEvent( "audio","pause" );
        if(sfMediaPlayer!=null)
        {
            if (sfMediaPlayer.isPlaying())
            {
                sfMediaPlayer.stop();
            }
            sfMediaPlayer.reset();
            sfMediaPlayer.release();
        }

        sfMediaPlayer = null;
        isSermonPlaying = false;
        isBiblePlaying = false;
        isSermonPaused = false;
        isBibleAudioPaused = false;
        totalDuration = -1;
    }

    /**
     * Gets the length of the audio file
     * @param sermon
     * @return duration of sermon
     */
    public long durationFromRemote( SFSermonModel sermon )
    {
        try
        {
            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
            retriever.setDataSource( sermon.mAudioUrl, new HashMap<String, String>() );
            String time = retriever.extractMetadata( MediaMetadataRetriever.METADATA_KEY_DURATION );
            return Long.parseLong( time );
        }
        catch( Exception e ) // this exception will throw if the headers can't be found or the uri is invalid
        {
            e.printStackTrace();
        }

        return (long) -1;
    }

    /**
     * Gets the Top Level navigation menu
     * @param forceRefresh
     * @return sfAppSections
     */
    public SFNavMenuModel[] getAppSections( boolean forceRefresh )
    {
        if( sfAppSections == null || forceRefresh )
        {
            sfAppSections = SFNavMenuModel.getTopLevel();
        }

        return sfAppSections;

    }

    /**
     * Populates the sfConnectContentMeta data
     * @param position
     */
    public void populateConnectMeta( int position )
    {

        SFAppData appData = new SFAppData();
        int contactSectionId = appData.getSectionIdByPosition( position );
        ArrayList<HashMap<String,String>> sectionContent = appData.getContentForSectionId( contactSectionId, 0 );

        // specific content out of first item
        HashMap<String,String> specificContent = sectionContent.get( 0 );
        sfConnectContentMeta = appData.getMetaForSectionContentId( Integer.valueOf( specificContent.get( "id" ) ) );

        //return sfConnectContentMeta;
    }

    /**
     * Get the Mime type of a file
     * @param filePath
     * @return type
     */
    public static String getMimeType( String filePath )
    {
        String type = null;
        String extension = MimeTypeMap.getFileExtensionFromUrl( filePath );
        if( extension != null )
        {
            MimeTypeMap mime = MimeTypeMap.getSingleton();
            type = mime.getMimeTypeFromExtension( extension );
        }

        if( type == null )
        {
            type = MimeUtils.guessMimeTypeFromExtension( extension.toLowerCase() );
        }

        return type;
    }

    /**
     * launch video in browser intent
     * @param url
     */
    public void launchVideo( String url )
    {
        SFUtil.logSiteEvent("Launch video");

        try
        {
            Intent browser = new Intent( Intent.ACTION_VIEW, Uri.parse( url ) );
            this.logEvent( "audio","watch" );
            sfCurrentActivity.startActivity( browser );
        }
        catch( Exception e )
        {
            Log.d( "URI", "Exception: " + e.getLocalizedMessage() );
        }
    }

    /**
     * open notes with intent
     * @param filePath
     */
    public void showNotesFile( String filePath )
    {
        try
        {
            String mimeType = this.getMimeType( filePath );
            if( mimeType == null )
            {
                mimeType = "";
            }


            // Grant permissions to registered apps
            final PackageManager pm = this.getPackageManager();

            final IntentFilter filter = new IntentFilter( Intent.ACTION_MAIN );
            filter.addCategory( Intent.CATEGORY_LAUNCHER );

            List<IntentFilter> outFilters = new ArrayList<IntentFilter>();
            outFilters.add( filter );

            List<ComponentName> outActivities = new ArrayList<ComponentName>();
            pm.getPreferredActivities( outFilters, outActivities, null );

            File incomingFile = new File( filePath );
            Uri uri = FileProvider.getUriForFile( this, SFConstants.CONTENT_PROVIDER, incomingFile );

            List<ResolveInfo> list = pm.queryIntentActivities( new Intent( Intent.ACTION_VIEW ), 0 );

            for( ResolveInfo resolveInfo : list )
            {
                String packageName = resolveInfo.activityInfo.packageName;
                this.grantUriPermission( packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION );
            }

            Intent intentUrl = new Intent( Intent.ACTION_VIEW );
            intentUrl.setDataAndType( uri, mimeType );
            sfCurrentActivity.startActivity( intentUrl );

        }
        catch ( ActivityNotFoundException e )
        {
            String extension = MimeTypeMap.getFileExtensionFromUrl( filePath );
            String message = this.getString( R.string.no_viewer_preamble ) + " " + extension.toUpperCase() + " " +  this.getString( R.string.no_viewer_postamble );
            makeToast( message );
        }
    }

    /**
     * parses string of ints delimited by , into an array of Integers
     * @param sIncluded
     * @return
     */
    public Integer[] parseIncludedIn(String sIncluded )
    {
        int count = 0;
        if(sIncluded == null)
        {
            return null;
        }
        String[] sIncludedarray = sIncluded.split( "," );

        //Log.d("mTag","included in befor split = " + sIncluded);

        for( int i = 0; i < sIncludedarray.length; i++ )
        {
            //Log.d("mTag","included split at " + i + " = " + sIncludedarray[i]);
            if( !sIncludedarray[i].equals( "" ) )
            {
                count++;
            }
        }
        Integer[] returnValue = new Integer[count];
        for( int i = 0; i < count; i++ )
        {
            returnValue[i] = AiSTr.denullifyInt(  sIncludedarray[i] );
            //Log.d("mTag","returnValue at " + i + " = " + returnValue[i]);
        }
        return returnValue;
    }

    /**
     * used for outputing very larg strings in log
     * @param tag
     * @param str
     */
    public void longInfo(String tag,String str)
    {
        if(str.length() > 1000 )
        {
            Log.d( tag, str.substring( 0, 1000 ) );
            longInfo( tag,str.substring( 1000 ) );
        }
        else
        {
            Log.d(tag,str);
        }
    }

    /**
     * @deprecated
     */
    public void clearCaches()
    {

    }

    /**
     * displays a message on screen
     * @param input
     */
    public static void makeToast( String input )
    {
        final String message = input;
        final Activity currentActivity = getInstance().getCurrentActivity();
         currentActivity.runOnUiThread(
                 new Runnable()
                 {
                     @Override
                     public void run()
                     {
                         Toast.makeText( currentActivity, message, Toast.LENGTH_LONG ).show();
                     }
                 }
         );
    }

    /**
     * converts pixels to dp based on the device's display
     * @param dp
     * @return the dp from converted pixels
     */
    public int getDP(int dp)
    {
        float scale = this.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }

    /**
     * get formated elapse time in a String
     * @param secondsRaw
     * @return display ready elapse time
     */
    public String secondsToElapseString(int secondsRaw)
    {

        long hours =  secondsRaw/(3600);
        long minutes = (secondsRaw - hours)/60;
        long seconds = secondsRaw%60;
        return ( Long.toString( hours ) + ":"+(minutes < 10 ? "0":"") +Long.toString( minutes ) + ":" +(seconds < 10 ? "0": "") + Long.toString( seconds ) );
    }

    /**
     * handles a push
     * @param push
     */
    public void handlePush( SFPushHandler push )
    {
        //Analytics
        if(push.mChannel == 0){ this.logEvent( "handle_push","simple" );}
        else if(push.mChannel == 1){ this.logEvent( "handle_push","sermon" );}
        else if(push.mChannel == 2){ this.logEvent( "handle_push","newsletter" );}
        else if(push.mChannel == 3){ this.logEvent( "handle_push","post" );}

        if( push.mChannel == SFConstants.PUSH_CHANNEL_SIMPLE && push.mPayload.length() > 0)
        {
                this.launchUrl( push.mPayload );
            //mHavePush = false;
        }
        else
        {
            if( push.mPayload.length() < 1 )
            {
                push.mPayload = "0";
            }
            else
            {
                this.launchContentAfterSync( push.mChannel, Integer.valueOf( push.mPayload ) );
            }
        }

        push.clearPush();
    }

    /**
     * opens url in browser intent
     * @param url
     */
    public void launchUrl( String url )
    {
        SFUtil.logSiteEvent( "Launch a URL" );

        try
        {
            Intent browser = new Intent( Intent.ACTION_VIEW, Uri.parse( url ) );
            startActivity( browser );
        }
        catch( Exception e )
        {
            Log.d( "URI", "Exception: " + e.getLocalizedMessage() );
        }
    }

    /**
     * processes Item from push and tells the app where to go
     * @param channel
     * @param externalId
     */
    public void launchContentAfterSync( int channel, final int externalId )
    {
        // don't do anything if the channel type is not within an acceptable range
        if( channel < SFConstants.PUSH_CHANNEL_SIMPLE || channel > SFConstants.PUSH_CHANNEL_POST  )
        {
            return;
        }

        //finishAction = "";
        //this.mFinishActionId = 0;

        //destinationChannel = channel;
        //this.showProgress( getString( R.string.something_new ), getString( R.string.grabbing_now ) );
        final SFApplication application = this.getInstance();
        Thread t = new Thread(
                new Runnable()
                {
                    public void run()
                    {
                        //Log.d("mTag","hit launch content after sync with channel = " +destinationChannel);
                        SFBackgroundSync sync = new SFBackgroundSync( application );
                        //mFinishActionId = externalId;
                        sync.processNotification( externalId );
                    }
                }
        );
        t.start();
    }

    /**
     * deletes files from the passed dir
     * @param dir
     * @return
     */
    public boolean deleteFilesFromDir( File dir )
    {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                boolean success = deleteFilesFromDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        else
        {
            return dir.delete();
        }

        return true;
    }

    /**
     * Check the device to make sure it has the Google Play Services APK. If
     * it doesn't, display a dialog that allows users to download the APK from
     * the Google Play Store or enable it in the device's system settings.
     */
    public boolean checkPlayServices()
    {
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable( this );
        if( resultCode != ConnectionResult.SUCCESS )
        {
            if( GooglePlayServicesUtil.isUserRecoverableError( resultCode ) )
            {
                // Offer the connection failure dialog to real devices, not the emulator since it can't typically recover
                if( !Build.FINGERPRINT.startsWith( "generic" ) && !Build.FINGERPRINT.startsWith( "unknown" ) )
                {
                    //GooglePlayServicesUtil.getErrorDialog( resultCode, this.getCurrentActivity(),
                            //PLAY_SERVICES_RESOLUTION_REQUEST ).show();
                    Log.e( "ERROR", "Cannot connect to Play Services" );
                }
            }
            else
            {
                Log.i( "mTag", "This device is not supported." );
            }
            return false;
        }
        return true;
    }

    /**
     * Gets the current registration ID for application on GCM service.
     *
     * If result is empty, the app needs to register.
     *
     * @return registration ID, or empty string if there is no existing
     *         registration ID.
     */
    public String getRegistrationId()
    {
        final SharedPreferences prefs = getGCMPreferences( this );
        String registrationId = prefs.getString( PROPERTY_REG_ID, "" );
        if( registrationId.isEmpty() )
        {
            Log.i( "mTag", "Registration not found." );
            return "";
        }
        // Check if app was updated; if so, it must clear the registration ID
        // since the existing regID is not guaranteed to work with the new
        // app version.
        int registeredVersion = prefs.getInt( PROPERTY_APP_VERSION, Integer.MIN_VALUE );
        int currentVersion = getAppVersion( this );
        if( registeredVersion != currentVersion )
        {
            Log.i( "mTag", "App version changed." );
            return "";
        }
        return registrationId;
    }

    /**
     * Registers the application with GCM servers asynchronously.
     * <p>
     * Stores the registration ID and app version Code in the application's
     * shared preferences.
     */
    public void registerInBackground() {
        FirebaseMessaging.getInstance().getToken().addOnSuccessListener(new OnSuccessListener<String>() {
            @Override
            public void onSuccess(String token) {
                regId = token;
                storeRegistrationId(SFApplication.this, token);

                try
                {
                    new AsyncTask<Void, Void, String>()
                    {
                        public String msg = "";

                        @Override
                        protected String doInBackground( Void... params )
                        {
                            //String msg = "";
                            try
                            {
                                //If app is registered for a topic, it needs to be unregistered before registering for the new topic
                                if (regId != null && !regId.isEmpty())
                                {
                                    String url_select = getString( R.string.pushserve_url ) + "/unRegisterDevice?";
                                    Map<String, String> url_params = new HashMap<>();

                                    url_params.put( "key", SFConstants.PUSHSERVE_KEY );
                                    url_params.put( "device_token", regId );

                                    String paramString = AiSTr.getEncodedData( url_params );
                                    url_select += paramString;

                                    //System.out.println( "Device Registration url_select: " + url_select );
                                    URL url;
                                    HttpURLConnection urlConnection = null;


                                    String response = null;
                                    try
                                    {
                                        url = new URL( url_select );
                                        urlConnection = (HttpURLConnection) url.openConnection();

                                        //InputStream in = urlConnection.getInputStream();
                                        //InputStreamReader isw = new InputStreamReader( (in) );

                                        response = urlConnection.getResponseMessage();


                                    } catch (Exception e)
                                    {
                                        Log.e( "ERROR", "Could not register app with GCM server, Response: " + response );
                                        e.printStackTrace();
                                    }
                                }

                                msg = "Device registered, registration ID=" + regId;
                                //System.out.println( msg );

                                //System.out.println( "sendRegistrationIdToBackend: " + msg );

                                // For this demo: we don't need to send it because the device
                                // will send upstream messages to a server that echo back the
                                // message using the 'from' address in the message.

                                // Persist the regID - no need to register again.
                                storeRegistrationId( getApplicationContext(), regId );
                                //System.out.println( "storeRegistrationId: " + msg );

                                // You should send the registration ID to PushServe.sharefaith.com over HTTP,
                                // so it can use GCM/HTTP or CCS to send messages to your app.
                                // The request to your server should be authenticated if your app
                                // is using accounts.
                                //sendRegistrationIdToBackend(regId);

                                String model = getDeviceName().replaceAll( "\\s+", "" );
                                int currentVersion = getAppVersion( getApplicationContext() );

                                String url_select = getString( R.string.pushserve_url ) + "/registerTheSharefaithAppDevice?";

                                //List<BasicNameValuePair> url_params = new LinkedList<BasicNameValuePair>();
                                Map<String, String> url_params = new HashMap<>();

                                url_params.put( "app_store_id", PACKAGE_BASE + SFApplication.getInstance().getSfCurrentChurch() );
                                url_params.put( "key", SFConstants.PUSHSERVE_KEY );
                                url_params.put( "channel[" + SFConstants.PUSH_CHANNEL_SIMPLE + "]", SFConstants.CHANNEL_NAME_SIMPLE );
                                url_params.put( "channel[" + SFConstants.PUSH_CHANNEL_SERMON + "]", SFConstants.CHANNEL_NAME_SERMON );
                                url_params.put( "channel[" + SFConstants.PUSH_CHANNEL_NEWSLETTER + "]", SFConstants.CHANNEL_NAME_NEWSLETTER );
                                url_params.put( "channel[" + SFConstants.PUSH_CHANNEL_POST + "]", SFConstants.CHANNEL_NAME_POST );
                                url_params.put( "device", "{\"device_os\":\"Android\",\"device_token\":\"" + regId + "\",\"app_version\":\"" + currentVersion + "\",\"device_model\":\"" + model + "\"}" );

                                String paramString = AiSTr.getEncodedData( url_params );
                                url_select += paramString;

                                //System.out.println( "Device Registration url_select: " + url_select );
                                URL url;
                                HttpURLConnection urlConnection = null;


                                String response = null;
                                try
                                {
                                    url = new URL( url_select );
                                    urlConnection = (HttpURLConnection) url.openConnection();

                                    //InputStream in = urlConnection.getInputStream();
                                    //InputStreamReader isw = new InputStreamReader( (in) );

                                    response = urlConnection.getResponseMessage();


                                } catch (Exception e)
                                {
                                    Log.e( "ERROR", "Could not register app with FCM server, Response: " + response );
                                    e.printStackTrace();
                                    Sentry.capture(e);
                                }

                            } catch (Exception ex)
                            {
                                msg = "Error :" + ex.getMessage();
                                Sentry.capture(ex);
                                // If there is an error, don't just keep trying to register.
                                // Require the user to click a button again, or perform
                                // exponential back-off.
                            }
                            return msg;
                        }

                        @Override
                        protected void onPostExecute( final String msg )
                        {
                            //System.out.println("Push Registration Message: "+msg);
                        }
                    }.execute( null, null, null );
                }
                catch (Exception e)
                {
                    SFApplication.makeToast( "couldn't register for push notifications. Please make sure you are logged into a google account" );
                }
            }
        });


    }

    /*private class OnSuccessListener extends com.google.android.gms.tasks.OnSuccessListener<something no one will say in docs>
    {
        public void onSuccess(Object o) {

        }
    }*/

    /**
     * @return Application's {@code SharedPreferences}.
     */
    private SharedPreferences getGCMPreferences( Context context )
    {
        // This sample app persists the registration ID in shared preferences, but
        // how you store the regID in your app is up to you.
        return getSharedPreferences( SFApplication.class.getSimpleName(), Context.MODE_PRIVATE );
    }

    /**
     * @return Application's version code from the {@code PackageManager}.
     */
    private static int getAppVersion( Context context )
    {
        try
        {
            PackageInfo packageInfo = context.getPackageManager()
                    .getPackageInfo( context.getPackageName(), 0 );
            return packageInfo.versionCode;
        }
        catch( PackageManager.NameNotFoundException e )
        {
            // should never happen
            //throw new RuntimeException( "Could not get package name: " + e );
            return 0;
        }
    }

    /**
     * Stores registration id
     * @param context
     * @param regId
     */
    private void storeRegistrationId( Context context, String regId )
    {
        final SharedPreferences prefs = getGCMPreferences( context );
        int appVersion = getAppVersion( context );
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString( PROPERTY_REG_ID, regId );
        editor.putInt( PROPERTY_APP_VERSION, appVersion );
        editor.commit();
    }

    /**
     *  Get the Device Model Information
     */
    public String getDeviceName()
    {
        String manufacturer = Build.MANUFACTURER;
        String model = Build.MODEL;
        if( model.startsWith( manufacturer ) )
        {
            return model;
        }
        else
        {
            return manufacturer + " " + model;
        }
    }

    /**
     * Gets the default {@link Tracker} for this {@link Application}.
     * @return tracker
     */
    synchronized public Tracker getDefaultTracker() {
        if (mTracker == null) {
            GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
            // To enable debug logging use: adb shell setprop log.tag.GAv4 DEBUG
            mTracker = analytics.newTracker(R.xml.global_tracker);
        }
        return mTracker;
    }

    /**
     * send Google Analytics screen event
     * @param screen
     */
    public void logScreen( String screen )
    {
        //Google Analytics tracking
        if( SFConstants.TRACK_ANALYTICS )
        {
            Tracker tracker = getDefaultTracker();
            tracker.setScreenName( screen );
            tracker.send( new HitBuilders.ScreenViewBuilder().build() );
        }
    }

    /**
     * send Google Analytics event
     * @param category
     * @param action
     */
    public void logEvent(String category, String action )
    {
        if( SFConstants.TRACK_ANALYTICS )
        {
            Tracker tracker = getDefaultTracker();
            tracker.send( new HitBuilders.EventBuilder()
                    .setCategory( category )
                    .setAction( action )
                    .setLabel( "label" )
                    .build()
            );
        }
    }

    /**
     * send Google Analytics event with label
     * @param category
     * @param action
     * @param label
     */
    public void logEvent(String category, String action, String label )
    {
        if( SFConstants.TRACK_ANALYTICS )
        {
            Tracker tracker = getDefaultTracker();
            tracker.send( new HitBuilders.EventBuilder()
                    .setCategory( category )
                    .setAction( action )
                    .setLabel( label )
                    .build()
            );
        }
    }
    /**
     * Gets the current calendar day, month, year and sets bounderies
     */
    public void setCurrentCalendar()
    {
        Calendar calendar = Calendar.getInstance();

        this.currentDayIndex= this.activeDayIndex = calendar.get( Calendar.DAY_OF_MONTH );
        this.currentMonthIndex = this.activeMonthIndex = calendar.get( Calendar.MONTH );
        this.currentYearIndex = this.activeYearIndex = calendar.get( Calendar.YEAR );

        calendar.add( Calendar.MONTH, -3 );
        this.minMonthIndex = calendar.get( Calendar.MONTH );
        this.minYearIndex = calendar.get( Calendar.YEAR );

        calendar.add( Calendar.MONTH, 15 );
        this.maxMonthIndex = calendar.get( Calendar.MONTH );
        this.maxYearIndex = calendar.get( Calendar.YEAR );

        calendar = null;
    }

    public void didResume( SFConfig config )
    {

        Log.w( "tag", "DIDRESUME" );
        long theTime = java.lang.System.currentTimeMillis()/1000;
        final SFApplication mApplication = this;
        if( config.mLastSync < theTime - 600 && mApplication.lastTimelySync < theTime - 600 )
        {
            //Old. Sync as in onCreate:
            if (!mApplication.isSyncing && !mApplication.isAppRestarting)
            {
                Log.w( "tag", "NOW SYNC!" );
                //demoLinearLayout.setVisibility( View.INVISIBLE );
                mApplication.isSyncing = true;
                //this.showProgress( getString( R.string.connecting ), getString( R.string.getting_updates ) );

                Thread t = new Thread(
                        new Runnable()
                        {
                            public void run()
                            {
                                SFBackgroundSync sync = new SFBackgroundSync( mApplication );
                                sync.doSync();
                            }
                        }
                );
                t.start();

            }
            mApplication.lastTimelySync = theTime;
        }
    }
}

