/*
 * 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.AlertDialog;
import android.app.Dialog;
import android.content.ContentValues;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.provider.Telephony;
import androidx.core.app.NavUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

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.PhoneUtils;

public class ApnEditorActivity extends BugleActionBarActivity {
    private static final int ERROR_DIALOG_ID = 0;
    private static final String ERROR_MESSAGE_KEY = "error_msg";
    private ApnEditorFragment mApnEditorFragment;

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

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        // Display the fragment as the main content.
        mApnEditorFragment = new ApnEditorFragment();
        mApnEditorFragment.setSubId(getIntent().getIntExtra(UIIntents.UI_INTENT_EXTRA_SUB_ID,
                ParticipantData.DEFAULT_SELF_SUB_ID));
        getFragmentManager().beginTransaction()
            .replace(android.R.id.content, mApnEditorFragment)
            .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, Bundle args) {

        if (id == ERROR_DIALOG_ID) {
            String msg = args.getString(ERROR_MESSAGE_KEY);

            return new AlertDialog.Builder(this)
                .setPositiveButton(android.R.string.ok, null)
                .setMessage(msg)
                .create();
        }

        return super.onCreateDialog(id);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK: {
                if (mApnEditorFragment.validateAndSave(false)) {
                    finish();
                }
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
        super.onPrepareDialog(id, dialog);

        if (id == ERROR_DIALOG_ID) {
            final String msg = args.getString(ERROR_MESSAGE_KEY);

            if (msg != null) {
                ((AlertDialog) dialog).setMessage(msg);
            }
        }
    }

    public static class ApnEditorFragment extends PreferenceFragment implements
        SharedPreferences.OnSharedPreferenceChangeListener {

        private static final String SAVED_POS = "pos";

        private static final int MENU_DELETE = Menu.FIRST;
        private static final int MENU_SAVE = Menu.FIRST + 1;
        private static final int MENU_CANCEL = Menu.FIRST + 2;

        private EditTextPreference mMmsProxy;
        private EditTextPreference mMmsPort;
        private EditTextPreference mName;
        private EditTextPreference mMmsc;
        private EditTextPreference mMcc;
        private EditTextPreference mMnc;
        private static String sNotSet;

        private String mCurMnc;
        private String mCurMcc;

        private Cursor mCursor;
        private boolean mNewApn;
        private boolean mFirstTime;
        private String mCurrentId;

        private int mSubId;

        /**
         * Standard projection for the interesting columns of a normal note.
         */
        private static final String[] sProjection = new String[] {
            Telephony.Carriers._ID,         // 0
            Telephony.Carriers.NAME,        // 1
            Telephony.Carriers.MMSC,        // 2
            Telephony.Carriers.MCC,         // 3
            Telephony.Carriers.MNC,         // 4
            Telephony.Carriers.NUMERIC,     // 5
            Telephony.Carriers.MMSPROXY,    // 6
            Telephony.Carriers.MMSPORT,     // 7
            Telephony.Carriers.TYPE,        // 8
        };

        private static final int ID_INDEX = 0;
        private static final int NAME_INDEX = 1;
        private static final int MMSC_INDEX = 2;
        private static final int MCC_INDEX = 3;
        private static final int MNC_INDEX = 4;
        private static final int NUMERIC_INDEX = 5;
        private static final int MMSPROXY_INDEX = 6;
        private static final int MMSPORT_INDEX = 7;
        private static final int TYPE_INDEX = 8;

        private SQLiteDatabase mDatabase;

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

        }

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

            addPreferencesFromResource(R.xml.apn_editor);

            setHasOptionsMenu(true);

            sNotSet = getResources().getString(R.string.apn_not_set);
            mName = (EditTextPreference) findPreference("apn_name");
            mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy");
            mMmsPort = (EditTextPreference) findPreference("apn_mms_port");
            mMmsc = (EditTextPreference) findPreference("apn_mmsc");
            mMcc = (EditTextPreference) findPreference("apn_mcc");
            mMnc = (EditTextPreference) findPreference("apn_mnc");

            final Intent intent = getActivity().getIntent();

            mFirstTime = savedInstanceState == null;
            mCurrentId = intent.getStringExtra(UIIntents.UI_INTENT_EXTRA_APN_ROW_ID);
            mNewApn = mCurrentId == null;

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

            if (mNewApn) {
                fillUi();
            } else {
                // Do initial query not on the UI thread
                new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        if (mCurrentId != null) {
                            String selection = Telephony.Carriers._ID + " =?";
                            String[] selectionArgs = new String[]{ mCurrentId };
                            mCursor = mDatabase.query(ApnDatabase.APN_TABLE, sProjection, selection,
                                    selectionArgs, null, null, null, null);
                        }
                        return null;
                    }

                    @Override
                    protected void onPostExecute(Void result) {
                        if (mCursor == null) {
                            getActivity().finish();
                            return;
                        }
                        mCursor.moveToFirst();

                        fillUi();
                    }
                }.execute((Void) null);
            }
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            if (mCursor != null) {
                mCursor.close();
                mCursor = null;
            }
        }

        @Override
        public void onResume() {
            super.onResume();
            getPreferenceScreen().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
        }

        @Override
        public void onPause() {
            getPreferenceScreen().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
            super.onPause();
        }

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

        private void fillUi() {
            if (mNewApn) {
                mMcc.setText(null);
                mMnc.setText(null);
                String numeric = PhoneUtils.get(mSubId).getSimOperatorNumeric();
                // MCC is first 3 chars and then in 2 - 3 chars of MNC
                if (numeric != null && numeric.length() > 4) {
                    // Country code
                    String mcc = numeric.substring(0, 3);
                    // Network code
                    String mnc = numeric.substring(3);
                    // Auto populate MNC and MCC for new entries, based on what SIM reports
                    mMcc.setText(mcc);
                    mMnc.setText(mnc);
                    mCurMnc = mnc;
                    mCurMcc = mcc;
                }
                mName.setText(null);
                mMmsProxy.setText(null);
                mMmsPort.setText(null);
                mMmsc.setText(null);
            } else if (mFirstTime) {
                mFirstTime = false;
                // Fill in all the values from the db in both text editor and summary
                mName.setText(mCursor.getString(NAME_INDEX));
                mMmsProxy.setText(mCursor.getString(MMSPROXY_INDEX));
                mMmsPort.setText(mCursor.getString(MMSPORT_INDEX));
                mMmsc.setText(mCursor.getString(MMSC_INDEX));
                mMcc.setText(mCursor.getString(MCC_INDEX));
                mMnc.setText(mCursor.getString(MNC_INDEX));
            }

            mName.setSummary(checkNull(mName.getText()));
            mMmsProxy.setSummary(checkNull(mMmsProxy.getText()));
            mMmsPort.setSummary(checkNull(mMmsPort.getText()));
            mMmsc.setSummary(checkNull(mMmsc.getText()));
            mMcc.setSummary(checkNull(mMcc.getText()));
            mMnc.setSummary(checkNull(mMnc.getText()));
        }

        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            super.onCreateOptionsMenu(menu, inflater);
            // If it's a new APN, then cancel will delete the new entry in onPause
            if (!mNewApn) {
                menu.add(0, MENU_DELETE, 0, R.string.menu_delete_apn)
                    .setIcon(R.drawable.ic_delete_small_dark);
            }
            menu.add(0, MENU_SAVE, 0, R.string.menu_save_apn)
                .setIcon(android.R.drawable.ic_menu_save);
            menu.add(0, MENU_CANCEL, 0, R.string.menu_discard_apn_change)
                .setIcon(android.R.drawable.ic_menu_close_clear_cancel);
        }

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

                case MENU_SAVE:
                    if (validateAndSave(false)) {
                        getActivity().finish();
                    }
                    return true;

                case MENU_CANCEL:
                    getActivity().finish();
                    return true;

                case android.R.id.home:
                    getActivity().onBackPressed();
                    return true;
            }
            return super.onOptionsItemSelected(item);
        }

        @Override
        public void onSaveInstanceState(Bundle icicle) {
            super.onSaveInstanceState(icicle);
            if (validateAndSave(true) && mCursor != null) {
                icicle.putInt(SAVED_POS, mCursor.getInt(ID_INDEX));
            }
        }

        /**
         * Check the key fields' validity and save if valid.
         * @param force save even if the fields are not valid, if the app is
         *        being suspended
         * @return true if the data was saved
         */
        private boolean validateAndSave(boolean force) {
            final String name = checkNotSet(mName.getText());
            final String mcc = checkNotSet(mMcc.getText());
            final String mnc = checkNotSet(mMnc.getText());

            if (getErrorMsg() != null && !force) {
                final Bundle bundle = new Bundle();
                bundle.putString(ERROR_MESSAGE_KEY, getErrorMsg());
                getActivity().showDialog(ERROR_DIALOG_ID, bundle);
                return false;
            }

            // Make database changes not on the UI thread
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    ContentValues values = new ContentValues();

                    // Add a placeholder name "Untitled", if the user exits the screen without
                    // adding a name but entered other information worth keeping.
                    values.put(Telephony.Carriers.NAME, name.length() < 1 ?
                            getResources().getString(R.string.untitled_apn) : name);
                    values.put(Telephony.Carriers.MMSPROXY, checkNotSet(mMmsProxy.getText()));
                    values.put(Telephony.Carriers.MMSPORT, checkNotSet(mMmsPort.getText()));
                    values.put(Telephony.Carriers.MMSC, checkNotSet(mMmsc.getText()));

                    values.put(Telephony.Carriers.TYPE, BugleApnSettingsLoader.APN_TYPE_MMS);

                    values.put(Telephony.Carriers.MCC, mcc);
                    values.put(Telephony.Carriers.MNC, mnc);

                    values.put(Telephony.Carriers.NUMERIC, mcc + mnc);

                    if (mCurMnc != null && mCurMcc != null) {
                        if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) {
                            values.put(Telephony.Carriers.CURRENT, 1);
                        }
                    }

                    if (mNewApn) {
                        mDatabase.insert(ApnDatabase.APN_TABLE, null, values);
                    } else {
                        // update the APN
                        String selection = Telephony.Carriers._ID + " =?";
                        String[] selectionArgs = new String[]{ mCurrentId };
                        int updated = mDatabase.update(ApnDatabase.APN_TABLE, values,
                                selection, selectionArgs);
                    }
                    return null;
                }
            }.execute((Void) null);

            return true;
        }

        private void deleteApn() {
            // Make database changes not on the UI thread
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    // delete the APN
                    String where = Telephony.Carriers._ID + " =?";
                    String[] whereArgs = new String[]{ mCurrentId };

                    mDatabase.delete(ApnDatabase.APN_TABLE, where, whereArgs);
                    return null;
                }
            }.execute((Void) null);

            getActivity().finish();
        }

        private String checkNull(String value) {
            if (value == null || value.length() == 0) {
                return sNotSet;
            } else {
                return value;
            }
        }

        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            Preference pref = findPreference(key);
            if (pref != null) {
                pref.setSummary(checkNull(sharedPreferences.getString(key, "")));
            }
        }

        private String getErrorMsg() {
            String errorMsg = null;

            String name = checkNotSet(mName.getText());
            String mcc = checkNotSet(mMcc.getText());
            String mnc = checkNotSet(mMnc.getText());

            if (name.length() < 1) {
                errorMsg = getString(R.string.error_apn_name_empty);
            } else if (mcc.length() != 3) {
                errorMsg = getString(R.string.error_mcc_not3);
            } else if ((mnc.length() & 0xFFFE) != 2) {
                errorMsg = getString(R.string.error_mnc_not23);
            }

            return errorMsg;
        }

        private String checkNotSet(String value) {
            if (value == null || value.equals(sNotSet)) {
                return "";
            } else {
                return value;
            }
        }
    }
}
