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

import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
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.NoteColumns;
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;

import java.util.ArrayList;
import java.util.HashSet;


public class DataUtils {
    public static final String TAG = "DataUtils";//定义了一个Java常量变量，名为TAG
    public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
        if (ids == null) {
            Log.d(TAG, "the ids is null");
            return true;
        }
        if (ids.size() == 0) {
            Log.d(TAG, "no id is in the hashset");
            return true;
        }

        ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
        for (long id : ids) {
            if(id == Notes.ID_ROOT_FOLDER) {
                Log.e(TAG, "Don't delete system folder root");
                continue;
            }
            ContentProviderOperation.Builder builder = ContentProviderOperation
                    .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
            operationList.add(builder.build());
        }
        try {
            ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
            if (results == null || results.length == 0 || results[0] == null) {
                Log.d(TAG, "delete notes failed, ids:" + ids.toString());
                return false;
            }
            return true;
        } catch (RemoteException e) {
            Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
        } catch (OperationApplicationException e) {
            Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
        }
        return false;
    }/*这段代码是一个静态方法，它接受两个参数：ContentResolver对象和一个Long类型的HashSet集合。这个方法的作用是批量删除笔记。

如果传入的ids集合为空，方法会输出一条日志并返回true；如果ids集合的大小为0，同样会输出一条日志并返回true。

如果ids集合不为空且大小不为0，方法会遍历ids集合中的每个元素。如果该元素等于Notes.ID_ROOT_FOLDER，也就是系统文件夹的根目录，那么会输出一个错误日志并跳过该元素；否则，会创建一个ContentProviderOperation对象，使用ContentProviderOperation.newDelete()方法来构建一个删除操作，并将该操作添加到操作列表（operationList）中。

最后，方法会使用ContentResolver.applyBatch()方法来执行操作列表中的所有操作，如果操作成功，则返回true，否则返回false。如果发生RemoteException或OperationApplicationException异常，方法会输出一个错误日志并返回false。*/

    public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
        ContentValues values = new ContentValues();
        values.put(NoteColumns.PARENT_ID, desFolderId);
        values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
        values.put(NoteColumns.LOCAL_MODIFIED, 1);
        resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
    }/*这段代码是一个静态方法，它接受四个参数：ContentResolver对象、一个long类型的id、一个long类型的srcFolderId和一个long类型的desFolderId。这个方法的作用是将一个笔记移动到指定的文件夹中。

方法首先创建一个ContentValues对象，并将要更新的字段和值添加到该对象中。这里，将NoteColumns.PARENT_ID字段设置为desFolderId，表示将笔记的父文件夹设置为目标文件夹；将NoteColumns.ORIGIN_PARENT_ID字段设置为srcFolderId，表示将笔记的原始父文件夹设置为源文件夹；将NoteColumns.LOCAL_MODIFIED字段设置为1，表示该笔记已被本地修改过。

接下来，方法调用ContentResolver.update()方法来更新笔记。该方法接受四个参数：笔记的URI、要更新的值、选择条件和选择条件的参数。这里，笔记的URI是通过ContentUris.withAppendedId()方法创建的，其值为Notes.CONTENT_NOTE_URI与id拼接而成；要更新的值是上面创建的ContentValues对象；选择条件和选择条件的参数都为null，表示更新所有行。*/

    public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
            long folderId) {
        if (ids == null) {
            Log.d(TAG, "the ids is null");
            return true;
        }

        ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
        for (long id : ids) {
            ContentProviderOperation.Builder builder = ContentProviderOperation
                    .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
            builder.withValue(NoteColumns.PARENT_ID, folderId);
            builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
            operationList.add(builder.build());
        }

        try {
            ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
            if (results == null || results.length == 0 || results[0] == null) {
                Log.d(TAG, "delete notes failed, ids:" + ids.toString());
                return false;
            }
            return true;
        } catch (RemoteException e) {
            Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
        } catch (OperationApplicationException e) {
            Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
        }
        return false;
    }/*这段代码是一个静态方法，它接受三个参数：ContentResolver对象、一个Long类型的HashSet集合ids和一个Long类型的folderId。这个方法的作用是批量将笔记移动到指定的文件夹中。

如果传入的ids集合为空，方法会输出一条日志并返回true。

如果ids集合不为空，方法会遍历ids集合中的每个元素。对于每个元素，方法会创建一个ContentProviderOperation对象，并使用ContentProviderOperation.newUpdate()方法来构建一个更新操作。然后，将NoteColumns.PARENT_ID字段设置为folderId，表示将笔记的父文件夹设置为目标文件夹；将NoteColumns.LOCAL_MODIFIED字段设置为1，表示该笔记已被本地修改过。最后，将该操作添加到操作列表（operationList）中。

最后，方法使用ContentResolver.applyBatch()方法来执行操作列表中的所有操作。如果操作成功，则返回true，否则返回false。如果发生RemoteException或OperationApplicationException异常，方法会输出一个错误日志并返回false*/

    /**
     * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
     */
    public static int getUserFolderCount(ContentResolver resolver) {
        Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
                new String[] { "COUNT(*)" },
                NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
                new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
                null);

        int count = 0;
        if(cursor != null) {
            if(cursor.moveToFirst()) {
                try {
                    count = cursor.getInt(0);
                } catch (IndexOutOfBoundsException e) {
                    Log.e(TAG, "get folder count failed:" + e.toString());
                } finally {
                    cursor.close();
                }
            }
        }
        return count;
    }/*这段代码是一个静态方法，它接受一个ContentResolver对象作为参数。该方法的作用是返回用户创建的文件夹的数量。

该方法创建了一个Cursor对象，使用ContentResolver.query()方法查询笔记数据库，并返回所有类型为Notes.TYPE_FOLDER（文件夹类型）且不在回收站中的笔记数量。查询结果只包含一列，即COUNT(*)。

查询结果存储在Cursor对象中。如果Cursor对象不为null，方法会将光标移动到第一行，并使用getInt(0)方法获取查询结果中的第一列的值，即文件夹数量。如果发生IndexOutOfBoundsException异常，则输出一个错误日志。最后，方法关闭Cursor对象并返回文件夹数量。

注意，该方法只返回用户创建的文件夹数量，不包括系统预置的文件夹（如回收站）。*/

    public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
        Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
                null,
                NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
                new String [] {String.valueOf(type)},
                null);

        boolean exist = false;
        if (cursor != null) {
            if (cursor.getCount() > 0) {
                exist = true;
            }
            cursor.close();
        }
        return exist;
    }/*这段代码是一个静态方法，它接受三个参数：ContentResolver对象、一个long类型的noteId和一个int类型的type。该方法的作用是检查给定的笔记是否存在于笔记数据库中，并且不在回收站中。

该方法首先创建一个Cursor对象，使用ContentResolver.query()方法查询笔记数据库，查询的条件是笔记类型为type，并且笔记的父文件夹不是回收站。查询结果包含所有列。

然后，方法检查查询结果是否存在，如果存在则将exist变量设置为true。最后，方法关闭Cursor对象并返回exist变量的值，即给定的笔记是否存在于笔记数据库中。*/

    public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
        Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
                null, null, null, null);

        boolean exist = false;
        if (cursor != null) {
            if (cursor.getCount() > 0) {
                exist = true;
            }
            cursor.close();
        }
        return exist;
    }/*这段代码是一个静态方法，它接受两个参数：ContentResolver对象和一个long类型的noteId。该方法的作用是检查给定的笔记是否存在于笔记数据库中。

该方法首先创建一个Cursor对象，使用ContentResolver.query()方法查询笔记数据库。查询条件为笔记ID等于noteId，查询结果包含所有列。

然后，方法检查查询结果是否存在，如果存在则将exist变量设置为true。最后，方法关闭Cursor对象并返回exist变量的值，即给定的笔记是否存在于笔记数据库中*/

    public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
        Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
                null, null, null, null);

        boolean exist = false;
        if (cursor != null) {
            if (cursor.getCount() > 0) {
                exist = true;
            }
            cursor.close();
        }
        return exist;
    }/*这段代码是一个静态方法，它接受两个参数：ContentResolver对象和一个long类型的dataId。该方法的作用是检查给定的数据是否存在于数据数据库中。

该方法首先创建一个Cursor对象，使用ContentResolver.query()方法查询数据数据库。查询条件为数据ID等于dataId，查询结果包含所有列。

然后，方法检查查询结果是否存在，如果存在则将exist变量设置为true。最后，方法关闭Cursor对象并返回exist变量的值，即给定的数据是否存在于数据数据库中。*/

    public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
        Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
                NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
                " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
                " AND " + NoteColumns.SNIPPET + "=?",
                new String[] { name }, null);
        boolean exist = false;
        if(cursor != null) {
            if(cursor.getCount() > 0) {
                exist = true;
            }
            cursor.close();
        }
        return exist;
    }/*这段代码是一个静态方法，它接受两个参数：ContentResolver对象和一个String类型的name。该方法的作用是检查给定名称的文件夹在笔记数据库中是否可见（即不在回收站中）。

该方法首先创建一个Cursor对象，使用ContentResolver.query()方法查询笔记数据库。查询条件为笔记类型为Notes.TYPE_FOLDER（文件夹类型）、父文件夹不是回收站（NoteColumns.PARENT_ID <> Notes.ID_TRASH_FOLER）以及笔记的摘要（NoteColumns.SNIPPET）等于给定的名称。查询结果包含所有列。

然后，方法检查查询结果是否存在，如果存在则将exist变量设置为true。最后，方法关闭Cursor对象并返回exist变量的值，即给定名称的文件夹在笔记数据库中是否可见。*/

    public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
        Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
                new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
                NoteColumns.PARENT_ID + "=?",
                new String[] { String.valueOf(folderId) },
                null);

        HashSet<AppWidgetAttribute> set = null;
        if (c != null) {
            if (c.moveToFirst()) {
                set = new HashSet<AppWidgetAttribute>();
                do {
                    try {
                        AppWidgetAttribute widget = new AppWidgetAttribute();
                        widget.widgetId = c.getInt(0);
                        widget.widgetType = c.getInt(1);
                        set.add(widget);
                    } catch (IndexOutOfBoundsException e) {
                        Log.e(TAG, e.toString());
                    }
                } while (c.moveToNext());
            }
            c.close();
        }
        return set;
    }/*这段代码是一个静态方法，它接受两个参数：ContentResolver对象和一个long类型的folderId。该方法的作用是获取给定文件夹下所有包含小部件的笔记的小部件ID和小部件类型。

该方法首先创建一个Cursor对象，使用ContentResolver.query()方法查询笔记数据库。查询条件为笔记的父文件夹ID等于给定的folderId。查询结果包含小部件ID和小部件类型这两列。

然后，方法将查询结果装入一个HashSet对象中。如果查询结果不为空，则创建一个HashSet<AppWidgetAttribute>对象，遍历查询结果并逐个添加小部件ID和小部件类型到HashSet中。如果查询结果为空，则返回null。

最后，方法关闭Cursor对象并返回HashSet对象，其中包含给定文件夹下所有包含小部件的笔记的小部件ID和小部件类型。*/

    public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
        Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
                new String [] { CallNote.PHONE_NUMBER },
                CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",
                new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
                null);

        if (cursor != null && cursor.moveToFirst()) {
            try {
                return cursor.getString(0);
            } catch (IndexOutOfBoundsException e) {
                Log.e(TAG, "Get call number fails " + e.toString());
            } finally {
                cursor.close();
            }
        }
        return "";
    }/*这段代码是一个静态方法，它接受两个参数：ContentResolver对象和一个long类型的noteId。该方法的作用是获取给定笔记ID对应的电话笔记的电话号码。

该方法首先创建一个Cursor对象，使用ContentResolver.query()方法查询数据数据库。查询条件为电话笔记的笔记ID等于给定的noteId，且电话笔记的MIME类型为CallNote.CONTENT_ITEM_TYPE。查询结果包含电话号码这一列。

然后，方法检查查询结果是否存在，如果存在则返回查询结果中的电话号码。如果查询结果不存在，则返回空字符串。

最后，方法关闭Cursor对象并返回电话号码（或空字符串）。*/

    public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
        Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
                new String [] { CallNote.NOTE_ID },
                CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
                + CallNote.PHONE_NUMBER + ",?)",
                new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
                null);

        if (cursor != null) {
            if (cursor.moveToFirst()) {
                try {
                    return cursor.getLong(0);
                } catch (IndexOutOfBoundsException e) {
                    Log.e(TAG, "Get call note id fails " + e.toString());
                }
            }
            cursor.close();
        }
        return 0;
    }/*这段代码是一个静态方法，它接受三个参数：ContentResolver对象、一个String类型的phoneNumber和一个long类型的callDate。该方法的作用是根据给定的电话号码和通话日期获取对应的电话笔记的笔记ID。

该方法首先创建一个Cursor对象，使用ContentResolver.query()方法查询数据数据库。查询条件为电话笔记的通话日期等于给定的callDate，电话笔记的MIME类型为CallNote.CONTENT_ITEM_TYPE，且电话号码等于给定的phoneNumber。查询结果包含笔记ID这一列。

然后，方法检查查询结果是否存在。如果存在，则返回查询结果中的笔记ID。如果查询结果不存在，则返回0。

最后，方法关闭Cursor对象并返回笔记ID（或0）。*/

    public static String getSnippetById(ContentResolver resolver, long noteId) {
        Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
                new String [] { NoteColumns.SNIPPET },
                NoteColumns.ID + "=?",
                new String [] { String.valueOf(noteId)},
                null);

        if (cursor != null) {
            String snippet = "";
            if (cursor.moveToFirst()) {
                snippet = cursor.getString(0);
            }
            cursor.close();
            return snippet;
        }
        throw new IllegalArgumentException("Note is not found with id: " + noteId);
    }/*这段代码是一个静态方法，它接受两个参数：ContentResolver对象和一个long类型的noteId。该方法的作用是获取给定笔记ID对应的笔记的摘要（snippet）。

该方法首先创建一个Cursor对象，使用ContentResolver.query()方法查询笔记的内容提供者。查询条件为笔记的ID等于给定的noteId。查询结果包含笔记的摘要这一列。

然后，方法检查查询结果是否存在。如果存在，则获取查询结果中的笔记摘要并将其存储在一个字符串变量snippet中。然后，方法关闭Cursor对象并返回snippet。如果查询结果不存在，则抛出一个IllegalArgumentException异常，其中包含“Note is not found with id: ”和给定的noteId作为错误消息。*/

    public static String getFormattedSnippet(String snippet) {
        if (snippet != null) {
            snippet = snippet.trim();
            int index = snippet.indexOf('\n');
            if (index != -1) {
                snippet = snippet.substring(0, index);
            }
        }
        return snippet;
    }
}/*这段代码是一个静态方法，它接受一个String类型的snippet参数。该方法的作用是对给定的snippet进行格式化处理，以便在界面上显示。

该方法首先检查传入的snippet是否为空。如果不为空，则使用String.trim()方法删除snippet字符串中的前导和尾随空格。然后，使用String.indexOf()方法查找snippet字符串中第一个换行符的位置。如果找到了换行符，则使用String.substring()方法截取snippet字符串中第一个换行符之前的所有字符，并将结果存储回snippet变量中。否则，不做任何修改，直接返回原始的snippet字符串。

最后，方法返回格式化后的snippet字符串。*/
