/*
 * Copyright (C) 2011 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.browser;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Message;
import android.preference.PreferenceManager;
import android.webkit.WebSettings.AutoFillProfile;

import java.util.concurrent.CountDownLatch;

public class AutofillHandler {

    private AutoFillProfile mAutoFillProfile;
    // Default to zero. In the case no profile is set up, the initial
    // value will come from the AutoFillSettingsFragment when the user
    // creates a profile. Otherwise, we'll read the ID of the last used
    // profile from the prefs db.
    private int mAutoFillActiveProfileId;
    private static final int NO_AUTOFILL_PROFILE_SET = 0;

    private CountDownLatch mLoaded = new CountDownLatch(1);
    private Context mContext;

    public AutofillHandler(Context context) {
        mContext = context;
    }

    /**
     * Load settings from the browser app's database. It is performed in
     * an AsyncTask as it involves plenty of slow disk IO.
     * NOTE: Strings used for the preferences must match those specified
     * in the various preference XML files.
     */
    public void asyncLoadFromDb() {
        // Run the initial settings load in an AsyncTask as it hits the
        // disk multiple times through SharedPreferences and SQLite. We
        // need to be certain though that this has completed before we start
        // to load pages though, so in the worst case we will block waiting
        // for it to finish in BrowserActivity.onCreate().
         new LoadFromDb().start();
    }

    public void waitForLoad() {
        try {
            mLoaded.await();
        } catch (InterruptedException e) {}
    }

    private class LoadFromDb extends Thread {

        @Override
        public void run() {
            SharedPreferences p =
                    PreferenceManager.getDefaultSharedPreferences(mContext);

            // Read the last active AutoFill profile id.
            mAutoFillActiveProfileId = p.getInt(
                    PreferenceKeys.PREF_AUTOFILL_ACTIVE_PROFILE_ID,
                    mAutoFillActiveProfileId);

            // Load the autofill profile data from the database. We use a database separate
            // to the browser preference DB to make it easier to support multiple profiles
            // and switching between them.
            AutoFillProfileDatabase autoFillDb = AutoFillProfileDatabase.getInstance(mContext);
            Cursor c = autoFillDb.getProfile(mAutoFillActiveProfileId);

            if (c.getCount() > 0) {
                c.moveToFirst();

                String fullName = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.FULL_NAME));
                String email = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.EMAIL_ADDRESS));
                String company = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.COMPANY_NAME));
                String addressLine1 = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.ADDRESS_LINE_1));
                String addressLine2 = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.ADDRESS_LINE_2));
                String city = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.CITY));
                String state = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.STATE));
                String zip = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.ZIP_CODE));
                String country = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.COUNTRY));
                String phone = c.getString(c.getColumnIndex(
                        AutoFillProfileDatabase.Profiles.PHONE_NUMBER));
                mAutoFillProfile = new AutoFillProfile(mAutoFillActiveProfileId,
                        fullName, email, company, addressLine1, addressLine2, city,
                        state, zip, country, phone);
            }
            c.close();
            autoFillDb.close();

            mLoaded.countDown();
        }
    }

    public void setAutoFillProfile(AutoFillProfile profile, Message msg) {
        int profileId = NO_AUTOFILL_PROFILE_SET;
        if (profile != null) {
            profileId = profile.getUniqueId();
            // Update the AutoFill DB with the new profile.
            new SaveProfileToDbTask(msg).execute(profile);
        } else {
            // Delete the current profile.
            if (mAutoFillProfile != null) {
                new DeleteProfileFromDbTask(msg).execute(mAutoFillProfile.getUniqueId());
            }
        }
        // Make sure we set mAutoFillProfile before calling setActiveAutoFillProfileId
        // Calling setActiveAutoFillProfileId will trigger an update of WebViews
        // which will expect a new profile to be set
        mAutoFillProfile = profile;
        setActiveAutoFillProfileId(profileId);
    }

    public AutoFillProfile getAutoFillProfile() {
        return mAutoFillProfile;
    }

    private void setActiveAutoFillProfileId(int activeProfileId) {
        mAutoFillActiveProfileId = activeProfileId;
        Editor ed = PreferenceManager.
            getDefaultSharedPreferences(mContext).edit();
        ed.putInt(PreferenceKeys.PREF_AUTOFILL_ACTIVE_PROFILE_ID, activeProfileId);
        ed.apply();
    }

    private abstract class AutoFillProfileDbTask<T> extends AsyncTask<T, Void, Void> {
        AutoFillProfileDatabase mAutoFillProfileDb;
        Message mCompleteMessage;

        public AutoFillProfileDbTask(Message msg) {
            mCompleteMessage = msg;
        }

        @Override
        protected void onPostExecute(Void result) {
            if (mCompleteMessage != null) {
                mCompleteMessage.sendToTarget();
            }
            mAutoFillProfileDb.close();
        }

        @Override
        abstract protected Void doInBackground(T... values);
    }


    private class SaveProfileToDbTask extends AutoFillProfileDbTask<AutoFillProfile> {
        public SaveProfileToDbTask(Message msg) {
            super(msg);
        }

        @Override
        protected Void doInBackground(AutoFillProfile... values) {
            mAutoFillProfileDb = AutoFillProfileDatabase.getInstance(mContext);
            assert mAutoFillActiveProfileId != NO_AUTOFILL_PROFILE_SET;
            AutoFillProfile newProfile = values[0];
            mAutoFillProfileDb.addOrUpdateProfile(mAutoFillActiveProfileId, newProfile);
            return null;
        }
    }

    private class DeleteProfileFromDbTask extends AutoFillProfileDbTask<Integer> {
        public DeleteProfileFromDbTask(Message msg) {
            super(msg);
        }

        @Override
        protected Void doInBackground(Integer... values) {
            mAutoFillProfileDb = AutoFillProfileDatabase.getInstance(mContext);
            int id = values[0];
            assert  id > 0;
            mAutoFillProfileDb.dropProfile(id);
            return null;
        }
    }
}