package jp.sourceforge.tamanegisoul.sa.action;

import java.util.Date;

import jp.sourceforge.tamanegisoul.sa.R;
import jp.sourceforge.tamanegisoul.sa.util.AppAccountManager;
import jp.sourceforge.tamanegisoul.sa.util.AppAlarmListener;
import jp.sourceforge.tamanegisoul.sa.util.AppAlarmManager;
import jp.sourceforge.tamanegisoul.sa.util.AppUncaughtExceptionHandler;
import jp.sourceforge.tamanegisoul.sa.util.DBHelper;
import jp.sourceforge.tamanegisoul.sa.util.ErrorReporter;
import jp.sourceforge.tamanegisoul.sa.util.FormatUtils;
import jp.sourceforge.tamanegisoul.sa.util.LogUtil;
import jp.sourceforge.tamanegisoul.sa.util.PreferenceUtils;
import android.accounts.Account;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Service;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.provider.CalendarContract;
import android.provider.CalendarContract.Calendars;
import android.provider.CalendarContract.Events;
import android.view.Gravity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;

/**
 * メインのActivity
 */
public class DashboardActivity extends Activity implements OnSharedPreferenceChangeListener {

    /** スケジュール一覧のアダプタ */
    private CursorAdapter mScheduleListAdapter;
    /** 現在スケジュール表示中のアカウント。選択アカウント変更を検知するために… */
    private Account mCurrentAccount;

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        LogUtil.d("DashboardActivity.onSharedPreferenceChanged(key->%s)", key);
        if (key.equals(PreferenceUtils.KEY_ACCOUNT)) {
            validateView();
        } else if (key.equals(PreferenceUtils.KEY_ALARM_TIME) || key.equals(PreferenceUtils.KEY_IS_PROGRESS_SNOOZE)) {
            // ウィジェットを更新(ウィジェットをリスナーにして更新したいが、うまくいかないのでここで更新)
            SimpleWidgetProvider.validateView(this.getApplicationContext());
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Thread.setDefaultUncaughtExceptionHandler(new AppUncaughtExceptionHandler(getApplicationContext()));

        // エラー情報があったら何もしない(セーフモード)で起動
        // エラー無しなら通常起動
        if (!ErrorReporter.isErrorOccured()) {
            setContentView(R.layout.dashboard);

            // このActivityがメインなのでサービスを起動
            startService(new Intent(getApplicationContext(), CalendarObserverService.class));
            bindService(new Intent(getApplicationContext(), CalendarObserverService.class), new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    LogUtil.d("DashboardActivity.ServiceConnection.onServiceConnected()");
                    // カレンダーの更新リスナー
                    ((CalendarObserverService.LocalBinder) service).getService().addOnCalendarChangeListener(new CalendarObserverService.OnCalendarChangeListener() {
                        @Override
                        public void onChange() {
                            LogUtil.d("DashboardActivity.CalendarObserverService.OnCalendarChangeListener.onChange()");
                            validateView();
                        }
                    });
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {
                }
            }, Service.BIND_AUTO_CREATE);

            // アラームの更新リスナー
            AppAlarmManager.getInstance(this).registerAppAlarmListener(new AppAlarmListener() {
                @Override
                public void alarmSet(Date date) {
                    LogUtil.d("DashboardActivity.AppAlarmListener.onChange(%s)", date);
                    validateView();
                }
            });

            // 設定の更新リスナー
            // 匿名クラスにすると呼ばれないので注意
            PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);

            // 強制同期ボタン
            ((Button) findViewById(R.id.sync_button)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Account account = AppAccountManager.getInstance(DashboardActivity.this).getAccount();
                    if (account != null) {
                        Toast t = Toast.makeText(DashboardActivity.this, "しばらくすると同期が完了します", Toast.LENGTH_SHORT);
                        t.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0);
                        t.show();
                        ContentResolver.requestSync(account, DBHelper.URI_CALENDAR.getAuthority(), new Bundle());
                    }
                }
            });
            // カレンダー表示ボタン
            ((Button) findViewById(R.id.calendar_button)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com/calendar")));
                }
            });
            // スヌーズ解除ボタン
            ((Button) findViewById(R.id.cancel_snooze_button)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ((Button) findViewById(R.id.cancel_snooze_button)).setVisibility(View.GONE);
                    // 次のアラームを設定
                    AppAlarmManager.getInstance(DashboardActivity.this).cancelSnooze();
                    AppAlarmManager.getInstance(DashboardActivity.this).refreshAlarm();
                }
            });
            // 予定一覧
            ((ListView) findViewById(R.id.schedule_list)).setEmptyView(findViewById(R.id.schedule_list_is_empty));
            ((ListView) findViewById(R.id.schedule_list)).setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    // カレンダーイベント編集を起動
                    long itemId = ((ListView) parent).getAdapter().getItemId(position);
                    Intent i = new Intent(parent.getContext(), CalendarEventActivity.class);
                    i.putExtra(DBHelper.C_CALENDAR_ID, itemId);
                    startActivity(i);
                }
            });
            // イベント追加ボタン
            ((Button) findViewById(R.id.add_event_button)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startActivity(new Intent(DashboardActivity.this, CalendarEventActivity.class));
                }
            });
            // 設定ボタン
            ((Button) findViewById(R.id.preference_button)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startActivity(new Intent(DashboardActivity.this, AppPreferenceActivity.class));
                }
            });
            // 祝日一覧ボタン
            ((Button) findViewById(R.id.holiday_list_button)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startActivity(new Intent(DashboardActivity.this, HolidayListActivity.class));
                }
            });
            // ヘルプボタン
            ((Button) findViewById(R.id.help_button)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    createHelpDialog().show();
                }
            });
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (ErrorReporter.isErrorOccured()) {
            // 前回エラー発生してたらエラー情報送信ダイアログ表示
            ErrorReporter.showConfirmDialog(this);
        } else {
            // 未設定なら設定画面を強制表示
            if (PreferenceUtils.getString(this, PreferenceUtils.KEY_WEEKDAY_TIME) == null && PreferenceUtils.getString(this, PreferenceUtils.KEY_HOLIDAY_TIME) == null) {
                // アラーム時刻が未設定
                showPreferenceNotSetDialog("アラーム時刻を設定してください");
            } else if (PreferenceUtils.getRingtone(this) == null && PreferenceUtils.getVibratorPattern(this) == null) {
                // 音、バイブレーターが未設定
                showPreferenceNotSetDialog("音またはバイブレーターを設定してください");
            }

            validateView();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mScheduleListAdapter != null)
            mScheduleListAdapter.getCursor().close();
        // 設定の更新リスナー
        PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).unregisterOnSharedPreferenceChangeListener(this);
    }

    private void validateView() {
        // アカウント未設定なら同期ボタン・イベント追加ボタンを無効化
        ((Button) findViewById(R.id.sync_button)).setEnabled(PreferenceUtils.getString(this, PreferenceUtils.KEY_ACCOUNT) != null);
        ((Button) findViewById(R.id.add_event_button)).setEnabled(PreferenceUtils.getString(this, PreferenceUtils.KEY_ACCOUNT) != null);
        // 次回アラーム表示更新
        String nextAlarm = FormatUtils.formatDateTimeDisplay(AppAlarmManager.getInstance(this).getAlarmTime());
        if(nextAlarm == null)
            nextAlarm = "アラーム未設定";
        ((TextView) findViewById(R.id.next_alarm_text)).setText(nextAlarm);
        // 今日は何の日表示
        ((TextView) findViewById(R.id.day_notation)).setText(getTodayDescription());
        // スヌーズ中なら解除ボタン表示
        int visibility = PreferenceUtils.isProgressSnooze(this) ? View.VISIBLE : View.GONE;
        ((Button) findViewById(R.id.cancel_snooze_button)).setVisibility(visibility);
        // スケジュール一覧を更新
        refreshScheduleListAdapter();
        if (mScheduleListAdapter != null)
            mScheduleListAdapter.getCursor().requery();
        // 最新同期時刻
        ((TextView) findViewById(R.id.schedule_sync_time)).setText(FormatUtils.formatDateTimeDisplay(PreferenceUtils.getDateTime(this, PreferenceUtils.KEY_LATEST_SYNC_TIME)));
    }

    /**
     * @return 今日の日付を表わす文字列（祝日ならその名称）
     */
    private String getTodayDescription() {
        Date today = new Date();
        String description = "";
        SQLiteDatabase db = null;
        try {
            db = new DBHelper(this).getReadableDatabase();
            Cursor c = db.query(DBHelper.T_HOLIDAY, null, DBHelper.C_HOLIDAY_DATE + "=?", new String[] { FormatUtils.formatDate(today) }, null, null, null);
            if (c.moveToFirst())
                description = c.getString(c.getColumnIndex(DBHelper.C_HOLIDAY_NAME));
        } finally {
            if (db != null)
                db.close();
        }
        return String.format("今日は%s%sです", FormatUtils.formatDateDisplay(today), description);
    }

    /**
     * 未設定ダイアログを表示する。
     * 
     * @param message
     */
    private void showPreferenceNotSetDialog(String message) {
        AlertDialog dialog = new AlertDialog.Builder(this).create();
        dialog.setMessage(message);
        dialog.setButton(AlertDialog.BUTTON_POSITIVE, "設定する", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                startActivity(new Intent(DashboardActivity.this, AppPreferenceActivity.class));
            }
        });
        dialog.show();
    }

    /**
     * @return ヘルプ表示ダイアログ
     */
    private AlertDialog createHelpDialog() {
        String versionName;
        try {
            PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_META_DATA);
            versionName = packageInfo.versionName;
        } catch (NameNotFoundException e) {
            versionName = "不明";
        }
        AlertDialog alertDialog = new AlertDialog.Builder(DashboardActivity.this).create();
        alertDialog.setMessage(String.format("Installed ver.%s\nサポートページに移動しますか？", versionName));
        alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // サポートページに移動
                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://sourceforge.jp/projects/schedulealarm/wiki/FrontPage")));
            }
        });
        alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, getResources().getString(android.R.string.cancel), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        return alertDialog;
    }

    /**
     * スケジュール一覧のアダプタを更新する。
     */
    private void refreshScheduleListAdapter() {
        Account account = AppAccountManager.getInstance(this).getAccount();
        if (account != null) {
            // アカウント設定済みなら更新する
            if (mCurrentAccount != account) {
                // アカウントが変更されていたら更新する
                mCurrentAccount = account;
                // 現在時刻か7日以内の+alarm,-alarmを含むイベントを取得する
                Cursor cursor;
                if (Build.VERSION.SDK_INT > 14) {
                    cursor = getContentResolver().query(DBHelper.URI_CALENDAR_EVENTS, new String[] { 
                    		CalendarContract.Events._ID, CalendarContract.Events.TITLE, CalendarContract.Events.DTSTART, CalendarContract.Events.ALL_DAY },
                    		Calendars.ACCOUNT_NAME + "=? and dtstart>=strftime('%s', datetime('now','start of day')) || '000' and dtstart<=strftime('%s', datetime(datetime('now','start of day')),'7 days') || '000' and (title like '%+alarm' or title like '%-alarm' or title like '%#alarm')",
                            new String[] { account.name }, "dtstart");
                } else if (Build.VERSION.SDK_INT < 8) {
                    cursor = getContentResolver().query(DBHelper.URI_CALENDAR_EVENTS, new String[] { "_id", "title", "dtstart", "allDay" },
                            "Calendars._sync_account=? and dtstart>=strftime('%s', datetime('now','start of day')) || '000' and dtstart<=strftime('%s', datetime(datetime('now','start of day')),'7 days') || '000' and (title like '%+alarm' or title like '%-alarm' or title like '%#alarm')",
                            new String[] { account.name }, "dtstart");
                } else {
                    cursor = getContentResolver().query(DBHelper.URI_CALENDAR_EVENTS, new String[] { "_id", "title", "dtstart", "allDay" },
                            "_sync_account=? and dtstart>=strftime('%s', datetime('now','start of day')) || '000' and dtstart<=strftime('%s', datetime(datetime('now','start of day')),'7 days') || '000' and (title like '%+alarm' or title like '%-alarm' or title like '%#alarm')",
                            new String[] { account.name }, "dtstart");
                }
                if (mScheduleListAdapter == null) {
                    // アダプタ未作成なら作成
                    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursor, new String[] { "title", "dtstart" }, new int[] { android.R.id.text1, android.R.id.text2 });
                    adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
                        @Override
                        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
                            String text = null;
                            if (view.getId() == android.R.id.text1) {
                                // タイトル表示
                                text = cursor.getString(1);
                            } else if (view.getId() == android.R.id.text2) {
                                // 日時表示
                                Date d = new Date(cursor.getLong(2));
                                text = cursor.getString(1).contains("-alarm") ? FormatUtils.formatDateDisplay(d) : FormatUtils.formatDateTimeDisplay(d);
                            }
                            ((TextView) view).setText(text);
                            return true;
                        }
                    });
                    ((ListView) findViewById(R.id.schedule_list)).setAdapter(adapter);
                } else {
                    // アダプタ作成済なら更新
                    mScheduleListAdapter.changeCursor(cursor);
                }
            }
        }
    }
}
