/*
 * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
 *
 * 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 net.micode.notes.model;

import android.appwidget.AppWidgetManager;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;

import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.tool.ResourceParser.NoteBgResources;


public class WorkingNote {
    // Note for the working note
    private Note mNote;
    // Note Id
    private long mNoteId;
    // Note content
    private String mContent;
    // Note mode
    private int mMode;

    private long mAlertDate;

    private long mModifiedDate;

    private int mBgColorId;

    private int mWidgetId;

    private int mWidgetType;

    private long mFolderId;

    private Context mContext;

    private static final String TAG = "WorkingNote";

    private boolean mIsDeleted;

    private NoteSettingChangedListener mNoteSettingStatusListener;

    public static final String[] DATA_PROJECTION = new String[] {
            DataColumns.ID,
            DataColumns.CONTENT,
            DataColumns.MIME_TYPE,
            DataColumns.DATA1,
            DataColumns.DATA2,
            DataColumns.DATA3,
            DataColumns.DATA4,
    };

    public static final String[] NOTE_PROJECTION = new String[] {
            NoteColumns.PARENT_ID,
            NoteColumns.ALERTED_DATE,
            NoteColumns.BG_COLOR_ID,
            NoteColumns.WIDGET_ID,
            NoteColumns.WIDGET_TYPE,
            NoteColumns.MODIFIED_DATE
    };

    private static final int DATA_ID_COLUMN = 0;

    private static final int DATA_CONTENT_COLUMN = 1;

    private static final int DATA_MIME_TYPE_COLUMN = 2;

    private static final int DATA_MODE_COLUMN = 3;

    private static final int NOTE_PARENT_ID_COLUMN = 0;

    private static final int NOTE_ALERTED_DATE_COLUMN = 1;

    private static final int NOTE_BG_COLOR_ID_COLUMN = 2;

    private static final int NOTE_WIDGET_ID_COLUMN = 3;

    private static final int NOTE_WIDGET_TYPE_COLUMN = 4;

    private static final int NOTE_MODIFIED_DATE_COLUMN = 5;

    // New note construct
    private WorkingNote(Context context, long folderId) {
        mContext = context;
        mAlertDate = 0;
        mModifiedDate = System.currentTimeMillis();
        mFolderId = folderId;
        mNote = new Note();
        mNoteId = 0;
        mIsDeleted = false;
        mMode = 0;
        mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
    }

    // Existing note construct
    private WorkingNote(Context context, long noteId, long folderId) {
        mContext = context;
        mNoteId = noteId;
        mFolderId = folderId;
        mIsDeleted = false;
        mNote = new Note();
        loadNote();
    }

    /**
     * 加载笔记数据
     */
    private void loadNote() {
        Cursor cursor = mContext.getContentResolver().query(
                ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
                null, null);
    
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); // 获取笔记所属文件夹 ID
                mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); // 获取笔记背景颜色 ID
                mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); // 获取笔记小部件 ID
                mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); // 获取笔记小部件类型
                mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); // 获取笔记提醒日期
                mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); // 获取笔记修改日期
            }
            cursor.close();
        } else {
            Log.e(TAG, "No note with id:" + mNoteId);
            throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
        }
        loadNoteData(); // 加载笔记数据
    }
    
    /**
     * 加载笔记的具体数据
     */
    private void loadNoteData() {
        Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
                DataColumns.NOTE_ID + "=?", new String[] {
                    String.valueOf(mNoteId)
                }, null);
    
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                do {
                    String type = cursor.getString(DATA_MIME_TYPE_COLUMN); // 获取数据类型
                    if (DataConstants.NOTE.equals(type)) {
                        mContent = cursor.getString(DATA_CONTENT_COLUMN); // 获取笔记文本内容
                        mMode = cursor.getInt(DATA_MODE_COLUMN); // 获取笔记模式
                        mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); // 设置笔记文本数据 ID
                    } else if (DataConstants.CALL_NOTE.equals(type)) {
                        mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); // 设置通话数据 ID
                    } else {
                        Log.d(TAG, "Wrong note type with type:" + type); // 记录错误的数据类型
                    }
                } while (cursor.moveToNext());
            }
            cursor.close();
        } else {
            Log.e(TAG, "No data with id:" + mNoteId);
            throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId);
        }
    }

    /**
     * 创建一个空的笔记对象
     *
     * @param context          上下文对象
     * @param folderId         笔记所属文件夹 ID
     * @param widgetId         笔记小部件 ID
     * @param widgetType       笔记小部件类型
     * @param defaultBgColorId 默认背景颜色 ID
     * @return 创建的空白笔记对象
     */
    public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
            int widgetType, int defaultBgColorId) {
        WorkingNote note = new WorkingNote(context, folderId); // 创建一个工作笔记对象
        note.setBgColorId(defaultBgColorId); // 设置默认背景颜色 ID
        note.setWidgetId(widgetId); // 设置小部件 ID
        note.setWidgetType(widgetType); // 设置小部件类型
        return note;
    }
    
    /**
     * 根据 ID 从数据库加载笔记对象
     *
     * @param context 上下文对象
     * @param id      笔记 ID
     * @return 加载的笔记对象
     */
    public static WorkingNote load(Context context, long id) {
        return new WorkingNote(context, id, 0); // 根据 ID 创建工作笔记对象
    }
    
    /**
     * 保存笔记对象到数据库
     *
     * @return 保存是否成功
     */
    public synchronized boolean saveNote() {
        if (isWorthSaving()) {
            if (!existInDatabase()) { // 如果笔记不存在于数据库中
                if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
                    Log.e(TAG, "Create new note fail with id:" + mNoteId);
                    return false; // 创建新笔记失败
                }
            }
            mNote.syncNote(mContext, mNoteId); // 同步笔记到数据库
            if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
                    && mWidgetType != Notes.TYPE_WIDGET_INVALIDE
                    && mNoteSettingStatusListener != null) {
                mNoteSettingStatusListener.onWidgetChanged(); // 更新小部件状态
            }
            return true; // 保存成功
        } else {
            return false; // 未值得保存，保存失败
        }
    }

    /**
     * 检查笔记是否存在于数据库中
     * @return 笔记是否存在于数据库中
     */
    public boolean existInDatabase() {
        return mNoteId > 0;
    }
    
    /**
     * 检查笔记是否值得保存
     * 笔记不值得保存的情况包括：已被标记删除、（不存在于数据库且内容为空）、（存在于数据库且没有本地修改）
     * @return 笔记是否值得保存
     */
    private boolean isWorthSaving() {
        if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
                || (existInDatabase() && !mNote.isLocalModified())) {
            return false; // 不值得保存
        } else {
            return true; // 值得保存
        }
    }
    
    /**
     * 设置笔记设置状态改变监听器
     *
     * @param l 笔记设置状态改变监听器
     */
    public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
        mNoteSettingStatusListener = l; // 设置笔记设置状态改变监听器
    }

    public void setAlertDate(long date, boolean set) {
/*
这段代码实现了一个名为 `setAlertDate()` 的公共方法。以下是对该方法的解释：
1. 首先，方法接受两个参数，一个是日期（`date`），一个是布尔值（`set`），用于设置提醒日期和是否已设置提醒的状态。
2. 首先，检查传入的日期值是否与当前的提醒日期（`mAlertDate`）相等。如果不相等，执行以下操作：
   - 将传入的日期值（`date`）赋值给 `mAlertDate`，更新提醒日期。
   - 通过调用 `mNote` 对象的 `setNoteValue()` 方法，将提醒日期（`mAlertDate`）
   以字符串形式保存到 `NoteColumns.ALERTED_DATE` 字段中，即更新笔记中的提醒日期。
3. 接下来，检查是否已设置笔记设置状态的监听器（`mNoteSettingStatusListener`）。如果监听器不为 `null`，执行以下操作：
   - 通过调用 `mNoteSettingStatusListener` 的 `onClockAlertChanged()` 方法，
   传递提醒日期（`date`）和设置状态（`set`）给监听器，以便通知监听器提醒状态的改变。
4. 方法执行完毕。
综上，该方法用于设置笔记的提醒日期和状态，并更新相应的数据。在设置提醒日期时，如果传入的日期与当前提醒日期不相等，
则更新提醒日期，并更新笔记的 `NoteColumns.ALERTED_DATE` 字段。同时，如果设置了提醒状态监听器，
则调用该监听器的 `onClockAlertChanged()` 方法，传递提醒日期和设置状态，以便通知监听器提醒状态的改变。
 */
        if (date != mAlertDate) {
            mAlertDate = date;
            mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate));
        }
        if (mNoteSettingStatusListener != null) {
            mNoteSettingStatusListener.onClockAlertChanged(date, set);
        }
    }

    public void markDeleted(boolean mark) {
        mIsDeleted = mark;
        if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
                && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
                mNoteSettingStatusListener.onWidgetChanged();
        }
    }

    public void setBgColorId(int id) {
/*
 * 这段代码定义了一个名为 `setBgColorId()` 的方法，
 * 用于设置背景颜色的 ID。
以下是对该方法的解释：
1. 方法接受一个整型参数 `id`，表示要设置的背景颜色的 ID。
2. 首先，判断传入的 `id` 是否与当前的背景颜色 ID `mBgColorId` 不相等，
即判断是否有新的背景颜色需要设置。
3. 如果传入的 `id` 与当前 `mBgColorId` 不相等，执行以下操作：
   - 将 `mBgColorId` 更新为传入的 `id`，即将背景颜色 ID 更新为新的值。
   - 如果存在 `mNoteSettingStatusListener` 监听器对象（非空），
   则调用 `mNoteSettingStatusListener` 的 `onBackgroundColorChanged()` 方法，
   以通知监听器背景颜色已更改。
   - 通过调用 `mNote` 对象的 `setNoteValue()` 方法，
   向 `mNote` 对象设置背景颜色的值。这个方法可能是将背景颜色 ID 存储到数据库或持久化存储中。
4. 该方法结束。
综上，`setBgColorId()` 方法的功能是根据传入的参数设置背景颜色的 ID，
并触发相应的事件通知和持久化存储。
 */
        if (id != mBgColorId) {
            mBgColorId = id;
            if (mNoteSettingStatusListener != null) {
                mNoteSettingStatusListener.onBackgroundColorChanged();
            }
            mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
        }
    }

    public void setCheckListMode(int mode) {
/*
 * 这段代码定义了一个名为 `setCheckListMode()` 的方法，用于设置检查清单模式。
以下是对该方法的解释：
1. 方法接受一个整型参数 `mode`，表示要设置的检查清单模式。
2. 首先，判断传入的 `mode` 是否与当前的模式 `mMode` 不相等，
即判断是否有新的模式需要设置。
3. 如果传入的 `mode` 与当前 `mMode` 不相等，执行以下操作：
   - 如果存在 `mNoteSettingStatusListener` 监听器对象（非空），
   则调用 `mNoteSettingStatusListener` 的 `onCheckListModeChanged()` 方法，传入当前模式 `mMode` 和新模式 `mode`，以通知监听器模式已更改。
   - 将 `mMode` 更新为传入的 `mode`，即将模式值更新为新的值。
   - 通过调用 `mNote` 对象的 `setTextData()` 方法，
   向 `mNote` 对象设置检查清单模式的值。这个方法可能是将模式值存储到数据库或持久化存储中。
4. 该方法结束。
综上，`setCheckListMode()` 方法的功能是根据传入的参数设置检查清单的模式，
并触发相应的事件通知和持久化存储。
 */
        if (mMode != mode) {
            if (mNoteSettingStatusListener != null) {
                mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
            }
            mMode = mode;
            mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
        }
    }

    /**
     * 设置小部件类型
     * @param type 小部件类型
     */
    public void setWidgetType(int type) {
        if (type != mWidgetType) {
            mWidgetType = type;
            mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); // 设置笔记值中的小部件类型
        }
    }
    /**
     * 设置小部件 ID
     * @param id 小部件 ID
     */
    public void setWidgetId(int id) {
        if (id != mWidgetId) {
            mWidgetId = id;
            mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); // 设置笔记值中的小部件 ID
        }
    }
    /**
     * 设置工作文本
     * @param text 文本内容
     */
    public void setWorkingText(String text) {
        if (!TextUtils.equals(mContent, text)) {
            mContent = text;
            mNote.setTextData(DataColumns.CONTENT, mContent); // 设置笔记的文本数据
        }
    }
    /**
     * 转换为通话记录类型的笔记
     * @param phoneNumber 电话号码
     * @param callDate 通话日期
     */
    public void convertToCallNote(String phoneNumber, long callDate) {
        mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); // 设置通话数据中的通话日期
        mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); // 设置通话数据中的电话号码
        mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); // 设置笔记值中的父文件夹 ID
    }

    public boolean hasClockAlert() {
        return (mAlertDate > 0 ? true : false);
    }

    public String getContent() {
        return mContent;
    }

    public long getAlertDate() {
        return mAlertDate;
    }

    public long getModifiedDate() {
        return mModifiedDate;
    }

    public int getBgColorResId() {
        return NoteBgResources.getNoteBgResource(mBgColorId);
    }

    public int getBgColorId() {
        return mBgColorId;
    }

    public int getTitleBgResId() {
        return NoteBgResources.getNoteTitleBgResource(mBgColorId);
    }

    public int getCheckListMode() {
        return mMode;
    }

    public long getNoteId() {
        return mNoteId;
    }

    public long getFolderId() {
        return mFolderId;
    }

    public int getWidgetId() {
        return mWidgetId;
    }

    public int getWidgetType() {
        return mWidgetType;
    }

    public interface NoteSettingChangedListener {
        /**
         * Called when the background color of current note has just changed
         */
        void onBackgroundColorChanged();

        /**
         * Called when user set clock
         */
        void onClockAlertChanged(long date, boolean set);

        /**
         * Call when user create note from widget
         */
        void onWidgetChanged();

        /**
         * Call when switch between check list mode and normal mode
         * @param oldMode is previous mode before change
         * @param newMode is new mode
         */
        void onCheckListModeChanged(int oldMode, int newMode);
    }
}
