/*
 * 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.gtask.data;

import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;

import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import net.micode.notes.tool.ResourceParser;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

// SqlNote.java

/**
 * 这个类用于操作笔记数据的 SQLite 数据库操作
 */
public class SqlNote {
    private static final String TAG = SqlNote.class.getSimpleName();  // 用于在日志中标识类名的常量

    private static final int INVALID_ID = -99999;  // 无效 ID，表示数据库中不存在的 ID

    // 定义了笔记表的所有列名，用于查询数据库时使用
    public static final String[] PROJECTION_NOTE = new String[]{
            NoteColumns.ID, NoteColumns.ALERTED_DATE, ... // 这里省略了一些列名
    NoteColumns.VERSION
};

// 定义了各列在查询结果中的索引位置
public static final int ID_COLUMN = 0;
public static final int ALERTED_DATE_COLUMN = 1;
// ... 其他列的索引位置

// 下面是一系列私有成员变量，代表了一个笔记对象的各个属性
// 这些变量用于在对象内部保存笔记的各种信息
private Context mContext;
private ContentResolver mContentResolver;
private boolean mIsCreate;
private long mId;
private long mAlertDate;
private int mBgColorId;
private long mCreatedDate;
private int mHasAttachment;
private long mModifiedDate;
private long mParentId;
private String mSnippet;
private int mType;
private int mWidgetId;
private int mWidgetType;
private long mOriginParent;
private long mVersion;
private ContentValues mDiffNoteValues;
private ArrayList<SqlData> mDataList;

/**
 * 构造函数，初始化笔记对象的各个属性
 */
public SqlNote(Context context) {
        mContext = context;
        mContentResolver = context.getContentResolver();
        mIsCreate = true;
        mId = INVALID_ID;
        mAlertDate = 0;
        mBgColorId = ResourceParser.getDefaultBgId(context);
        mCreatedDate = System.currentTimeMillis();
        mHasAttachment = 0;
        mModifiedDate = System.currentTimeMillis();
        mParentId = 0;
        mSnippet = "";
        mType = Notes.TYPE_NOTE;
        mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
        mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
        mOriginParent = 0;
        mVersion = 0;
        mDiffNoteValues = new ContentValues();
        mDataList = new ArrayList<SqlData>();
        }

/**
 * 从 Cursor 中加载笔记数据的构造函数
 */
public SqlNote(Context context, Cursor c) {
        mContext = context;
        mContentResolver = context.getContentResolver();
        mIsCreate = false;
        loadFromCursor(c);
        mDataList = new ArrayList<SqlData>();
        if (mType == Notes.TYPE_NOTE)
        loadDataContent();
        mDiffNoteValues = new ContentValues();
        }

/**
 * 从数据库中加载指定 ID 的笔记数据的构造函数
 */
public SqlNote(Context context, long id) {
        mContext = context;
        mContentResolver = context.getContentResolver();
        mIsCreate = false;
        loadFromCursor(id);
        mDataList = new ArrayList<SqlData>();
        if (mType == Notes.TYPE_NOTE)
        loadDataContent();
        mDiffNoteValues = new ContentValues();
        }

/**
 * 从 Cursor 中加载笔记数据
 */
private void loadFromCursor(Cursor c) {
        // 根据 Cursor 中的数据加载笔记对象的各个属性
        }

/**
 * 从数据库中加载指定 ID 的笔记数据
 */
private void loadFromCursor(long id) {
        Cursor c = null;
        try {
        c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
        new String[]{String.valueOf(id)}, null);
        if (c != null) {
        c.moveToNext();
        loadFromCursor(c);
        } else {
        Log.w(TAG, "loadFromCursor: cursor = null");
        }
        } finally {
        if (c != null)
        c.close();
        }
        }
        // ... 其他方法
        }
private void loadFromCursor(Cursor c) {
        mId = c.getLong(ID_COLUMN);  // 从 Cursor 中获取 ID 列的值，并存储到 mId 变量中
        mAlertDate = c.getLong(ALERTED_DATE_COLUMN);  // 从 Cursor 中获取 ALERTED_DATE 列的值，并存储到 mAlertDate 变量中
        mBgColorId = c.getInt(BG_COLOR_ID_COLUMN);  // 从 Cursor 中获取 BG_COLOR_ID 列的值，并存储到 mBgColorId 变量中
        mCreatedDate = c.getLong(CREATED_DATE_COLUMN);  // 从 Cursor 中获取 CREATED_DATE 列的值，并存储到 mCreatedDate 变量中
        mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN);  // 从 Cursor 中获取 HAS_ATTACHMENT 列的值，并存储到 mHasAttachment 变量中
        mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN);  // 从 Cursor 中获取 MODIFIED_DATE 列的值，并存储到 mModifiedDate 变量中
        mParentId = c.getLong(PARENT_ID_COLUMN);  // 从 Cursor 中获取 PARENT_ID 列的值，并存储到 mParentId 变量中
        mSnippet = c.getString(SNIPPET_COLUMN);  // 从 Cursor 中获取 SNIPPET 列的值，并存储到 mSnippet 变量中
        mType = c.getInt(TYPE_COLUMN);  // 从 Cursor 中获取 TYPE 列的值，并存储到 mType 变量中
        mWidgetId = c.getInt(WIDGET_ID_COLUMN);  // 从 Cursor 中获取 WIDGET_ID 列的值，并存储到 mWidgetId 变量中
        mWidgetType = c.getInt(WIDGET_TYPE_COLUMN);  // 从 Cursor 中获取 WIDGET_TYPE 列的值，并存储到 mWidgetType 变量中
        mVersion = c.getLong(VERSION_COLUMN);  // 从 Cursor 中获取 VERSION 列的值，并存储到 mVersion 变量中
        }

private void loadDataContent() {
        Cursor c = null;
        mDataList.clear();  // 清空 mDataList 列表
        try {
        c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
        "(note_id=?)", new String[]{String.valueOf(mId)}, null);
        if (c != null) {
        if (c.getCount() == 0) {  // 检查 Cursor 中是否有数据
        Log.w(TAG, "it seems that the note has not data");  // 如果没有数据，则打印警告日志并返回
        return;
        }
        while (c.moveToNext()) {
        SqlData data = new SqlData(mContext, c);  // 创建 SqlData 对象，并从 Cursor 中加载数据
        mDataList.add(data);  // 将 SqlData 对象添加到 mDataList 列表中
        }
        } else {
        Log.w(TAG, "loadDataContent: cursor = null");  // 如果 Cursor 为 null，则打印警告日志
        }
        } finally {
        if (c != null)
        c.close();  // 关闭 Cursor
        }
        }
public boolean setContent(JSONObject js) {
        try {
        // 解析传入的 JSON 对象
        JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);

        // 判断是否为系统文件夹，如果是则无法设置内容
        if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
        Log.w(TAG, "cannot set system folder");
        }
        // 判断是否为文件夹类型
        else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
        // 更新文件夹的摘要和类型
        String snippet = note.has(NoteColumns.SNIPPET) ? note.getString(NoteColumns.SNIPPET) : "";
        if (mIsCreate || !mSnippet.equals(snippet)) {
        mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
        }
        mSnippet = snippet;

        int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE;
        if (mIsCreate || mType != type) {
        mDiffNoteValues.put(NoteColumns.TYPE, type);
        }
        mType = type;
        }
        // 如果是笔记类型
        else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
        // 解析数据部分
        JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);

        // 解析并更新笔记的各个属性
        long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID;
        if (mIsCreate || mId != id) {
        mDiffNoteValues.put(NoteColumns.ID, id);
        }
        mId = id;

// 解析提醒时间，若不存在则默认为 0，更新到 mDiffNoteValues 和成员变量中
        long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note.getLong(NoteColumns.ALERTED_DATE) : 0;
        if (mIsCreate || mAlertDate != alertDate) {
        mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate);
        }
        mAlertDate = alertDate;

// 解析背景色 Id，若不存在则使用默认背景色 Id，更新到 mDiffNoteValues 和成员变量中
        int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext);
        if (mIsCreate || mBgColorId != bgColorId) {
        mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId);
        }
        mBgColorId = bgColorId;

// 解析笔记创建时间，若不存在则使用当前系统时间，更新到 mDiffNoteValues 和成员变量中
        long createDate = note.has(NoteColumns.CREATED_DATE) ? note.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();
        if (mIsCreate || mCreatedDate != createDate) {
        mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate);
        }
        mCreatedDate = createDate;

// 解析是否有附件，若不存在则默认为 0，更新到 mDiffNoteValues 和成员变量中
        int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note.getInt(NoteColumns.HAS_ATTACHMENT) : 0;
        if (mIsCreate || mHasAttachment != hasAttachment) {
        mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment);
        }
        mHasAttachment = hasAttachment;

// 解析笔记最近修改时间，若不存在则使用当前系统时间，更新到 mDiffNoteValues 和成员变量中
        long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();
        if (mIsCreate || mModifiedDate != modifiedDate) {
        mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate);
        }
        mModifiedDate = modifiedDate;

// 解析笔记父文件夹 Id，若不存在则默认为 0，更新到 mDiffNoteValues 和成员变量中
        long parentId = note.has(NoteColumns.PARENT_ID) ? note.getLong(NoteColumns.PARENT_ID) : 0;
        if (mIsCreate || mParentId != parentId) {
        mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId);
        }
        mParentId = parentId;

// 解析笔记摘要，若不存在则默认为空字符串，更新到 mDiffNoteValues 和成员变量中
        String snippet = note.has(NoteColumns.SNIPPET) ? note.getString(NoteColumns.SNIPPET) : "";
        if (mIsCreate || !mSnippet.equals(snippet)) {
        mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
        }
        mSnippet = snippet;

// 解析笔记类型，若不存在则默认为 TYPE_NOTE，更新到 mDiffNoteValues 和成员变量中
        int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE;
        if (mIsCreate || mType != type) {
        mDiffNoteValues.put(NoteColumns.TYPE, type);
        }
        mType = type;

// 解析 widgetId，若不存在则默认为 INVALID_APPWIDGET_ID，更新到 mDiffNoteValues 和成员变量中
        int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID) : AppWidgetManager.INVALID_APPWIDGET_ID;
        if (mIsCreate || mWidgetId != widgetId) {
        mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId);
        }
        mWidgetId = widgetId;

// 解析 widgetType，若不存在则默认为 TYPE_WIDGET_INVALIDE，更新到 mDiffNoteValues 和成员变量中
        int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE;
        if (mIsCreate || mWidgetType != widgetType) {
        mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType);
        }
        mWidgetType = widgetType;

// 解析 originParent，若不存在则默认为 0，更新到 mDiffNoteValues 和成员变量中
        long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0;
        if (mIsCreate || mOriginParent != originParent) {
        mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent);
        }
        mOriginParent = originParent;
        // 处理数据部分
        for (int i = 0; i < dataArray.length(); i++) {
        JSONObject data = dataArray.getJSONObject(i);
        SqlData sqlData = null;
        if (data.has(DataColumns.ID)) {
        long dataId = data.getLong(DataColumns.ID);
        // 查找是否已存在该数据，如果不存在则新建一个
        for (SqlData temp : mDataList) {
        if (dataId == temp.getId()) {
        sqlData = temp;
        }
        }
        }

        if (sqlData == null) {
        sqlData = new SqlData(mContext);
        mDataList.add(sqlData);
        }

        // 更新数据内容
        sqlData.setContent(data);
        }
        }
        } catch (JSONException e) {
        Log.e(TAG, e.toString());
        e.printStackTrace();
        return false;
        }
        return true;
        }


public JSONObject getContent() {
        try {
        JSONObject js = new JSONObject();

        // 如果是新创建的笔记对象，则没有在数据库中创建过
        if (mIsCreate) {
        Log.e(TAG, "it seems that we haven't created this in database yet");
        return null;
        }

        JSONObject note = new JSONObject();
        if (mType == Notes.TYPE_NOTE) {
        // 解析笔记对象的各个属性，并存入 note JSON 对象中
        note.put(NoteColumns.ID, mId);
        note.put(NoteColumns.ALERTED_DATE, mAlertDate);
        note.put(NoteColumns.BG_COLOR_ID, mBgColorId);
        note.put(NoteColumns.CREATED_DATE, mCreatedDate);
        note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment);
        note.put(NoteColumns.MODIFIED_DATE, mModifiedDate);
        note.put(NoteColumns.PARENT_ID, mParentId);
        note.put(NoteColumns.SNIPPET, mSnippet);
        note.put(NoteColumns.TYPE, mType);
        note.put(NoteColumns.WIDGET_ID, mWidgetId);
        note.put(NoteColumns.WIDGET_TYPE, mWidgetType);
        note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent);
        js.put(GTaskStringUtils.META_HEAD_NOTE, note);

        JSONArray dataArray = new JSONArray();
        for (SqlData sqlData : mDataList) {
        // 解析笔记的数据内容，添加到 dataArray 中
        JSONObject data = sqlData.getContent();
        if (data != null) {
        dataArray.put(data);
        }
        }
        js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
        } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {
        // 如果是文件夹或系统类型的笔记，则只解析对应的属性
        note.put(NoteColumns.ID, mId);
        note.put(NoteColumns.TYPE, mType);
        note.put(NoteColumns.SNIPPET, mSnippet);
        js.put(GTaskStringUtils.META_HEAD_NOTE, note);
        }

        return js;
        } catch (JSONException e) {
        Log.e(TAG, e.toString());
        e.printStackTrace();
        }
        return null;
        }
/**
 * 设置笔记的父级 ID
 * @param id 父级 ID
 */
public void setParentId(long id) {
        mParentId = id;
        mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
        }

/**
 * 设置笔记在 GTask 中的 ID
 * @param gid GTask 中的 ID
 */
public void setGtaskId(String gid) {
        mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);
        }

/**
 * 设置笔记在服务器上同步时对应的 ID
 * @param syncId 同步 ID
 */
public void setSyncId(long syncId) {
        mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId);
        }

/**
 * 重置笔记的本地修改状态
 */
public void resetLocalModified() {
        mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);
        }

/**
 * 获取笔记的 ID
 * @return 笔记的 ID
 */
public long getId() {
        return mId;
        }

/**
 * 获取笔记的父级 ID
 * @return 笔记的父级 ID
 */
public long getParentId() {
        return mParentId;
        }

/**
 * 获取笔记的摘要
 * @return 笔记的摘要
 */
public String getSnippet() {
        return mSnippet;
        }

/**
 * 判断笔记是否为笔记类型
 * @return 是否为笔记类型
 */
/**
 * 判断笔记是否为笔记类型
 * @return 是否为笔记类型
 */
public boolean isNoteType() {
        return mType == Notes.TYPE_NOTE;
        }

/**
 * 提交笔记变更
 * @param validateVersion 是否验证版本号
 * @throws ActionFailureException 执行操作失败时抛出该异常
 */
public void commit(boolean validateVersion) throws ActionFailureException {
        // 如果是新建笔记
        if (mIsCreate) {
        // 如果 ID 无效且 DiffNoteValues 中包含 ID，则删除 ID
        if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
        mDiffNoteValues.remove(NoteColumns.ID);
        }
        // 插入新的笔记数据
        Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues);
        try {
        mId = Long.valueOf(uri.getPathSegments().get(1));
        } catch (NumberFormatException e) {
        Log.e(TAG, "Get note id error :" + e.toString());
        throw new ActionFailureException("create note failed");
        }
        if (mId == 0) {
        throw new IllegalStateException("Create thread id failed");
        }
        // 如果是笔记类型，则提交其它相关数据
        if (mType == Notes.TYPE_NOTE) {
        for (SqlData sqlData : mDataList) {
        sqlData.commit(mId, false, -1);
        }
        }
        }
        // 如果是更新笔记
        else {
        // 如果 ID 无效或为根文件夹或通话记录文件夹
        if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) {
        Log.e(TAG, "No such note");
        throw new IllegalStateException("Try to update note with invalid id");
        }
        // 如果 DiffNoteValues 中有变更，则更新笔记
        if (mDiffNoteValues.size() > 0) {
        mVersion++;
        int result = 0;
        if (!validateVersion) {
        // 如果不验证版本号，则直接更新笔记
        result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
        + NoteColumns.ID + "=?)", new String[]{
        String.valueOf(mId)
        });
        } else {
        // 如果验证版本号，则只在版本号匹配时更新笔记
        result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
        + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)",
        new String[]{
        String.valueOf(mId), String.valueOf(mVersion)
        });
        }
        if (result == 0) {
        Log.w(TAG, "there is no update. maybe user updates note when syncing");
        }
        }
        // 如果是笔记类型，则提交其它相关数据
        if (mType == Notes.TYPE_NOTE) {
        for (SqlData sqlData : mDataList) {
        sqlData.commit(mId, validateVersion, mVersion);
        }
        }
        }

        // 刷新本地信息
        loadFromCursor(mId);
        if (mType == Notes.TYPE_NOTE)
        loadDataContent();

        mDiffNoteValues.clear();
        mIsCreate = false;
        }
