/*
 * Original work Copyright (C) 2013 The ChameleonOS Open Source Project
 * Modified work Copyright (C) 2013-2014 [email protected]
 *
 * 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.germainz.identiconizer;

import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
import android.provider.ContactsContract;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.NumberPicker;
import android.widget.TextView;
import android.widget.Toast;

import com.germainz.identiconizer.identicons.IdenticonFactory;
import com.germainz.identiconizer.services.ContactsObserverService;
import com.germainz.identiconizer.services.IdenticonCreationService;
import com.germainz.identiconizer.services.IdenticonRemovalService;
import com.larswerkman.holocolorpicker.ColorPicker;
import com.larswerkman.holocolorpicker.OpacityBar;
import com.larswerkman.holocolorpicker.SaturationBar;
import com.larswerkman.holocolorpicker.ValueBar;

import java.io.File;
import java.util.Locale;

public class IdenticonsSettings extends AppCompatPreferenceActivity implements OnPreferenceChangeListener {
    private static final int PERMISSIONS_REQUEST_CODE = 123;
    private static final String ACTION_SETTINGS_ABOUT = "com.germainz.identiconizer.SETTINGS_ABOUT";
    private SwitchPreference mEnabledPref;
    private ImageListPreference mStylePref;
    private SwitchPreference mSerifPref;
    private Preference mLengthPref;
    private Preference mBgColorPref;
    private Config mConfig;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActionBar bar = getSupportActionBar();
        String action = getIntent().getAction();
        if (action != null && action.equals(ACTION_SETTINGS_ABOUT)) {
            bar.setHomeButtonEnabled(true);
            bar.setDisplayHomeAsUpEnabled(true);
            bar.setDisplayShowTitleEnabled(true);
            bar.setTitle(R.string.about_title);
            addPreferencesFromResource(R.xml.settings_about);
            try {
                PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
                findPreference("version").setSummary(
                        String.format(Locale.ENGLISH, "%s (%d)", pInfo.versionName, pInfo.versionCode));
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return;
        }

        bar.setTitle(R.string.app_name);
        getPreferenceManager().setSharedPreferencesMode(MODE_PRIVATE);
        addPreferencesFromResource(R.xml.identicons_prefs);
        File prefsDir = new File(this.getApplicationInfo().dataDir, "shared_prefs");
        File prefsFile = new File(prefsDir, getPreferenceManager().getSharedPreferencesName() + ".xml");
        if (prefsFile.exists()) prefsFile.setReadable(true, false);
        mConfig = Config.getInstance(this);

        mEnabledPref = (SwitchPreference) findPreference(Config.PREF_ENABLED);
        mEnabledPref.setChecked(mConfig.isEnabled());
        if (mEnabledPref.isChecked() && !mConfig.isXposedModActive())
            startService(new Intent(this, ContactsObserverService.class));
        mEnabledPref.setOnPreferenceChangeListener(this);

        PreferenceScreen prefSet = getPreferenceScreen();
        mStylePref = (ImageListPreference) prefSet.findPreference(Config.PREF_STYLE);
        mStylePref.setOnPreferenceChangeListener(this);
        int style = mConfig.getIdenticonStyle();
        mStylePref.setValue(String.valueOf(style));
        updateStyleSummary(style);

        Preference startServicePref = findPreference(Config.PREF_CREATE);
        startServicePref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                startService(new Intent(IdenticonsSettings.this, IdenticonCreationService.class));
                return true;
            }
        });

        startServicePref = findPreference(Config.PREF_REMOVE);
        startServicePref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                startService(new Intent(IdenticonsSettings.this, IdenticonRemovalService.class));
                return true;
            }
        });

        Preference contactsListPref = findPreference(Config.PREF_CONTACTS_LIST);
        contactsListPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                startActivity(new Intent(IdenticonsSettings.this, ContactsListActivity.class));
                return true;
            }
        });

        final Preference sizePref = findPreference(Config.PREF_SIZE);
        final int identiconSize = mConfig.getIdenticonSize();
        sizePref.setSummary(identiconSize + " × " + identiconSize);
        sizePref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                final NumberPicker npView = new NumberPicker(IdenticonsSettings.this);

                final int minValue = 96;
                final int maxValue = getMaxContactPhotoSize();
                final int step = 16;
                String[] valueSet = new String[(maxValue - minValue) / step + 1];
                for (int i = minValue; i <= maxValue; i += step) {
                    valueSet[(i - minValue) / step] = i + " × " + i;
                }
                setDividerColor(npView, Color.LTGRAY);
                npView.setMinValue(0);
                npView.setMaxValue(valueSet.length - 1);
                npView.setDisplayedValues(valueSet);
                npView.setValue((mConfig.getIdenticonSize() - minValue) / step);

                new AlertDialog.Builder(IdenticonsSettings.this)
                        .setView(npView)
                        .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                int value = npView.getValue() * step + minValue;
                                mConfig.setIdenticonSize(value);
                                sizePref.setSummary(value + " × " + value);
                            }
                        })
                        .setNegativeButton(R.string.dialog_cancel, null)
                        .create().show();
                return true;
            }
        });

        mSerifPref = (SwitchPreference) findPreference(Config.PREF_SERIF);
        mSerifPref.setChecked(mConfig.isIdenticonSerif());
        if (mConfig.getIdenticonStyle() != IdenticonFactory.IDENTICON_STYLE_GMAIL)
            mSerifPref.setEnabled(false);
        mSerifPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                boolean serif = !mConfig.isIdenticonSerif();
                mConfig.setIdenticonSerif(serif);
                return true;
            }
        });

        mLengthPref = findPreference(Config.PREF_LENGTH);
        final int length = mConfig.getIdenticonLength();
        final String length_summary = " (Text may overflow when too long)";
        mLengthPref.setSummary(length + length_summary);
        mLengthPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                final NumberPicker npView = new NumberPicker(IdenticonsSettings.this);

                final int minValue = 1;
                final int maxValue = 5;
                setDividerColor(npView, Color.LTGRAY);
                npView.setMinValue(minValue);
                npView.setMaxValue(maxValue);
                npView.setValue((mConfig.getIdenticonLength()));

                new AlertDialog.Builder(IdenticonsSettings.this)
                        .setView(npView)
                        .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialogInterface, int i) {
                                int length = npView.getValue();
                                mConfig.setIdenticonLength(length);
                                mLengthPref.setSummary(length + length_summary);
                            }
                        })
                        .setNegativeButton(R.string.dialog_cancel, null)
                        .create().show();
                return true;
            }
        });
        if (mConfig.getIdenticonStyle() != IdenticonFactory.IDENTICON_STYLE_GMAIL)
            mLengthPref.setEnabled(false);

        mBgColorPref = findPreference(Config.PREF_BG_COLOR);
        if (mConfig.getIdenticonStyle() == IdenticonFactory.IDENTICON_STYLE_GMAIL)
            mBgColorPref.setEnabled(false);
        mBgColorPref.setSummary(colorIntToRGB(mConfig.getIdenticonBgColor()));
        mBgColorPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                LayoutInflater inflater = IdenticonsSettings.this.getLayoutInflater();
                View colorPickerView = inflater.inflate(R.layout.color_picker, (ViewGroup) findViewById(R.id.color_picker_root));

                final ColorPicker colorPicker = (ColorPicker) colorPickerView.findViewById(R.id.picker);
                SaturationBar saturationBar = (SaturationBar) colorPickerView.findViewById(R.id.saturationbar);
                ValueBar valueBar = (ValueBar) colorPickerView.findViewById(R.id.valuebar);
                final OpacityBar opacityBar = (OpacityBar) colorPickerView.findViewById(R.id.opacitybar);
                final TextView valueTextView = (TextView) colorPickerView.findViewById(R.id.value);
                Button applyButton = (Button) colorPickerView.findViewById(R.id.apply_value);

                colorPicker.addSaturationBar(saturationBar);
                colorPicker.addValueBar(valueBar);
                colorPicker.addOpacityBar(opacityBar);

                int savedColor = mConfig.getIdenticonBgColor();
                colorPicker.setColor(savedColor);
                valueTextView.setText(colorIntToRGB(mConfig.getIdenticonBgColor()));

                colorPicker.setOnColorChangedListener(new ColorPicker.OnColorChangedListener() {
                    @Override
                    public void onColorChanged(int color) {
                        valueTextView.setText(colorIntToRGB(color));
                    }
                });

                applyButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        String value = "#" + valueTextView.getText().toString();
                        try {
                            int color = Color.parseColor(value);
                            colorPicker.setColor(color);
                        } catch (IllegalArgumentException e) {
                            Toast.makeText(IdenticonsSettings.this, getString(R.string.invalid_color), Toast.LENGTH_SHORT).show();
                        }
                    }
                });

                AlertDialog alertDialog = new AlertDialog.Builder(IdenticonsSettings.this)
                        .setView(colorPickerView)
                        .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                dialogInterface.cancel();
                            }
                        })
                        .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                int color = colorPicker.getColor();
                                mConfig.setIdenticonBgColor(color);
                                mBgColorPref.setSummary(colorIntToRGB(color));
                                dialogInterface.dismiss();
                            }
                        })
                        .show();
                alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
                return true;
            }
        });

        checkPermissions();
    }

    private void checkPermissions() {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.WRITE_CONTACTS)) {
                new AlertDialog.Builder(this)
                        .setTitle("Permission required")
                        .setMessage("This app requires access to your contacts to function")
                        .setPositiveButton("Request permission", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ActivityCompat.requestPermissions(IdenticonsSettings.this,
                                        new String[]{Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS},
                                        PERMISSIONS_REQUEST_CODE);
                            }
                        })
                        .show();
            } else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS},
                        PERMISSIONS_REQUEST_CODE);
            }
        }

    }

    @Override
    public void onPause() {
        super.onPause();
        File prefsDir = new File(this.getApplicationInfo().dataDir, "shared_prefs");
        File prefsFile = new File(prefsDir, getPreferenceManager().getSharedPreferencesName() + ".xml");
        if (prefsFile.exists()) prefsFile.setReadable(true, false);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSIONS_REQUEST_CODE: {
                if (grantResults.length == 0 || grantResults[0] == PackageManager.PERMISSION_DENIED) {
                    Toast.makeText(this, "This app cannot function without the required permissions", Toast.LENGTH_LONG).show();
                    finish();
                }
            }
        }
    }

    public boolean onPreferenceChange(Preference preference, Object newValue) {
        if (preference == mEnabledPref) {
            mConfig.setEnabled((Boolean) newValue);
            if ((Boolean) newValue && !mConfig.isXposedModActive())
                startService(new Intent(this, ContactsObserverService.class));
            else if (!mConfig.isXposedModActive())
                stopService(new Intent(this, ContactsObserverService.class));
            return true;
        } else if (preference == mStylePref) {
            int style = Integer.valueOf((String) newValue);
            updateStyleSummary(style);
            mBgColorPref.setEnabled(style != IdenticonFactory.IDENTICON_STYLE_GMAIL);
            mSerifPref.setEnabled(style == IdenticonFactory.IDENTICON_STYLE_GMAIL);
            mLengthPref.setEnabled(style == IdenticonFactory.IDENTICON_STYLE_GMAIL);
            return true;
        }
        return false;
    }

    private void updateStyleSummary(int value) {
        mStylePref.setSummary(mStylePref.getEntries()[mStylePref.findIndexOfValue("" + value)]);
        mConfig.setIdenticonStyle(value);
    }

    public int getMaxContactPhotoSize() {
        final Uri uri = ContactsContract.DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI;
        final String[] projection = new String[]{ContactsContract.DisplayPhoto.DISPLAY_MAX_DIM};
        final Cursor c = this.getContentResolver().query(uri, projection, null, null, null);
        try {
            c.moveToFirst();
            return c.getInt(0);
        } finally {
            c.close();
        }
    }

    public String colorIntToRGB(int color) {
        return String.format("%08X", color);
    }

    private void setDividerColor(NumberPicker picker, int color) {
        java.lang.reflect.Field[] pickerFields = NumberPicker.class.getDeclaredFields();
        for (java.lang.reflect.Field pf : pickerFields) {
            if (pf.getName().equals("mSelectionDivider")) {
                pf.setAccessible(true);
                try {
                    ColorDrawable colorDrawable = new ColorDrawable(color);
                    pf.set(picker, colorDrawable);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (Resources.NotFoundException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
}