public class JBCloud {
    public static Context applicationContext;

    static Class<? extends IObjectManager> objectManagerClass = null;

    public static final int CLOUD_FUNCTION_SUCCESS = 0;
    public static final int CLOUD_FUNCTION_ERROR = 1;

    /**
     *
     * @param context
     * @param appKey
     * @param appId
     * @param host base url
     */
    public static void init(Context context , String appKey , String appId , String host , GetInstallationIdCallback callback) {
        applicationContext = context;
        IObjectManager.appKey = appKey;
        IObjectManager.appId = appId;
        IObjectManager.host = host;
        syncTimestamp();
        getInstallationId(callback);
        setObjectManager(ObjectManagerImp.class);
    }

    public static void showLog(){
        Utils.showLog();
    }

    public static void setObjectManager(Class<? extends IObjectManager> objectManager){
        JBCloud.objectManagerClass = objectManager;
    }

    static IObjectManager getObjectManager(String tableName){
        if (objectManagerClass == null)
            setObjectManager(ObjectManagerImp.class);
        Class[] paramTypes = { Context.class, String.class};
        try {
            Constructor con = objectManagerClass.getConstructor(paramTypes);
            return ((IObjectManager) con.newInstance(applicationContext, tableName));
        } catch (Exception e) {
            throw new RuntimeException("IObjectManager illegal " , e);
        }
    }

    public static void callFunctionInBackground(String name, Map<String, Object> params, final CloudCallback listener) {
        String url = "/api/cloud/" + name;
        StringBuilder stringBuffer = new StringBuilder(url);
        stringBuffer.append("?");
        for (String s : params.keySet()) {
            Object o = params.get(s);
            stringBuffer.append(s).append("=").append(String.valueOf(o)).append("&");
        }
        JBCloud.getObjectManager(null).customJsonRequest(applicationContext, false ,new ResponseListener<CustomResponse>() {
            @Override
            public void onResponse(CustomResponse entity) {
                JSONObject response = JSON.parseObject(entity.getData());
                int code = response.getIntValue("code");
                ResponseEntity responseEntity = new ResponseEntity();
                responseEntity.setCode(code);
                responseEntity.setData(response.getJSONObject("data"));
                responseEntity.setMessage(response.getString("message"));
                if (listener == null)
                    return;
                if (code == CLOUD_FUNCTION_SUCCESS){
                    listener.done(responseEntity);
                }else if (code == CLOUD_FUNCTION_ERROR){
                    JBException jbException = new JBException(response.getString("message"));
                    jbException.errorCode = JBException.CLOUD_ERROR;
                    listener.error(jbException , responseEntity);
                }else {
                    listener.done(responseEntity);
                }
            }

            @Override
            public void onError(JBException e) {
                if (listener != null)
                    listener.error(e , null);
            }
        }, stringBuffer.toString(), IObjectManager.Method.GET, null);
    }

    //获取InstallationID
    public static void getInstallationId(final GetInstallationIdCallback callback) {
        String installationId = (String) SharedPreferencesUtils.get(applicationContext, "installationId" , "");
        if (!TextUtils.isEmpty(installationId)){
            if (callback != null)
                callback.done(installationId);
            return;
        }
        String url = "/api/installation";
        HashMap<String, Object> params = new HashMap<>();
        params.put("deviceToken" , getDeviceId());
        params.put("deviceType" , "android");
        JBCloud.getObjectManager(null).customJsonRequest(applicationContext, false, new ResponseListener<CustomResponse>() {
            @Override
            public void onResponse(CustomResponse entity) {
                JSONObject response = JSON.parseObject(entity.getData());
                JSONObject data = response.getJSONObject("data");
                String id = data.getString("_id");
                Utils.printLog("InstallationId 获取成功 "+id );
                if (callback != null)
                    callback.done(id);
                if (id != null)
                    SharedPreferencesUtils.put(applicationContext, "installationId", id);
            }

            @Override
            public void onError(JBException e) {
                Utils.printLog("InstallationId 获取失败 "+ e.getMessage());
                if (callback != null)
                    callback.error(e);
            }
        },url, IObjectManager.Method.POST, JSON.toJSONString(params));
    }

    //同步时间戳
    public static void syncTimestamp() {
        String url = "/time";
        Request.Builder builder = new Request.Builder();
        builder.get().url(IObjectManager.host + url);
        Call call = ObjectManagerImp.client.newCall(builder.build());
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Utils.printLog("时间戳获取失败 " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Utils.printLog("时间戳获取成功 " );
                SharedPreferencesUtils.put(applicationContext, "timeDiff", Long.valueOf(response.body().string()) - System.currentTimeMillis());

            }
        });
    }

    //获取设备唯一ID
    public static String getDeviceId(){
        final TelephonyManager tm = (TelephonyManager) applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
        final String tmDevice, tmSerial, androidId;
        tmDevice = "" + tm.getDeviceId();
        tmSerial = "" + tm.getSimSerialNumber();
        androidId = "" + android.provider.Settings.Secure.getString(applicationContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
        UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
        return deviceUuid.toString();
    }

} public class JBFile extends JBObject {
    private String className = "_File";

    private String path;
    private byte[] data;
    private File file;
    private String name;

    public JBFile() {
    }

    public JBFile(File file) {
        this.file = file;
    }

    public JBFile(byte[] bytes) {
        this.data = bytes;
    }

    public static JBFile createWithoutData(String id){
        JBFile jbObject = new JBFile();
        jbObject.setId(id);
        return jbObject;
    }

    public File getFile(){
        return file;
    }

    @Override
    public String getClassName() {
        return className;
    }

    public void saveInBackground(final FileUploadCallback callback) {
        getUploadToken(new ResponseListener<CustomResponse>() {
            @Override
            public void onResponse(CustomResponse entity) {
                if (uploader != null)
                    uploader.upload(entity ,JBFile.this,callback);
            }

            @Override
            public void onError(JBException e) {
                callback.error(e);
            }
        });
    }

    private void getUploadToken(ResponseListener<CustomResponse> listener) {
        JBCloud.getObjectManager(null).customJsonRequest(JBCloud.applicationContext, false , listener, "/api/file/getToken?fileName="+filename+"&platform=" + platform, IObjectManager.Method.GET, null);
    }

    private static IUploader uploader = null;
    private static String platform , filename;
    public static void setUploader(IUploader uploader){
        JBFile.uploader = uploader;
    }
    static {
        if (uploader == null){
            uploader = new QiNiuUploader();
            platform = "qiniu";
            filename = "android_file";
        }
    }
    public static void setPlatform(String platform){
        JBFile.platform = platform;
    }

    public static void setFilename(String filename){
        JBFile.filename = filename;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public byte[] getData() {
        return data;
    }

    public void setData(byte[] data) {
        this.data = data;
    }

    public static JBFile withFile(File file) {
        return new JBFile(file);
    }

    public static JBFile withByte(byte[] bytes){
        return new JBFile(bytes);
    }

    public String getUrl() {
        return (String) get("url");
    }

    public String mimeType() {
        return null;
    }
} public class JBObject extends LinkedHashMap<String, Object> {
    protected String className;

    public JBObject() {
    }

    public JBObject(String className) {
        this.className = className;
    }

    public void setId(String id) {
        this.put("_id", id);
    }

    public String getId() {
        return (String) get("_id");
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public JBObject getJBObject(String key) {
        return (JBObject) get(key);
    }

    public Date getCreatedAt() {
        return new Date((long) get("createdAt"));
    }

    public JBFile getJBFile(String key){
        Object o = get(key);
        if (o instanceof JSONObject){
            JBFile jbFile = new JBFile();
            jbFile.putAll(((JSONObject) o));
            return jbFile;
        }else if (o instanceof JBObject){
            JBFile jbFile = new JBFile();
            jbFile.putAll(((JBObject) o));
            return jbFile;
        }
        return null;
    }

    public int getInt(String key){
        Number v = (Number)this.get(key);
        return v != null?v.intValue():0;
    }

    public double getDouble(String key) {
        Number number = (Number)this.get(key);
        return number != null?number.doubleValue():0.0D;
    }

    public JSONArray getJSONArray(String key) {
        Object list = this.get(key);
        if(list == null) {
            return null;
        } else if(list instanceof JSONArray) {
            return (JSONArray)list;
        } else {
            JSONArray array;
            if(list instanceof Collection) {
                array = new JSONArray((Collection)list);
                return array;
            } else if(!(list instanceof Object[])) {
                return null;
            } else {
                array = new JSONArray();
                Object[] arr$ = (Object[])list;
                int len$ = arr$.length;

                for(int i$ = 0; i$ < len$; ++i$) {
                    Object obj = arr$[i$];
                    array.put(obj);
                }

                return array;
            }
        }
    }

    public org.json.JSONObject getJSONObject(String key) {
        Object object = this.get(key);
        if(object instanceof org.json.JSONObject) {
            return (org.json.JSONObject)object;
        } else {
            String jsonString = JSON.toJSONString(object);
            org.json.JSONObject jsonObject = null;

            try {
                jsonObject = new org.json.JSONObject(jsonString);
                return jsonObject;
            } catch (Exception var6) {
                throw new IllegalStateException("Invalid json string", var6);
            }
        }
    }

    public List getList(String key) {
        return (List)this.get(key);
    }

    public long getLong(String key) {
        Number number = (Number)this.get(key);
        return number != null?number.longValue():0L;
    }

    public JBUser getJBUser(String key) {
        return (JBUser)this.get(key);
    }

    public Date getDate(String key){
        Object o = get(key);
        if (o instanceof Long){
            return new Date((Long) o);
        }else
            return o == null ? null : ((Date) o);
    }

    @Override
    public boolean equals(Object object) {
        return object instanceof JBObject && ((JBObject) object).getId().equals(getId());
    }

    public static JBObject createWithoutData(String className, String id) {
        JBObject jbObject = new JBObject(className);
        jbObject.setId(id);
        return jbObject;
    }


    public void saveInBackground(SaveCallback callback) {
        JBCloud.getObjectManager(className).saveObject(this, false, getId(), callback);
    }

    public JBObject save() throws JBException {
        final Object[] objects = new Object[2];
        JBCloud.getObjectManager(className).saveObject(this, true, getId(), new SaveCallback() {
            @Override
            public void done(JBObject object) {
                objects[0] = object;
            }

            @Override
            public void error(JBException e) {
                objects[1] = e;
            }
        });
        if (objects[1] != null)
            throw (JBException) objects[1];
        return (JBObject) objects[0];
    }

    public void deleteInBackground(DeleteCallback callback) {
        deleteByIdInBackground(className , getId() , callback);
    }

    public void delete()throws JBException{
        deleteById(className , getId());
    }

    public static void deleteByIdInBackground(String className, String id, DeleteCallback callback) {
        if (Utils.isBlankString(id))
            return;
        JBCloud.getObjectManager(className).deleteObject(id, false, callback);
    }

    public static void deleteById(String className, String id) throws JBException{
        if (Utils.isBlankString(id))
            return;
        final Object[] objects = new Object[1];
        JBCloud.getObjectManager(className).deleteObject(id, false, new DeleteCallback() {
            @Override
            public void done() {

            }

            @Override
            public void error(JBException e) {
                objects[0] = e;
            }
        });
        if (objects[1] != null)
            throw (JBException) objects[0];
    }

    public void incrementKeyInBackground(String key , RequestCallback callback){
        incrementKeyInBackground(key , 1 , callback);
    }

    public void incrementKeyInBackground(String key , int amount , RequestCallback callback){
        HashMap<String, Integer> map = new HashMap<>();
        map.put(key , amount);
        incrementKeysInBackground(className , getId() , map , callback);
    }

    public void incrementKey(String key) throws JBException {
        incrementKey(key , 1);
    }

    public void incrementKey(String key , int amount) throws JBException {
        HashMap<String, Integer> map = new HashMap<>();
        map.put(key , amount);
        incrementKeys(className , getId() , map);
    }

    public static void incrementKeysInBackground(String className , String id , Map<String , Integer> incrementKeyAmount , RequestCallback callback){
        if (Utils.isBlankString(id))
            return;
        JBCloud.getObjectManager(className).incrementObjectKey(incrementKeyAmount , id , false , callback);
    }

    public static void incrementKeys(String className , String id , Map<String , Integer> incrementKeyAmount) throws JBException{
        if (Utils.isBlankString(id))
            return;
        final Object[] objects = new Object[1];
        JBCloud.getObjectManager(className).incrementObjectKey(incrementKeyAmount, id, true, new RequestCallback() {
            @Override
            public void done() {

            }

            @Override
            public void error(JBException e) {
                objects[0] = e;
            }
        });
        if (objects[0] != null){
            throw (JBException) objects[0];
        }
    }
} public class JBQuery<T extends JBObject> {

    private Class<T> clazz;
    private String className;
    private JBQuery.CachePolicy cachePolicy = CachePolicy.NETWORK_ONLY;
    private String queryPath;
    private String externalQueryPath;
    QueryConditions conditions;
    private IObjectManager manager;

    public JBQuery(String theClassName) {
        this(theClassName, (Class) null);
        this.className = theClassName;
    }

    public static JBQuery<JBObject> getInstance(String theClassName) {
        return new JBQuery<>(theClassName, JBObject.class);
    }

    public JBQuery(String theClassName, Class<T> clazz) {
        this.cachePolicy = JBQuery.CachePolicy.IGNORE_CACHE;
        Utils.checkClassName(theClassName);
        this.className = theClassName;
        this.clazz = clazz;
        this.conditions = new QueryConditions();
        manager = JBCloud.getObjectManager(theClassName);
    }

    Class<T> getClazz() {
        return this.clazz;
    }

    void setClazz(Class<T> clazz) {
        this.clazz = clazz;
    }

    List<String> getInclude() {
        return this.conditions.getInclude();
    }

    void setInclude(List<String> include) {
        this.conditions.setInclude(include);
    }

    Set<String> getSelectedKeys() {
        return this.conditions.getSelectedKeys();
    }

    void setSelectedKeys(Set<String> selectedKeys) {
        this.conditions.setSelectedKeys(selectedKeys);
    }

    Map<String, String> getParameters() {
        return this.conditions.getParameters();
    }

    void setParameters(Map<String, String> parameters) {
        this.conditions.setParameters(parameters);
    }

    String getQueryPath() {
        return this.queryPath;
    }

    void setQueryPath(String queryPath) {
        this.queryPath = queryPath;
    }

    String getExternalQueryPath() {
        return this.externalQueryPath;
    }

    void setExternalQueryPath(String path) {
        this.externalQueryPath = path;
    }

    static String getTag() {
        return "com.parse.JBQuery";
    }

    Map<String, List<QueryOperation>> getWhere() {
        return this.conditions.getWhere();
    }

    public String getClassName() {
        return this.className;
    }

    public JBQuery<T> setClassName(String className) {
        this.className = className;
        return this;
    }

    public JBQuery.CachePolicy getCachePolicy() {
        return this.cachePolicy;
    }

    public JBQuery<T> setCachePolicy(JBQuery.CachePolicy cachePolicy) {
        this.cachePolicy = cachePolicy;
        return this;
    }

    public JBQuery.CachePolicy getPolicy() {
        return this.cachePolicy;
    }

    public JBQuery<T> setPolicy(JBQuery.CachePolicy policy) {
        this.cachePolicy = policy;
        return this;
    }

    public boolean isTrace() {
        return this.conditions.isTrace();
    }

    public JBQuery<T> setTrace(boolean trace) {
        this.conditions.setTrace(trace);
        return this;
    }

    public int getLimit() {
        return this.conditions.getLimit();
    }

    public JBQuery<T> setLimit(int limit) {
        this.conditions.setLimit(limit);
        return this;
    }

    public JBQuery<T> limit(int limit) {
        this.setLimit(limit);
        return this;
    }

    public JBQuery<T> skip(int skip) {
        this.setSkip(skip);
        return this;
    }

    public int getSkip() {
        return this.conditions.getSkip();
    }

    public JBQuery<T> setSkip(int skip) {
        this.conditions.setSkip(skip);
        return this;
    }

    public String getOrder() {
        return this.conditions.getOrder();
    }

    public JBQuery<T> setOrder(String order) {
        this.conditions.setOrder(order);
        return this;
    }

    public JBQuery<T> order(String order) {
        this.setOrder(order);
        return this;
    }

    public JBQuery<T> addAscendingOrder(String key) {
        this.conditions.addAscendingOrder(key);
        return this;
    }

    public JBQuery<T> addDescendingOrder(String key) {
        this.conditions.addDescendingOrder(key);
        return this;
    }

    public JBQuery<T> include(String key) {
        this.conditions.include(key);
        return this;
    }

    public JBQuery<T> selectKeys(Collection<String> keys) {
        this.conditions.selectKeys(keys);
        return this;
    }

    public JBQuery<T> orderByAscending(String key) {
        this.conditions.orderByAscending(key);
        return this;
    }

    public JBQuery<T> orderByDescending(String key) {
        this.conditions.orderByDescending(key);
        return this;
    }

    public JBQuery<T> whereContainedIn(String key, Collection<? extends Object> values) {
        this.conditions.whereContainedIn(key, values);
        return this;
    }

    public JBQuery<T> whereContains(String key, String substring) {
        this.conditions.whereContains(key, substring);
        return this;
    }

    public JBQuery<T> whereSizeEqual(String key, int size) {
        this.conditions.whereSizeEqual(key, size);
        return this;
    }

    public JBQuery<T> whereContainsAll(String key, Collection<?> values) {
        this.conditions.whereContainsAll(key, values);
        return this;
    }

    public JBQuery<T> whereDoesNotExist(String key) {
        this.conditions.whereDoesNotExist(key);
        return this;
    }

    public JBQuery<T> whereEndsWith(String key, String suffix) {
        this.conditions.whereEndsWith(key, suffix);
        return this;
    }

    public JBQuery<T> whereEqualTo(String key, Object value) {
        this.conditions.whereEqualTo(key, value);
        return this;
    }

    private JBQuery<T> addWhereItem(QueryOperation op) {
        this.conditions.addWhereItem(op);
        return this;
    }

    private JBQuery<T> addOrItems(QueryOperation op) {
        this.conditions.addOrItems(op);
        return this;
    }

    protected JBQuery<T> addWhereItem(String key, String op, Object value) {
        this.conditions.addWhereItem(key, op, value);
        return this;
    }

    public JBQuery<T> whereExists(String key) {
        this.conditions.whereExists(key);
        return this;
    }

    public JBQuery<T> whereGreaterThan(String key, Object value) {
        this.conditions.whereGreaterThan(key, value);
        return this;
    }

    public JBQuery<T> whereGreaterThanOrEqualTo(String key, Object value) {
        this.conditions.whereGreaterThanOrEqualTo(key, value);
        return this;
    }

    public JBQuery<T> whereLessThan(String key, Object value) {
        this.conditions.whereLessThan(key, value);
        return this;
    }

    public JBQuery<T> whereLessThanOrEqualTo(String key, Object value) {
        this.conditions.whereLessThanOrEqualTo(key, value);
        return this;
    }

    public JBQuery<T> whereMatches(String key, String regex) {
        this.conditions.whereMatches(key, regex);
        return this;
    }

    public JBQuery<T> whereMatches(String key, String regex, String modifiers) {
        this.conditions.whereMatches(key, regex, modifiers);
        return this;
    }

    public JBQuery<T> whereNotContainedIn(String key, Collection<? extends Object> values) {
        this.conditions.whereNotContainedIn(key, values);
        return this;
    }

    public JBQuery<T> whereNotEqualTo(String key, Object value) {
        this.conditions.whereNotEqualTo(key, value);
        return this;
    }

    public JBQuery<T> whereStartsWith(String key, String prefix) {
        this.conditions.whereStartsWith(key, prefix);
        return this;
    }

    public static <T extends JBObject> JBQuery<T> or(List<JBQuery<T>> queries) {
        String className = null;
        if (queries.size() > 0) {
            className = ((JBQuery) queries.get(0)).getClassName();
        }

        JBQuery result = JBQuery.getInstance(className);
        if (queries.size() > 1) {

            for (Object query1 : queries) {
                JBQuery query = (JBQuery) query1;
                if (!className.equals(query.getClassName())) {
                    throw new IllegalArgumentException("All queries must be for the same class");
                }

                result.addOrItems(new QueryOperation("$or", "$or", query.conditions.compileWhereOperationMap()));
            }
        } else {
            result.setWhere(((JBQuery) queries.get(0)).conditions.getWhere());
        }

        return result;
    }

    public JBQuery<T> whereMatchesKeyInQuery(String key, String searchKey, String targetClass, JBQuery<?> query) {
        HashMap<String , Object> inner = new HashMap<>();
        inner.put("searchClass", query.getClassName());
        inner.put("where", query.conditions.compileWhereOperationMap());
        if (query.conditions.getSkip() > 0) {
            inner.put("skip", query.conditions.getSkip());
        }

        if (query.conditions.getLimit() > 0) {
            inner.put("limit", query.conditions.getLimit());
        }

        if (!Utils.isBlankContent(query.getOrder())) {
            inner.put("order", query.getOrder());
        }
        inner.put("searchKey", searchKey);
        inner.put("targetClass", targetClass);
        return this.addWhereItem(key, "$sub", inner);
    }

    public JBQuery<T> whereMatchesQuery(String key, JBQuery<?> query) {
        Map map = Utils.createMap("where", query.conditions.compileWhereOperationMap());
        map.put("className", query.className);
        if (query.conditions.getSkip() > 0) {
            map.put("skip", Integer.valueOf(query.conditions.getSkip()));
        }

        if (query.conditions.getLimit() > 0) {
            map.put("limit", Integer.valueOf(query.conditions.getLimit()));
        }

        if (!Utils.isBlankContent(query.getOrder())) {
            map.put("order", query.getOrder());
        }

        this.addWhereItem(key, "$inQuery", map);
        return this;
    }

    public JBQuery<T> whereDoesNotMatchKeyInQuery(String key, String keyInQuery, JBQuery<?> query) {
        Map map = Utils.createMap("className", query.className);
        map.put("where", query.conditions.compileWhereOperationMap());
        Map queryMap = Utils.createMap("query", map);
        queryMap.put("key", keyInQuery);
        this.addWhereItem(key, "$dontSelect", queryMap);
        return this;
    }

    public JBQuery<T> whereDoesNotMatchQuery(String key, JBQuery<?> query) {
        Map map = Utils.createMap("className", query.className);
        map.put("where", query.conditions.compileWhereOperationMap());
        this.addWhereItem(key, "$notInQuery", map);
        return this;
    }

    JBQuery<T> setWhere(Map<String, List<QueryOperation>> value) {
        this.conditions.setWhere(value);
        return this;
    }

    public void deleteAllInBackground(DeleteCallback deleteCallback){
        assembleParameters();
        manager.deleteByQuery(getParameters() , false , deleteCallback);
    }

    public void deleteAll() throws JBException{
        assembleParameters();
        final Object[] objects = new Object[1];
        manager.deleteByQuery(getParameters(), true, new DeleteCallback() {
            @Override
            public void done() {

            }

            @Override
            public void error(JBException e) {
                objects[0] = e;
            }
        });
        if (objects[0] != null)
            throw (JBException) objects[0];
    }

    public List<JBObject> find() throws JBException{
        assembleParameters();
        final Object[] objects = new Object[2];
        manager.objectQuery(getParameters(), true, new FindCallback<JBObject>() {
            @Override
            public void done(List<JBObject> r) {
                objects[0] = r;
            }

            @Override
            public void error(JBException e) {
                objects[1] = e;
            }
        }, cachePolicy);
        if (objects[1] != null)
            throw ((JBException) objects[1]);
        return (List<JBObject>) objects[0];
    }

    public void findInBackground(FindCallback<JBObject> callback) {
        assembleParameters();
        manager.objectQuery(getParameters(), false ,callback, cachePolicy);
    }

    public int count() throws JBException {
        assembleParameters();
        final Object[] objects = new Object[2];
        manager.countQuery(getParameters(), true , new CountCallback() {
            @Override
            public void done(int count) {
                objects[0] = count;
            }

            @Override
            public void error(JBException e) {
                objects[1] = e;
            }
        });
        if (objects[1] != null)
            throw ((JBException) objects[1]);
        return (int) objects[0];
    }

    public void countInBackground(CountCallback callback) {
        assembleParameters();
        manager.countQuery(getParameters(), false , callback);
    }

    protected Map<String, String> assembleParameters() {
        return this.conditions.assembleParameters();
    }

    public enum CachePolicy {
        CACHE_ELSE_NETWORK,
        CACHE_ONLY,
        CACHE_THEN_NETWORK,
        IGNORE_CACHE,
        NETWORK_ELSE_CACHE,
        NETWORK_ONLY;

        private CachePolicy() {
        }
    }
} public class ResponseEntity {
    private int code;
    private String message;
    private Map<String,Object> data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Map<String, Object> getData() {
        return data;
    }

    public void setData(Map<String, Object> data) {
        this.data = data;
    }

} public interface CloudCallback {
    void done(ResponseEntity responseEntity);
    void error(JBException e , ResponseEntity responseEntity);
} public interface CountCallback {
    void done(int count);
    void error(JBException e);
} public interface DeleteCallback {
    void done();
    void error(JBException e);
} public interface FileUploadCallback {
    void done(JBFile jbFile);
    void error(JBException e);
    void onProgress(double percent);
} public interface FindCallback<T> {
    void done(List<T> result);
    void error(JBException e);
} public interface RequestCallback {
    void done();
    void error(JBException e);
} public interface SaveCallback {
    void done(JBObject object);
    void error(JBException e);
} public class JBException extends Exception {
    /**
     * 认证失败
     */
    public static int AUTH_FAILURE_ERROR = 1;

    /**
     * 网络错误
     */
    public static int NETWORK_ERROR = 2;

    /**
     * 解析错误
     */
    public static int PARSE_ERROR = 3;

    /**
     * 服务器错误
     */
    public static int SERVER_ERROR = 4;

    /**
     * 云方法错误
     */
    public static int CLOUD_ERROR = 5;

    /**
     * 上传错误
     */
    public static int UPLOAD_ERROR = 6;

    //responseErrorCode
    public static int SESSION_TOKEN_ERROR_CODE = 1310;

    public int errorCode;
    public int responseErrorCode;
    public String responseErrorMsg;

    public JBException() {
    }

    public JBException(String detailMessage) {
        super(detailMessage);
    }

    public JBException(int errorCode , String detailMessage) {
        super(detailMessage);
        this.errorCode = errorCode;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public int getResponseErrorCode() {
        return responseErrorCode;
    }

    public String getResponseErrorMsg() {
        return responseErrorMsg;
    }
}
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.Toast;
import com.javabaas.JBCloud;
import com.javabaas.JBFile;
import com.javabaas.JBObject;
import com.javabaas.JBQuery;
import com.javabaas.ResponseEntity;
import com.javabaas.callback.CloudCallback;
import com.javabaas.callback.CountCallback;
import com.javabaas.callback.DeleteCallback;
import com.javabaas.callback.FileUploadCallback;
import com.javabaas.callback.FindCallback;
import com.javabaas.callback.RequestCallback;
import com.javabaas.callback.SaveCallback;
import com.javabaas.exception.JBException;
import java.io.File;
import java.util.HashMap;
import java.util.List;
    }


    public void onIncrement(View view) {
        final JBObject testC = JBObject.createWithoutData("testC", "928ca972d4e04912ab9ef6f1de214a02");
        String s = amountEt.getText().toString();
        final Integer amount ;
        if (TextUtils.isEmpty(s))
            amount = 1;
        else
            amount = Integer.parseInt(s);
        if (isSync){
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    Message msg = Message.obtain();
                    try {
                        testC.incrementKey("testInt" , amount);
                        msg.obj = "同步自增"+amount+"成功";
                    } catch (JBException e) {
                        e.printStackTrace();
                        msg.obj = "同步自增"+amount+"失败";
                    }
                    handler.sendMessage(msg);
                }
            }.start();
        }else {
            testC.incrementKeyInBackground("testInt", amount, new RequestCallback() {
                @Override
                public void done() {
                    showToast(MainActivity.this , "异步自增"+amount+"成功");
                }

                @Override
                public void error(JBException e) {
                    showToast(MainActivity.this ,"异步自增"+amount+"失败");
                }
            });
        }
    }

    @Override
    public void onClick(View v) {
    }

    Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            Toast.makeText(MainActivity.this, msg.obj.toString(), Toast.LENGTH_SHORT).show();
            return false;
        }
    });

    public static Toast toast = null;

    public static void showToast(Context context ,String msg) {
        if (toast == null) {
            toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
        } else {
            toast.setText(msg);
        }
        toast.show();
    }


    public void onSignUp(View view) {
        startActivity(new Intent(this , UserActivity.class));
    }

    public void onRegexQuery(View view) {
        final JBQuery jbQuery = JBQuery.getInstance("testC");
        jbQuery.whereMatches("testA" , "^z");
        //jbQuery.whereStartsWith("testA" , "张");
        //jbQuery.whereEndsWith("testA" , "四");
        //jbQuery.whereContains("testA" , "Z");
        jbQuery.findInBackground(new FindCallback<JBObject>() {
            @Override
            public void done(List<JBObject> result) {
                for (JBObject jbObject : result) {
                    System.out.println(((String) jbObject.get("testA")));
                }
            }

            @Override
            public void error(JBException e) {
                System.out.println(e.getResponseErrorCode());
            }
        });
    }

    private void showFileChooser() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("*/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);

        try {
            startActivityForResult( Intent.createChooser(intent, "Select a File to Upload"), 100);
        } catch (android.content.ActivityNotFoundException ex) {
            Toast.makeText(this, "Please install a File Manager.",  Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)  {
        switch (requestCode) {
            case 100:
                if (resultCode == RESULT_OK) {
                    // Get the Uri of the selected file
                    Uri uri = data.getData();
                    String path = getPath(this, uri);
                    if (TextUtils.isEmpty(path)){
                        showToast(this , "文件错误");
                        return;
                    }
                    final File file = new File(path);

                    final ProgressDialog progressDialog = new ProgressDialog(this);
                    progressDialog.show();
                    progressDialog.setMax((int) file.length());
                    new JBFile(file).saveInBackground(new FileUploadCallback() {