package com.github.shadowsocks;
/*
 * Shadowsocks - A shadowsocks client for Android
 * Copyright (C) 2014 <max.c.lv@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *                            ___====-_  _-====___
 *                      _--^^^#####//      \\#####^^^--_
 *                   _-^##########// (    ) \\##########^-_
 *                  -############//  |\^^/|  \\############-
 *                _/############//   (@::@)   \\############\_
 *               /#############((     \\//     ))#############\
 *              -###############\\    (oo)    //###############-
 *             -#################\\  / VV \  //#################-
 *            -###################\\/      \//###################-
 *           _#/|##########/\######(   /\   )######/\##########|\#_
 *           |/ |#/\#/\#/\/  \#/\##\  |  |  /##/\#/  \/\#/\#/\#| \|
 *           `  |/  V  V  `   V  \#\| |  | |/#/  V   '  V  V  \|  '
 *              `   `  `      `   / | |  | | \   '      '  '   '
 *                               (  | |  | |  )
 *                              __\ | |  | | /__
 *                             (vvv(VVV)(VVV)vvv)
 *
 *                              HERE BE DRAGONS
 *
 */

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.TextAppearanceSpan;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.CheckedTextView;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;

import com.github.clans.fab.FloatingActionButton;
import com.github.clans.fab.FloatingActionMenu;
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback;
import com.github.shadowsocks.database.Profile;
import com.github.shadowsocks.database.ProfileManager;
import com.github.shadowsocks.database.SSRSub;
import com.github.shadowsocks.database.SSRSubManager;
import com.github.shadowsocks.network.ping.PingCallback;
import com.github.shadowsocks.network.ping.PingHelper;
import com.github.shadowsocks.network.request.RequestCallback;
import com.github.shadowsocks.network.request.RequestHelper;
import com.github.shadowsocks.network.ssrsub.SubUpdateCallback;
import com.github.shadowsocks.network.ssrsub.SubUpdateHelper;
import com.github.shadowsocks.utils.Constants;
import com.github.shadowsocks.utils.Parser;
import com.github.shadowsocks.utils.ToastUtils;
import com.github.shadowsocks.utils.TrafficMonitor;
import com.github.shadowsocks.utils.Utils;
import com.github.shadowsocks.widget.UndoSnackbarManager;
import com.google.android.material.snackbar.Snackbar;

import net.glxn.qrgen.android.QRCode;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatDrawableManager;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.TaskStackBuilder;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import static com.github.shadowsocks.ShadowsocksApplication.app;

public class ProfileManagerActivity extends AppCompatActivity implements View.OnClickListener, Toolbar.OnMenuItemClickListener, NfcAdapter.CreateNdefMessageCallback, ProfileManager.ProfileAddedListener, SSRSubManager.SSRSubAddedListener {

    private static final String TAG = ProfileManagerActivity.class.getSimpleName();
    private static final int MSG_FULL_TEST_FINISH = 1;

    private ProfileViewHolder selectedItem;
    private Handler handler = new Handler();

    private FloatingActionMenu menu;

    private ProfilesAdapter profilesAdapter;
    private SSRSubAdapter ssrsubAdapter;
    private UndoSnackbarManager<Profile> undoManager;

    private ClipboardManager clipboard;

    private NfcAdapter nfcAdapter;
    private byte[] nfcShareItem;
    private boolean isNfcAvailable;
    private boolean isNfcEnabled;
    private boolean isNfcBeamEnabled;

    private ProgressDialog testProgressDialog;
    private boolean isTesting;
    private GuardedProcess ssTestProcess;

    private int REQUEST_QRCODE = 1;
    private boolean is_sort = false;

    private ServiceBoundContext mServiceBoundContext;

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        mServiceBoundContext = new ServiceBoundContext(newBase) {

        };
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        profilesAdapter = new ProfilesAdapter();
        ssrsubAdapter = new SSRSubAdapter();

        clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);

        String action = getIntent().getAction();
        if (action != null && action.equals(Constants.Action.SCAN)) {
            qrcodeScan();
        }

        if (action != null && action.equals(Constants.Action.SORT)) {
            is_sort = true;
        }

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
        setContentView(R.layout.layout_profiles);

        initToolbar();
        initFab();

        app.profileManager.addProfileAddedListener(this);

        final RecyclerView profilesList = (RecyclerView) findViewById(R.id.profilesList);
        final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        profilesList.setLayoutManager(layoutManager);
        profilesList.setItemAnimator(new DefaultItemAnimator());
        profilesList.setAdapter(profilesAdapter);
        profilesList.postDelayed(new Runnable() {
            @Override
            public void run() {
                // scroll to position
                int position = getCurrentProfilePosition();
                profilesList.scrollToPosition(position);
            }
        }, 100);

        undoManager = new UndoSnackbarManager<>(profilesList, new UndoSnackbarManager.OnUndoListener<Profile>() {
            @Override
            public void onUndo(SparseArray<Profile> undo) {
                profilesAdapter.undo(undo);
            }
        }, new UndoSnackbarManager.OnCommitListener<Profile>() {
            @Override
            public void onCommit(SparseArray<Profile> commit) {
                profilesAdapter.commit(commit);
            }
        });

        if (!is_sort) {
            new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
                    ItemTouchHelper.START | ItemTouchHelper.END) {
                @Override
                public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                    int index = viewHolder.getAdapterPosition();
                    profilesAdapter.remove(index);
                    undoManager.remove(index, ((ProfileViewHolder) viewHolder).item);
                }

                @Override
                public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                    profilesAdapter.move(viewHolder.getAdapterPosition(), target.getAdapterPosition());
                    return true;
                }

            }).attachToRecyclerView(profilesList);
        }

        mServiceBoundContext.attachService(new IShadowsocksServiceCallback.Stub() {

            @Override
            public void stateChanged(int state, String profileName, String msg) throws RemoteException {
                // Ignored
            }

            @Override
            public void trafficUpdated(long txRate, long rxRate, long txTotal, long rxTotal) throws RemoteException {
                if (selectedItem != null) {
                    selectedItem.updateText(txTotal, rxTotal);
                }
            }
        });

        showProfileTipDialog();

        Intent intent = getIntent();
        if (intent != null) {
            handleShareIntent(intent);
        }
    }

    /**
     * init toolbar
     */
    private void initToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitle(R.string.profiles);
        toolbar.setNavigationIcon(R.drawable.ic_navigation_close);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = getParentActivityIntent();
                if (shouldUpRecreateTask(intent) || isTaskRoot()) {
                    TaskStackBuilder.create(ProfileManagerActivity.this).addNextIntentWithParentStack(intent).startActivities();
                } else {
                    finish();
                }
            }
        });
        toolbar.inflateMenu(R.menu.profile_manager_menu);
        toolbar.setOnMenuItemClickListener(this);
    }

    private int getCurrentProfilePosition() {
        int position = -1;
        List<Profile> profiles = profilesAdapter.profiles;
        for (int i = 0; i < profiles.size(); i++) {
            Profile profile = profiles.get(i);
            if (profile.id == app.profileId()) {
                position = i;
            }
        }
        return position;
    }

    /**
     * show profile tips dialog
     */
    private void showProfileTipDialog() {
        if (app.settings.getBoolean(Constants.Key.profileTip, true)) {
            app.editor.putBoolean(Constants.Key.profileTip, false).apply();
            new AlertDialog.Builder(this, R.style.Theme_Material_Dialog_Alert)
                    .setTitle(R.string.profile_manager_dialog)
                    .setMessage(R.string.profile_manager_dialog_content)
                    .setPositiveButton(R.string.gotcha, null)
                    .create().show();
        }
    }

    @SuppressLint("RestrictedApi")
    public void initFab() {
        menu = (FloatingActionMenu) findViewById(R.id.menu);
        menu.setClosedOnTouchOutside(true);
        AppCompatDrawableManager dm = AppCompatDrawableManager.get();
        FloatingActionButton manualAddFAB = (FloatingActionButton) findViewById(R.id.fab_manual_add);
        manualAddFAB.setImageDrawable(dm.getDrawable(this, R.drawable.ic_content_create));
        manualAddFAB.setOnClickListener(this);
        final FloatingActionButton qrcodeAddFAB = (FloatingActionButton) findViewById(R.id.fab_qrcode_add);
        qrcodeAddFAB.setImageDrawable(dm.getDrawable(this, R.drawable.ic_image_camera_alt));
        qrcodeAddFAB.setOnClickListener(this);
        FloatingActionButton nfcAddFAB = (FloatingActionButton) findViewById(R.id.fab_nfc_add);
        nfcAddFAB.setImageDrawable(dm.getDrawable(this, R.drawable.ic_device_nfc));
        nfcAddFAB.setOnClickListener(this);
        FloatingActionButton importAddFAB = (FloatingActionButton) findViewById(R.id.fab_import_add);
        importAddFAB.setImageDrawable(dm.getDrawable(this, R.drawable.ic_content_paste));
        importAddFAB.setOnClickListener(this);
        FloatingActionButton ssrsubAddFAB = (FloatingActionButton) findViewById(R.id.fab_ssr_sub);
        ssrsubAddFAB.setImageDrawable(dm.getDrawable(this, R.drawable.ic_rss));
        ssrsubAddFAB.setOnClickListener(this);
        menu.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
            @Override
            public void onMenuToggle(boolean opened) {
                if (opened) {
                    int visible = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) ? View.VISIBLE : View.GONE;
                    qrcodeAddFAB.setVisibility(visible);
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        updateNfcState();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        handleShareIntent(intent);
    }

    public void qrcodeScan() {
        try {
            Intent intent = new Intent("com.google.zxing.client.android.SCAN");
            intent.putExtra("SCAN_MODE", "QR_CODE_MODE");

            startActivityForResult(intent, REQUEST_QRCODE);
        } catch (Throwable e) {
            /*val dialog = new AlertDialog.Builder(this, R.style.Theme_Material_Dialog_Alert)
              .setTitle(R.string.scan_qrcode_install_title)
              .setPositiveButton(android.R.string.yes, ((_, _) => {
                  val marketUri = Uri.parse("market://details?id=com.google.zxing.client.android")
                  val marketIntent = new Intent(Intent.ACTION_VIEW, marketUri)
                  startActivity(marketIntent)
                }
              ): DialogInterface.OnClickListener)
              .setNeutralButton(R.string.scan_qrcode_direct_download_text, ((_, _) => {
                  val marketUri = Uri.parse("https://breakwa11.github.io/download/BarcodeScanner.apk")
                  val marketIntent = new Intent(Intent.ACTION_VIEW, marketUri)
                  startActivity(marketIntent)
                }
              ): DialogInterface.OnClickListener)
              .setNegativeButton(android.R.string.no, ((_, _) => finish()): DialogInterface.OnClickListener)
              .setMessage(R.string.scan_qrcode_install_text)
              .create()
            dialog.show()*/
            menu.toggle(false);
            startActivity(new Intent(this, ScannerActivity.class));
        }
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.fab_manual_add:
                menu.toggle(true);
                Profile profile = app.profileManager.createProfile();
                app.profileManager.updateProfile(profile);
                app.switchProfile(profile.id);
                finish();
                break;
            case R.id.fab_qrcode_add:
                menu.toggle(false);
                qrcodeScan();
                break;
            case R.id.fab_nfc_add:
                NfcAdd();
                break;
            case R.id.fab_import_add:
                clipboardImportAdd();
                break;
            case R.id.fab_ssr_sub:
                menu.toggle(true);
                ssrsubDialog();
                break;
            default:
                break;
        }
    }

    /**
     * add config by nfc
     */
    private void NfcAdd() {
        menu.toggle(true);
        AlertDialog dialog = new AlertDialog.Builder(ProfileManagerActivity.this, R.style.Theme_Material_Dialog_Alert)
                .setCancelable(true)
                .setPositiveButton(R.string.gotcha, null)
                .setTitle(R.string.add_profile_nfc_hint_title)
                .create();
        if (!isNfcBeamEnabled) {
            dialog.setMessage(getString(R.string.share_message_nfc_disabled));
            dialog.setButton(DialogInterface.BUTTON_NEUTRAL, getString(R.string.turn_on_nfc), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
                }
            });
        } else {
            dialog.setMessage(getString(R.string.add_profile_nfc_hint));
        }
        dialog.show();
    }

    /**
     * add config by clipboard
     */
    private void clipboardImportAdd() {
        menu.toggle(true);
        if (clipboard.hasPrimaryClip()) {
            List<Profile> profiles_normal = Parser.findAll(clipboard.getPrimaryClip().getItemAt(0).getText());
            List<Profile> profiles_ssr = Parser.findAll_ssr(clipboard.getPrimaryClip().getItemAt(0).getText());
            final List<Profile> profiles = new ArrayList<>();
            if (profiles_normal != null && !profiles_normal.isEmpty()) {
                profiles.addAll(profiles_normal);
            }
            if (profiles_ssr != null && !profiles_ssr.isEmpty()) {
                profiles.addAll(profiles_ssr);
            }

            if (!profiles.isEmpty()) {
                showUrlAddProfileDialog(profiles);
                return;
            }
        }
        ToastUtils.showShort(R.string.action_import_err);
    }

    /**
     * show url add profile dialog
     *
     * @param profiles
     */
    private void showUrlAddProfileDialog(final List<Profile> profiles) {
        AlertDialog dialog = new AlertDialog.Builder(this, R.style.Theme_Material_Dialog_Alert)
                .setTitle(R.string.add_profile_dialog)
                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        for (Profile item : profiles) {
                            app.profileManager.createProfile(item);
                        }
                    }
                })
                .setNeutralButton(R.string.dr, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        for (Profile item : profiles) {
                            app.profileManager.createProfileDr(item);
                        }
                    }
                })
                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                }).setMessage(makeString(profiles, "\n")).create();
        dialog.show();
    }

    public void ssrsubDialog() {
        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        View view = View.inflate(this, R.layout.layout_ssr_sub, null);
        Switch subAutoUpdateEnable = (Switch) view.findViewById(R.id.sw_ssr_sub_autoupdate_enable);

        // adding listener
        app.ssrsubManager.addSSRSubAddedListener(this);

        RecyclerView ssusubsList = (RecyclerView) view.findViewById(R.id.ssrsubList);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        ssusubsList.setLayoutManager(layoutManager);
        ssusubsList.setItemAnimator(new DefaultItemAnimator());
        ssusubsList.setAdapter(ssrsubAdapter);
        new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
                ItemTouchHelper.START | ItemTouchHelper.END) {
            @Override
            public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
                delSubDialog(viewHolder);
            }

            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                return true;
            }
        }).attachToRecyclerView(ssusubsList);

        if (prefs.getInt(Constants.Key.ssrsub_autoupdate, 0) == 1) {
            subAutoUpdateEnable.setChecked(true);
        }

        subAutoUpdateEnable.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                SharedPreferences.Editor editor = prefs.edit();
                if (isChecked) {
                    editor.putInt(Constants.Key.ssrsub_autoupdate, 1);
                } else {
                    editor.putInt(Constants.Key.ssrsub_autoupdate, 0);
                }
                editor.apply();
            }
        });

        new AlertDialog.Builder(this)
                .setTitle(getString(R.string.add_profile_methods_ssr_sub))
                .setPositiveButton(R.string.ssrsub_ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        confirmWithUpdateSub();
                    }
                })
                .setNegativeButton(android.R.string.no, null)
                .setNeutralButton(R.string.ssrsub_add, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        showAddSSRSubAddrDialog();
                    }
                })
                .setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        // remove listener
                        app.ssrsubManager.removeSSRSubAddedListener(ProfileManagerActivity.this);
                    }
                })
                .setView(view)
                .create()
                .show();
    }

    /**
     * del sub confirm dialog
     */
    private void delSubDialog(final RecyclerView.ViewHolder viewHolder) {
        final int index = viewHolder.getAdapterPosition();
        new AlertDialog.Builder(ProfileManagerActivity.this)
                .setTitle(getString(R.string.ssrsub_remove_tip_title))
                .setPositiveButton(R.string.ssrsub_remove_tip_direct, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ssrsubAdapter.remove(index);
                        app.ssrsubManager.delSSRSub(((SSRSubViewHolder) viewHolder).item.id);
                    }
                })
                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ssrsubAdapter.notifyDataSetChanged();
                    }
                })
                .setNeutralButton(R.string.ssrsub_remove_tip_delete, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        String group = ((SSRSubViewHolder) viewHolder).item.url_group;
                        List<Profile> deleteProfiles = app.profileManager.getAllProfilesByGroup(group);

                        for (Profile profile : deleteProfiles) {
                            if (profile.id != app.profileId()) {
                                app.profileManager.delProfile(profile.id);
                            }
                        }

                        int index = viewHolder.getAdapterPosition();
                        ssrsubAdapter.remove(index);
                        app.ssrsubManager.delSSRSub(((SSRSubViewHolder) viewHolder).item.id);

                        finish();
                        startActivity(new Intent(getIntent()));
                    }
                })
                .setMessage(getString(R.string.ssrsub_remove_tip))
                .setCancelable(false)
                .create()
                .show();
    }

    /**
     * config with update
     */
    private void confirmWithUpdateSub() {
        testProgressDialog = ProgressDialog.show(ProfileManagerActivity.this,
                getString(R.string.ssrsub_progres),
                getString(R.string.ssrsub_progres_text),
                false,
                true);

        // start update sub
        List<SSRSub> subs = app.ssrsubManager.getAllSSRSubs();
        SubUpdateHelper.instance().updateSub(subs, 0, new SubUpdateCallback() {
            @Override
            public void onFailed() {
                ToastUtils.showShort(R.string.ssrsub_error);
            }

            @Override
            public void onFinished() {
                if (testProgressDialog != null) {
                    testProgressDialog.dismiss();
                }

                finish();
                startActivity(new Intent(getIntent()));
            }
        });
    }

    private void showAddSSRSubAddrDialog() {
        final EditText urlAddEdit = new EditText(ProfileManagerActivity.this);
        new AlertDialog.Builder(ProfileManagerActivity.this)
                .setTitle(getString(R.string.ssrsub_add))
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // add ssr sub by url
                        String subUrl = urlAddEdit.getText().toString();
                        addSSRSubByUrl(subUrl);
                    }
                })
                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ssrsubDialog();
                    }
                })
                .setView(urlAddEdit)
                .create()
                .show();
    }

    /**
     * add ssr sub by url
     *
     * @param subUrl sub url
     */
    private void addSSRSubByUrl(final String subUrl) {
        if (!TextUtils.isEmpty(subUrl)) {
            // show progress dialog
            testProgressDialog = ProgressDialog.show(ProfileManagerActivity.this,
                    getString(R.string.ssrsub_progres),
                    getString(R.string.ssrsub_progres_text),
                    false,
                    true);

            // request sub content
            RequestHelper.instance().get(subUrl, new RequestCallback() {
                @Override
                public void onSuccess(int code, String response) {
                    SSRSub ssrsub = SubUpdateHelper.parseSSRSub(subUrl, response);
                    app.ssrsubManager.createSSRSub(ssrsub);
                }

                @Override
                public void onFailed(int code, String msg) {
                    ToastUtils.showShort(getString(R.string.ssrsub_error));
                }

                @Override
                public void onFinished() {
                    testProgressDialog.dismiss();
                    ssrsubDialog();
                }
            });
        } else {
            ssrsubDialog();
        }
    }

    private void updateNfcState() {
        isNfcAvailable = false;
        isNfcEnabled = false;
        isNfcBeamEnabled = false;
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter != null) {
            isNfcAvailable = true;
            if (nfcAdapter.isEnabled()) {
                isNfcEnabled = true;
                if (nfcAdapter.isNdefPushEnabled()) {
                    isNfcBeamEnabled = true;
                    nfcAdapter.setNdefPushMessageCallback(null, ProfileManagerActivity.this);
                }
            }
        }
    }

    private void handleShareIntent(Intent intent) {
        String sharedStr = null;
        String action = intent.getAction();
        if (Intent.ACTION_VIEW.equals(action)) {
            sharedStr = intent.getData().toString();
        } else if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
            Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            if (rawMsgs != null && rawMsgs.length > 0) {
                sharedStr = new String(((NdefMessage) rawMsgs[0]).getRecords()[0].getPayload());
            }
        }

        if (TextUtils.isEmpty(sharedStr)) {
            return;
        }

        final List<Profile> profiles = Utils.mergeList(Parser.findAll(sharedStr), Parser.findAll_ssr(sharedStr));

        if (profiles.isEmpty()) {
            finish();
            return;
        }
        AlertDialog dialog = new AlertDialog.Builder(this, R.style.Theme_Material_Dialog_Alert)
                .setTitle(R.string.add_profile_dialog)
                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        for (Profile profile : profiles) {
                            app.profileManager.createProfile(profile);
                        }
                    }
                })
                .setNeutralButton(R.string.dr, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        for (Profile profile : profiles) {
                            app.profileManager.createProfileDr(profile);
                        }
                    }
                })
                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                })
                .setMessage(makeString(profiles, "\n"))
                .create();
        dialog.show();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_QRCODE) {
            if (resultCode == RESULT_OK) {
                String contents = data.getStringExtra("SCAN_RESULT");
                if (TextUtils.isEmpty(contents)) {
                    return;
                }
                final List<Profile> profiles = Utils.mergeList(Parser.findAll(contents), Parser.findAll_ssr(contents));
                if (profiles.isEmpty()) {
                    finish();
                    return;
                }
                AlertDialog dialog = new AlertDialog.Builder(this, R.style.Theme_Material_Dialog_Alert)
                        .setTitle(R.string.add_profile_dialog)
                        .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                for (Profile profile : profiles) {
                                    app.profileManager.createProfile(profile);
                                }
                            }
                        })
                        .setNeutralButton(R.string.dr, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                for (Profile profile : profiles) {
                                    app.profileManager.createProfileDr(profile);
                                }
                            }
                        })
                        .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
