/*
 * 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.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.net.Uri;
import android.os.RemoteException;
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.NoteColumns;
import net.micode.notes.data.Notes.TextNote;

import java.util.ArrayList;


public class Note {
    // 存储笔记的差异值，使用 ContentValues 类型，可能用于存储一些更新信息
    private ContentValues mNoteDiffValues;
    // 存储笔记的数据，使用 NoteData 类型
    private NoteData mNoteData;
    // 日志标签，用于日志输出
    private static final String TAG = "Note";

    /**
     * Create a new note id for adding a new note to databases
     * 此方法用于创建一个新的笔记 ID 并添加到数据库中，是一个同步方法，保证多线程环境下的安全操作
     */
    public static synchronized long getNewNoteId(Context context, long folderId) {
        // 创建一个新的 ContentValues 对象，用于存储即将插入数据库的数据
        ContentValues values = new ContentValues();
        // 获取当前系统时间作为创建时间和修改时间
        long createdTime = System.currentTimeMillis();
        // 将创建时间添加到 ContentValues 中
        values.put(NoteColumns.CREATED_DATE, createdTime);
        // 将修改时间添加到 ContentValues 中
        values.put(NoteColumns.MODIFIED_DATE, createdTime);
        // 笔记的类型，这里可能是预定义的 TYPE_NOTE
        values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
        // 标记为本地已修改
        values.put(NoteColumns.LOCAL_MODIFIED, 1);
        // 父文件夹的 ID
        values.put(NoteColumns.PARENT_ID, folderId);
        // 通过 ContentResolver 插入数据，并获取插入后的 Uri
        Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);

        long noteId = 0;
        try {
            // 从 Uri 的路径段中获取笔记的 ID，这里假定 Uri 的路径段的第二个元素是笔记 ID
            noteId = Long.valueOf(uri.getPathSegments().get(1));
        } catch (NumberFormatException e) {
            // 若获取 ID 时出现异常，输出错误日志，并将 noteId 设为 0
            Log.e(TAG, "Get note id error :" + e.toString());
            noteId = 0;
        }
        // 如果笔记 ID 为 -1，抛出异常
        if (noteId == -1) {
            throw new IllegalStateException("Wrong note id:" + noteId);
        }
        // 返回创建的笔记 ID
        return noteId;
    }

    // 构造函数，初始化 Note 对象
    public Note() {
        mNoteDiffValues = new ContentValues();
        mNoteData = new NoteData();
    }

    /**
     * 用于设置笔记的某个值
     * @param key 键
     * @param value 值
     */
    public void setNoteValue(String key, String value) {
        // 将键值对添加到 mNoteDiffValues 中
        mNoteDiffValues.put(key, value);
        // 标记为本地已修改
        mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
        // 更新修改时间为当前系统时间
        mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
    }

    /**
     * 用于设置文本数据的某个键值对
     * @param key 键
     * @param value 值
     */
    public void setTextData(String key, String value) {
        mNoteData.setTextData(key, value);
    }

    /**
     * 用于设置文本数据的 ID
     * @param id 文本数据的 ID
     */
    public void setTextDataId(long id) {
        mNoteData.setTextDataId(id);
    }

    /**
     * 获取文本数据的 ID
     * @return 文本数据的 ID
     */
    public long getTextDataId() {
        return mNoteData.mTextDataId;
    }

    /**
     * 用于设置通话数据的 ID
     * @param id 通话数据的 ID
     */
    public void setCallDataId(long id) {
        mNoteData.setCallDataId(id);
    }

    /**
     * 用于设置通话数据的某个键值对
     * @param key 键
     * @param value 值
     */
    public void setCallData(String key, String value) {
        mNoteData.setCallData(key, value);
    }

    /**
     * 检查笔记是否在本地被修改
     * @return 如果 mNoteDiffValues 不为空或者 mNoteData 被本地修改，返回 true，否则返回 false
     */
    public boolean isLocalModified() {
        return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
    }

    /**
     * 同步笔记数据到数据库
     * @param context 上下文对象
     * @param noteId 笔记的 ID
     * @return 同步成功返回 true，失败返回 false
     */
    public boolean syncNote(Context context, long noteId) {
        // 如果笔记 ID 不合法，抛出异常
        if (noteId <= 0) {
            throw new IllegalArgumentException("Wrong note id:" + noteId);
        }

        // 如果笔记未在本地修改，认为同步成功
        if (!isLocalModified()) {
            return true;
        }

        /**
         * In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
         * {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
         * note data info
         * 理论上，一旦数据发生改变，笔记应该更新 NoteColumns#LOCAL_MODIFIED 和 NoteColumns#MODIFIED_DATE 列的值。为保证数据安全，即使更新笔记失败，也会更新笔记数据信息
         */
        if (context.getContentResolver().update(
                ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
                null) == 0) {
            // 如果更新笔记失败，输出错误日志
            Log.e(TAG, "Update note error, should not happen");
            // 不返回，继续执行下面的操作
        }
        // 清空 mNoteDiffValues，可能表示此次修改已同步
        mNoteDiffValues.clear();

        // 如果 mNoteData 本地修改且将数据推送到 ContentResolver 失败，同步失败
        if (mNoteData.isLocalModified()
                && (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
            return false;
        }

        // 同步成功
        return true;
    }
}

   // 定义一个名为 Note 的公共类
public class Note {
    // 存储笔记差异值的私有变量，使用 ContentValues 类型，可存储键值对数据
    private ContentValues mNoteDiffValues;
    // 存储笔记数据的私有变量，使用 NoteData 类型
    private NoteData mNoteData;
    // 用于日志输出的静态常量标签，方便在日志中识别该类的相关信息
    private static final String TAG = "Note";

    /**
     * 此方法用于创建一个新的笔记 ID，并将新笔记添加到数据库中。
     * 它是一个静态同步方法，确保在多线程环境下的线程安全。
     * @param context 应用程序上下文，用于获取 ContentResolver 以进行数据库操作
     * @param folderId 新笔记所属的文件夹的 ID
     * @return 新创建笔记的 ID
     */
    public static synchronized long getNewNoteId(Context context, long folderId) {
        // 创建一个新的 ContentValues 对象，用于存储插入数据库的数据
        ContentValues values = new ContentValues();
        // 获取当前系统时间的毫秒数作为笔记的创建时间
        long createdTime = System.currentTimeMillis();
        // 将创建时间存储在 CREATED_DATE 列中
        values.put(NoteColumns.CREATED_DATE, createdTime);
        // 将创建时间存储在 MODIFIED_DATE 列中，新笔记的创建时间也是其初始修改时间
        values.put(NoteColumns.MODIFIED_DATE, createdTime);
        // 存储笔记的类型，Notes.TYPE_NOTE 应该是预定义的笔记类型常量
        values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
        // 标记该笔记在本地已修改，可能用于后续的同步或更新操作
        values.put(NoteColumns.LOCAL_MODIFIED, 1);
        // 存储笔记所属的父文件夹的 ID
        values.put(NoteColumns.PARENT_ID, folderId);
        // 通过 ContentResolver 插入新的笔记数据到指定的 URI，并返回插入后的 URI
        Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);

        long noteId = 0;
        try {
            // 从返回的 URI 中获取笔记的 ID，这里假设 URI 的路径部分包含笔记的 ID，通常是 URI 的第二个部分
            noteId = Long.valueOf(uri.getPathSegments().get(1));
        } catch (NumberFormatException e) {
            // 捕获数字格式异常，打印错误日志，并将 noteId 设置为 0
            Log.e(TAG, "Get note id error :" + e.toString());
            noteId = 0;
        }
        // 如果笔记 ID 为 -1，则抛出异常，因为这是一个错误的笔记 ID
        if (noteId == -1) {
            throw new IllegalStateException("Wrong note id:" + noteId);
        }
        // 返回新创建的笔记的 ID
        return noteId;
    }

    // Note 类的构造函数，用于初始化 Note 对象
    public Note() {
        // 初始化存储笔记差异值的 ContentValues 对象
        mNoteDiffValues = new ContentValues();
        // 初始化存储笔记数据的 NoteData 对象
        mNoteData = new NoteData();
    }

    /**
     * 此方法用于设置笔记的键值对数据。
     * 同时更新笔记的修改信息，包括标记为本地已修改和修改时间。
     * @param key 要设置的键
     * @param value 要设置的值
     */
    public void setNoteValue(String key, String value) {
        // 将键值对存储到 mNoteDiffValues 中
        mNoteDiffValues.put(key, value);
        // 标记该笔记在本地已修改
        mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
        // 更新笔记的修改时间为当前系统时间
        mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
    }

    /**
     * 此方法用于设置文本数据的键值对。
     * 它可能会更新 NoteData 对象中的文本数据。
     * @param key 要设置的键
     * @param value 要设置的值
     */
    public void setTextData(String key, String value) {
        mNoteData.setTextData(key, value);
    }

    /**
     * 此方法用于设置文本数据的 ID。
     * @param id 要设置的文本数据的 ID
     */
    public void setTextDataId(long id) {
        mNoteData.setTextDataId(id);
    }

    /**
     * 获取文本数据的 ID。
     * @return 文本数据的 ID
     */
    public long getTextDataId() {
        return mNoteData.mTextDataId;
    }

    /**
     * 此方法用于设置通话数据的 ID。
     * 可能会更新 NoteData 对象中的通话数据的 ID。
     * @param id 要设置的通话数据的 ID
     */
    public void setCallDataId(long id) {
        mNoteData.setCallDataId(id);
    }

    /**
     * 此方法用于设置通话数据的键值对。
     * 可能会更新 NoteData 对象中的通话数据。
     * @param key 要设置的键
     * @param value 要设置的值
     */
    public void setCallData(String key, String value) {
        mNoteData.setCallData(key, value);
    }

    /**
     * 检查笔记是否在本地已修改。
     * 若 mNoteDiffValues 不为空或 NoteData 已在本地修改，则认为笔记已修改。
     * @return 如果笔记在本地已修改，返回 true；否则返回 false
     */
    public boolean isLocalModified() {
        return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
    }

    /**
     * 此方法用于将笔记数据同步到数据库。
     * @param context 应用程序上下文，用于获取 ContentResolver 进行数据库操作
     * @param noteId 要同步的笔记的 ID
     * @return 若同步成功，返回 true；否则返回 false
     */
    public boolean syncNote(Context context, long noteId) {
        // 检查笔记 ID 是否合法，如果不合法则抛出异常
        if (noteId <= 0) {
            throw new IllegalArgumentException("Wrong note id:" + noteId);
        }

        // 如果笔记未在本地修改，认为同步成功
        if (!isLocalModified()) {
            return true;
        }

        /**
         * 理论上，一旦数据发生变化，笔记应该更新 LOCAL_MODIFIED 和 MODIFIED_DATE 列。
         * 为确保数据安全，即使更新笔记失败，也会更新笔记的数据信息。
         */
        if (context.getContentResolver().update(
                ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
                null) == 0) {
            // 如果更新笔记时出现错误，打印错误日志，日志中会标记不应该发生此错误
            Log.e(TAG, "Update note error, should not happen");
            // 不返回，继续执行后续操作
        }
        // 清空 mNoteDiffValues，可能表示当前的修改已同步到数据库
        mNoteDiffValues.clear();

        // 如果 NoteData 已在本地修改，并且将其数据推送到 ContentResolver 失败，则同步失败
        if (mNoteData.isLocalModified()
                && (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
            return false;
        }

        // 表示笔记数据已成功同步
        return true;
    }
}