/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.messaging.ui.appsettings;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.provider.Telephony;
import androidx.core.app.NavUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.messaging.R;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.sms.ApnDatabase;
import com.android.messaging.sms.BugleApnSettingsLoader;
import com.android.messaging.ui.BugleActionBarActivity;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.OsUtil;
import com.android.messaging.util.PhoneUtils;

public class ApnSettingsActivity extends BugleActionBarActivity {
    private static final int DIALOG_RESTORE_DEFAULTAPN = 1001;

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

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        // Display the fragment as the main content.
        final ApnSettingsFragment fragment = new ApnSettingsFragment();
        fragment.setSubId(getIntent().getIntExtra(UIIntents.UI_INTENT_EXTRA_SUB_ID,
                ParticipantData.DEFAULT_SELF_SUB_ID));
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, fragment)
                .commit();
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpFromSameTask(this);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        if (id == DIALOG_RESTORE_DEFAULTAPN) {
            ProgressDialog dialog = new ProgressDialog(this);
            dialog.setMessage(getResources().getString(R.string.restore_default_apn));
            dialog.setCancelable(false);
            return dialog;
        }
        return null;
    }

    public static class ApnSettingsFragment extends PreferenceFragment implements
            Preference.OnPreferenceChangeListener {
        public static final String EXTRA_POSITION = "position";

        public static final String APN_ID = "apn_id";

        private static final String[] APN_PROJECTION = {
            Telephony.Carriers._ID,         // 0
            Telephony.Carriers.NAME,        // 1
            Telephony.Carriers.APN,         // 2
            Telephony.Carriers.TYPE         // 3
        };
        private static final int ID_INDEX    = 0;
        private static final int NAME_INDEX  = 1;
        private static final int APN_INDEX   = 2;
        private static final int TYPES_INDEX = 3;

        private static final int MENU_NEW = Menu.FIRST;
        private static final int MENU_RESTORE = Menu.FIRST + 1;

        private static final int EVENT_RESTORE_DEFAULTAPN_START = 1;
        private static final int EVENT_RESTORE_DEFAULTAPN_COMPLETE = 2;

        private static boolean mRestoreDefaultApnMode;

        private RestoreApnUiHandler mRestoreApnUiHandler;
        private RestoreApnProcessHandler mRestoreApnProcessHandler;
        private HandlerThread mRestoreDefaultApnThread;

        private String mSelectedKey;

        private static final ContentValues sCurrentNullMap;
        private static final ContentValues sCurrentSetMap;

        private UserManager mUm;

        private boolean mUnavailable;
        private int mSubId;

        static {
            sCurrentNullMap = new ContentValues(1);
            sCurrentNullMap.putNull(Telephony.Carriers.CURRENT);

            sCurrentSetMap = new ContentValues(1);
            sCurrentSetMap.put(Telephony.Carriers.CURRENT, "2");    // 2 for user-selected APN,
            // 1 for Bugle-selected APN
        }

        private SQLiteDatabase mDatabase;

        public void setSubId(final int subId) {
            mSubId = subId;
        }

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

            mDatabase = ApnDatabase.getApnDatabase().getWritableDatabase();

            if (OsUtil.isAtLeastL()) {
                mUm = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
                if (!mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
                    setHasOptionsMenu(true);
                }
            } else {
                setHasOptionsMenu(true);
            }
        }

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

            final ListView lv = (ListView) getView().findViewById(android.R.id.list);
            TextView empty = (TextView) getView().findViewById(android.R.id.empty);
            if (empty != null) {
                empty.setText(R.string.apn_settings_not_available);
                lv.setEmptyView(empty);
            }

            if (OsUtil.isAtLeastL() &&
                    mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
                mUnavailable = true;
                setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity()));
                return;
            }

            addPreferencesFromResource(R.xml.apn_settings);

            lv.setItemsCanFocus(true);
        }

        @Override
        public void onResume() {
            super.onResume();

            if (mUnavailable) {
                return;
            }

            if (!mRestoreDefaultApnMode) {
                fillList();
            }
        }

        @Override
        public void onPause() {
            super.onPause();

            if (mUnavailable) {
                return;
            }
        }

        @Override
        public void onDestroy() {
            super.onDestroy();

            if (mRestoreDefaultApnThread != null) {
                mRestoreDefaultApnThread.quit();
            }
        }

        private void fillList() {
            final String mccMnc = PhoneUtils.getMccMncString(PhoneUtils.get(mSubId).getMccMnc());

            new AsyncTask<Void, Void, Cursor>() {
                @Override
                protected Cursor doInBackground(Void... params) {
                    String selection = Telephony.Carriers.NUMERIC + " =?";
                    String[] selectionArgs = new String[]{ mccMnc };
                    final Cursor cursor = mDatabase.query(ApnDatabase.APN_TABLE, APN_PROJECTION,
                            selection, selectionArgs, null, null, null, null);
                    return cursor;
                }

                @Override
                protected void onPostExecute(Cursor cursor) {
                    if (cursor != null) {
                        try {
                            PreferenceGroup apnList = (PreferenceGroup)
                                    findPreference(getString(R.string.apn_list_pref_key));
                            apnList.removeAll();

                            mSelectedKey = BugleApnSettingsLoader.getFirstTryApn(mDatabase, mccMnc);
                            while (cursor.moveToNext()) {
                                String name = cursor.getString(NAME_INDEX);
                                String apn = cursor.getString(APN_INDEX);
                                String key = cursor.getString(ID_INDEX);
                                String type = cursor.getString(TYPES_INDEX);

                                if (BugleApnSettingsLoader.isValidApnType(type,
                                        BugleApnSettingsLoader.APN_TYPE_MMS)) {
                                    ApnPreference pref = new ApnPreference(getActivity());
                                    pref.setKey(key);
                                    pref.setTitle(name);
                                    pref.setSummary(apn);
                                    pref.setPersistent(false);
                                    pref.setOnPreferenceChangeListener(ApnSettingsFragment.this);
                                    pref.setSelectable(true);

                                    // Turn on the radio button for the currently selected APN. If
                                    // there is no selected APN, don't select an APN.
                                    if ((mSelectedKey != null && mSelectedKey.equals(key))) {
                                        pref.setChecked();
                                    }
                                    apnList.addPreference(pref);
                                }
                            }
                        } finally {
                            cursor.close();
                        }
                    }
                }
            }.execute((Void) null);
        }

        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            if (!mUnavailable) {
                menu.add(0, MENU_NEW, 0,
                        getResources().getString(R.string.menu_new_apn))
                        .setIcon(R.drawable.ic_add_white)
                        .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
                menu.add(0, MENU_RESTORE, 0,
                        getResources().getString(R.string.menu_restore_default_apn))
                        .setIcon(android.R.drawable.ic_menu_upload);
            }

            super.onCreateOptionsMenu(menu, inflater);
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
                case MENU_NEW:
                    addNewApn();
                    return true;

                case MENU_RESTORE:
                    restoreDefaultApn();
                    return true;
            }
            return super.onOptionsItemSelected(item);
        }

        private void addNewApn() {
            startActivity(UIIntents.get().getApnEditorIntent(getActivity(), null, mSubId));
        }

        @Override
        public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
                Preference preference) {
            startActivity(
                    UIIntents.get().getApnEditorIntent(getActivity(), preference.getKey(), mSubId));
            return true;
        }

        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            if (newValue instanceof String) {
                setSelectedApnKey((String) newValue);
            }

            return true;
        }

        // current=2 means user selected APN
        private static final String UPDATE_SELECTION = Telephony.Carriers.CURRENT + " =?";
        private static final String[] UPDATE_SELECTION_ARGS = new String[] { "2" };
        private void setSelectedApnKey(final String key) {
            mSelectedKey = key;

            // Make database changes not on the UI thread
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    // null out the previous "current=2" APN
                    mDatabase.update(ApnDatabase.APN_TABLE, sCurrentNullMap,
                            UPDATE_SELECTION, UPDATE_SELECTION_ARGS);

                    // set the new "current" APN (2)
                    String selection = Telephony.Carriers._ID + " =?";
                    String[] selectionArgs = new String[]{ key };

                    mDatabase.update(ApnDatabase.APN_TABLE, sCurrentSetMap,
                            selection, selectionArgs);
                    return null;
                }
            }.execute((Void) null);
        }

        private boolean restoreDefaultApn() {
            getActivity().showDialog(DIALOG_RESTORE_DEFAULTAPN);
            mRestoreDefaultApnMode = true;

            if (mRestoreApnUiHandler == null) {
                mRestoreApnUiHandler = new RestoreApnUiHandler();
            }

            if (mRestoreApnProcessHandler == null ||
                    mRestoreDefaultApnThread == null) {
                mRestoreDefaultApnThread = new HandlerThread(
                        "Restore default APN Handler: Process Thread");
                mRestoreDefaultApnThread.start();
                mRestoreApnProcessHandler = new RestoreApnProcessHandler(
                        mRestoreDefaultApnThread.getLooper(), mRestoreApnUiHandler);
            }

            mRestoreApnProcessHandler.sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START);
            return true;
        }

        private class RestoreApnUiHandler extends Handler {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case EVENT_RESTORE_DEFAULTAPN_COMPLETE:
                        fillList();
                        getPreferenceScreen().setEnabled(true);
                        mRestoreDefaultApnMode = false;
                        final Activity activity = getActivity();
                        activity.dismissDialog(DIALOG_RESTORE_DEFAULTAPN);
                        Toast.makeText(activity, getResources().getString(
                                        R.string.restore_default_apn_completed), Toast.LENGTH_LONG)
                                            .show();
                        break;
                }
            }
        }

        private class RestoreApnProcessHandler extends Handler {
            private Handler mCachedRestoreApnUiHandler;

            public RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) {
                super(looper);
                this.mCachedRestoreApnUiHandler = restoreApnUiHandler;
            }

            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case EVENT_RESTORE_DEFAULTAPN_START:
                        ApnDatabase.forceBuildAndLoadApnTables();
                        mCachedRestoreApnUiHandler.sendEmptyMessage(
                                EVENT_RESTORE_DEFAULTAPN_COMPLETE);
                        break;
                }
            }
        }
    }
}
