/*
 * Copyright (C) 2014 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.example.android.support.wearable.notifications;

import android.app.Activity;
import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.NotificationManagerCompat;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;

import java.util.Arrays;

/**
 * Main activity which posts a notification when resumed, and allows customization
 * of that notification via controls.
 */
public class MainActivity extends Activity implements Handler.Callback {
    private static final int MSG_POST_NOTIFICATIONS = 0;
    private static final long POST_NOTIFICATIONS_DELAY_MS = 200;

    private Handler mHandler;
    private Spinner mPresetSpinner;
    private EditText mTitleEditText;
    private EditText mTextEditText;
    private TextWatcher mTextChangedListener;
    private Spinner mPrioritySpinner;
    private Spinner mActionsSpinner;
    private CheckBox mIncludeLargeIconCheckbox;
    private CheckBox mLocalOnlyCheckbox;
    private CheckBox mIncludeContentIntentCheckbox;
    private CheckBox mVibrateCheckbox;
    private BackgroundPickers mBackgroundPickers;
    private int postedNotificationCount = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mHandler = new Handler(this);
        mTextChangedListener = new UpdateNotificationsOnTextChangeListener();

        initPresetSpinner();
        initTitleEditText();
        initTextEditText();
        initPrioritySpinner();
        initActionsSpinner();
        initIncludeLargeIconCheckbox();
        initLocalOnlyCheckbox();
        initIncludeContentIntentCheckbox();
        initVibrateCheckbox();
        initBackgroundPickers();

        NotificationPreset preset = NotificationPresets.PRESETS[
                mPresetSpinner.getSelectedItemPosition()];
        updateTextEditors(preset);
    }

    @Override
    protected void onResume() {
        super.onResume();
        updateNotifications(false /* cancelExisting */);
    }

    private void initPresetSpinner() {
        mPresetSpinner = (Spinner) findViewById(R.id.preset_spinner);
        mPresetSpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
                NotificationPresets.PRESETS));
        mPresetSpinner.post(new Runnable() {
            @Override
            public void run() {
                mPresetSpinner.setOnItemSelectedListener(new PresetSpinnerListener());
            }
        });
    }

    private void initTitleEditText() {
        mTitleEditText = (EditText) findViewById(R.id.title_editor);
    }

    private void initTextEditText() {
        mTextEditText = (EditText) findViewById(R.id.text_editor);
    }

    private void initPrioritySpinner() {
        mPrioritySpinner = (Spinner) findViewById(R.id.priority_spinner);
        mPrioritySpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
                PriorityPresets.PRESETS));
        mPrioritySpinner.setSelection(Arrays.asList(PriorityPresets.PRESETS)
                .indexOf(PriorityPresets.DEFAULT));
        mPrioritySpinner.post(new Runnable() {
            @Override
            public void run() {
                mPrioritySpinner.setOnItemSelectedListener(
                        new UpdateNotificationsOnItemSelectedListener(true /* cancelExisting */));
            }
        });
    }

    private void initActionsSpinner() {
        mActionsSpinner = (Spinner) findViewById(R.id.actions_spinner);
        mActionsSpinner.setAdapter(new NamedPresetSpinnerArrayAdapter(this,
                ActionsPresets.PRESETS));
        mActionsSpinner.post(new Runnable() {
            @Override
            public void run() {
                mActionsSpinner.setOnItemSelectedListener(
                        new UpdateNotificationsOnItemSelectedListener(false /* cancelExisting */));
            }
        });
    }

    private void initIncludeLargeIconCheckbox() {
        mIncludeLargeIconCheckbox = (CheckBox) findViewById(R.id.include_large_icon_checkbox);
        mIncludeLargeIconCheckbox.setOnCheckedChangeListener(
                new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
    }

    private void initLocalOnlyCheckbox() {
        mLocalOnlyCheckbox = (CheckBox) findViewById(R.id.local_only_checkbox);
        mLocalOnlyCheckbox.setOnCheckedChangeListener(
                new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
    }

    private void initIncludeContentIntentCheckbox() {
        mIncludeContentIntentCheckbox = (CheckBox) findViewById(
                R.id.include_content_intent_checkbox);
        mIncludeContentIntentCheckbox.setOnCheckedChangeListener(
                new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
    }

    private void initVibrateCheckbox() {
        mVibrateCheckbox = (CheckBox) findViewById(R.id.vibrate_checkbox);
        mVibrateCheckbox.setOnCheckedChangeListener(
                new UpdateNotificationsOnCheckedChangeListener(false /* cancelExisting */));
    }

    private void initBackgroundPickers() {
        mBackgroundPickers = new BackgroundPickers(
                (ViewGroup) findViewById(R.id.background_pickers),
                new BackgroundPickerListener());
    }

    private void updateTextEditors(NotificationPreset preset) {
        mTitleEditText.setText(getString(preset.titleResId));
        mTextEditText.setText(getString(preset.textResId));
        if (preset == NotificationPresets.BASIC) {
            findViewById(R.id.title_edit_field).setVisibility(View.VISIBLE);
            mTitleEditText.addTextChangedListener(mTextChangedListener);
            findViewById(R.id.text_edit_field).setVisibility(View.VISIBLE);
            mTextEditText.addTextChangedListener(mTextChangedListener);
        } else {
            findViewById(R.id.title_edit_field).setVisibility(View.GONE);
            mTitleEditText.removeTextChangedListener(mTextChangedListener);
            findViewById(R.id.text_edit_field).setVisibility(View.GONE);
            mTextEditText.removeTextChangedListener(mTextChangedListener);
        }
    }

    /**
     * Begin to re-post the sample notification(s).
     */
    private void updateNotifications(boolean cancelExisting) {
        // Disable messages to skip notification deleted messages during cancel.
        sendBroadcast(new Intent(NotificationIntentReceiver.ACTION_DISABLE_MESSAGES)
                .setClass(this, NotificationIntentReceiver.class));

        if (cancelExisting) {
            // Cancel all existing notifications to trigger fresh-posting behavior: For example,
            // switching from HIGH to LOW priority does not cause a reordering in Notification Shade.
            NotificationManagerCompat.from(this).cancelAll();
            postedNotificationCount = 0;

            // Post the updated notifications on a delay to avoid a cancel+post race condition
            // with notification manager.
            mHandler.removeMessages(MSG_POST_NOTIFICATIONS);
            mHandler.sendEmptyMessageDelayed(MSG_POST_NOTIFICATIONS, POST_NOTIFICATIONS_DELAY_MS);
        } else {
            postNotifications();
        }
    }

    /**
     * Post the sample notification(s) using current options.
     */
    private void postNotifications() {
        sendBroadcast(new Intent(NotificationIntentReceiver.ACTION_ENABLE_MESSAGES)
                .setClass(this, NotificationIntentReceiver.class));

        NotificationPreset preset = NotificationPresets.PRESETS[
                mPresetSpinner.getSelectedItemPosition()];
        CharSequence titlePreset = mTitleEditText.getText();
        CharSequence textPreset = mTextEditText.getText();
        PriorityPreset priorityPreset = PriorityPresets.PRESETS[
                mPrioritySpinner.getSelectedItemPosition()];
        ActionsPreset actionsPreset = ActionsPresets.PRESETS[
                mActionsSpinner.getSelectedItemPosition()];
        if (preset.actionsRequired() && actionsPreset == ActionsPresets.NO_ACTIONS_PRESET) {
            // If actions are required, but the no-actions preset was selected, change presets.
            actionsPreset = ActionsPresets.SINGLE_ACTION_PRESET;
            mActionsSpinner.setSelection(Arrays.asList(ActionsPresets.PRESETS).indexOf(
                    actionsPreset), true);
        }
        NotificationPreset.BuildOptions options = new NotificationPreset.BuildOptions(
                titlePreset,
                textPreset,
                priorityPreset,
                actionsPreset,
                mIncludeLargeIconCheckbox.isChecked(),
                mLocalOnlyCheckbox.isChecked(),
                mIncludeContentIntentCheckbox.isChecked(),
                mVibrateCheckbox.isChecked(),
                mBackgroundPickers.getRes());
        Notification[] notifications = preset.buildNotifications(this, options);

        // Post new notifications
        for (int i = 0; i < notifications.length; i++) {
            NotificationManagerCompat.from(this).notify(i, notifications[i]);
        }
        // Cancel any that are beyond the current count.
        for (int i = notifications.length; i < postedNotificationCount; i++) {
            NotificationManagerCompat.from(this).cancel(i);
        }
        postedNotificationCount = notifications.length;
    }

    @Override
    public boolean handleMessage(Message message) {
        switch (message.what) {
            case MSG_POST_NOTIFICATIONS:
                postNotifications();
                return true;
        }
        return false;
    }

    private class PresetSpinnerListener implements AdapterView.OnItemSelectedListener {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            NotificationPreset preset = NotificationPresets.PRESETS[position];
            mBackgroundPickers.generatePickers(preset.countBackgroundPickersRequired());
            updateTextEditors(preset);
            updateNotifications(false /* cancelExisting */);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {
        }
    }

    private class UpdateNotificationsOnTextChangeListener implements TextWatcher {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }

        @Override
        public void afterTextChanged(Editable s) {
            updateNotifications(false /* cancelExisting */);
        }
    }

    private class UpdateNotificationsOnItemSelectedListener
            implements AdapterView.OnItemSelectedListener {
        private final boolean mCancelExisting;

        public UpdateNotificationsOnItemSelectedListener(boolean cancelExisting) {
            mCancelExisting = cancelExisting;
        }
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            updateNotifications(mCancelExisting);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {
        }
    }

    private class UpdateNotificationsOnCheckedChangeListener
            implements CompoundButton.OnCheckedChangeListener {
        private final boolean mCancelExisting;

        public UpdateNotificationsOnCheckedChangeListener(boolean cancelExisting) {
            mCancelExisting = cancelExisting;
        }

        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
            updateNotifications(mCancelExisting);
        }
    }

    private class BackgroundPickerListener
            implements BackgroundPickers.OnBackgroundPickersChangedListener {
        @Override
        public void onBackgroundPickersChanged(BackgroundPickers pickers) {
            updateNotifications(false /* cancelExisting */);
        }
    }

    private class NamedPresetSpinnerArrayAdapter extends ArrayAdapter<NamedPreset> {
        public NamedPresetSpinnerArrayAdapter(Context context, NamedPreset[] presets) {
            super(context, R.layout.simple_spinner_item, presets);
        }

        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            TextView view = (TextView) super.getDropDownView(position, convertView, parent);
            view.setText(getString(getItem(position).nameResId));
            return view;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            TextView view = (TextView) getLayoutInflater().inflate(
                    android.R.layout.simple_spinner_item, parent, false);
            view.setText(getString(getItem(position).nameResId));
            return view;
        }
    }
}
