Dump Json serializable object to file.
    Provides multiple choice to customize the behavior.

    :param js: Serializable python object.
    :type js: dict or list

    :param abspath: ``save as`` path, file extension has to be ``.json`` or ``.gz``
        (for compressed json).
    :type abspath: string

    :param fastmode: (default False) If ``True``, then dumping json without
        sorted keys and pretty indent, and it's faster and smaller in size.
    :type fastmode: boolean

    :param replace: (default False) If ``True``, when you dump json to a existing
        path, it silently overwrite it. If False, an exception will be raised.
        Default False setting is to prevent overwrite file by mistake.
    :type replace: boolean

    :param compress: (default False) If ``True``, use GNU program gzip to
        compress the json file. Disk usage can be greatly reduced. But you have
        to use :func:`load_js(abspath, compress=True)<load_js>` in loading.
    :type compress: boolean

    :param enable_verbose: (default True) Trigger for message.
    :type enable_verbose: boolean

    Usage::

        >>> from weatherlab.lib.dataIO.js import dump_js
        >>> js = {"a": 1, "b": 2}
        >>> dump_js(js, "test.json", replace=True)
        Dumping to test.json...
            Complete! Elapse 0.002432 sec

    **中文文档**

    将Python中可被序列化的"字典", "列表"以及他们的组合, 按照Json的编码方式写入文件
    文件

    参数列表

    :param js: 可Json化的Python对象
    :type js: ``字典`` 或 ``列表``

    :param abspath: 写入文件的路径。扩展名必须为``.json``或``.gz``, 其中gz用于被压
        缩的Json
    :type abspath: ``字符串``

    :param fastmode: (默认 False) 当为``True``时, Json编码时不对Key进行排序, 也不
        进行缩进排版。这样做写入的速度更快, 文件的大小也更小。
    :type fastmode: "布尔值"

    :param replace: (默认 False) 当为``True``时, 如果写入路径已经存在, 则会自动覆盖
        原文件。而为``False``时, 则会抛出异常。防止误操作覆盖源文件。
    :type replace: "布尔值"

    :param compress: (默认 False) 当为``True``时, 使用开源压缩标准gzip压缩Json文件。
        通常能让文件大小缩小10-20倍不等。如要读取文件, 则需要使用函数
        :func:`load_js(abspath, compress=True)<load_js>`.
    :type compress: "布尔值"

    :param enable_verbose: (默认 True) 是否打开信息提示开关, 批处理时建议关闭.
    :type enable_verbose: "布尔值"

def dump_js(js, abspath, precision=None,
            fastmode=False, replace=False, compress=False, enable_verbose=True):
    """Dump Json serializable object to file.
    Provides multiple choice to customize the behavior.

    :param js: Serializable python object.
    :type js: dict or list

    :param abspath: ``save as`` path, file extension has to be ``.json`` or ``.gz``
        (for compressed json).
    :type abspath: string

    :param fastmode: (default False) If ``True``, then dumping json without
        sorted keys and pretty indent, and it's faster and smaller in size.
    :type fastmode: boolean

    :param replace: (default False) If ``True``, when you dump json to a existing
        path, it silently overwrite it. If False, an exception will be raised.
        Default False setting is to prevent overwrite file by mistake.
    :type replace: boolean

    :param compress: (default False) If ``True``, use GNU program gzip to
        compress the json file. Disk usage can be greatly reduced. But you have
        to use :func:`load_js(abspath, compress=True)<load_js>` in loading.
    :type compress: boolean

    :param enable_verbose: (default True) Trigger for message.
    :type enable_verbose: boolean

    Usage::

        >>> from weatherlab.lib.dataIO.js import dump_js
        >>> js = {"a": 1, "b": 2}
        >>> dump_js(js, "test.json", replace=True)
        Dumping to test.json...
            Complete! Elapse 0.002432 sec

    **中文文档**

    将Python中可被序列化的"字典", "列表"以及他们的组合, 按照Json的编码方式写入文件
    文件

    参数列表

    :param js: 可Json化的Python对象
    :type js: ``字典`` 或 ``列表``

    :param abspath: 写入文件的路径。扩展名必须为``.json``或``.gz``, 其中gz用于被压
        缩的Json
    :type abspath: ``字符串``

    :param fastmode: (默认 False) 当为``True``时, Json编码时不对Key进行排序, 也不
        进行缩进排版。这样做写入的速度更快, 文件的大小也更小。
    :type fastmode: "布尔值"

    :param replace: (默认 False) 当为``True``时, 如果写入路径已经存在, 则会自动覆盖
        原文件。而为``False``时, 则会抛出异常。防止误操作覆盖源文件。
    :type replace: "布尔值"

    :param compress: (默认 False) 当为``True``时, 使用开源压缩标准gzip压缩Json文件。
        通常能让文件大小缩小10-20倍不等。如要读取文件, 则需要使用函数
        :func:`load_js(abspath, compress=True)<load_js>`.
    :type compress: "布尔值"

    :param enable_verbose: (默认 True) 是否打开信息提示开关, 批处理时建议关闭.
    :type enable_verbose: "布尔值"
    """
    abspath = str(abspath)  # try stringlize

    if precision is not None:
        encoder.FLOAT_REPR = lambda x: format(x, ".%sf" % precision)
    
    msg = Messenger(enable_verbose=enable_verbose)

    if compress:  # check extension name
        root, ext = os.path.splitext(abspath)
        if ext != ".gz":
            if ext != ".tmp":
                raise Exception("compressed json has to use extension '.gz'!")
            else:
                _, ext = os.path.splitext(root)
                if ext != ".gz":
                    raise Exception(
                        "compressed json has to use extension '.gz'!")
    else:
        root, ext = os.path.splitext(abspath)
        if ext != ".json":
            if ext != ".tmp":
                raise Exception("file extension are not '.json'!")
            else:
                _, ext = os.path.splitext(root)
                if ext != ".json":
                    raise Exception("file extension are not '.json'!")

    msg.show("\nDumping to %s..." % abspath)
    st = time.clock()

    if os.path.exists(abspath):  # if exists, check replace option
        if replace:  # replace existing file
            if fastmode:  # no sort and indent, do the fastest dumping
                if compress:
                    with gzip.open(abspath, "wb") as f:
                        f.write(json.dumps(js).encode("utf-8"))
                else:
                    with open(abspath, "wb") as f:
                        f.write(json.dumps(js).encode("utf-8"))
            else:
                if compress:
                    with gzip.open(abspath, "wb") as f:
                        f.write(json.dumps(js, sort_keys=True,
                                           indent=4, separators=(",", ": ")).encode("utf-8"))
                else:
                    with open(abspath, "wb") as f:
                        f.write(json.dumps(js, f, sort_keys=True,
                                           indent=4, separators=(",", ": ")).encode("utf-8"))
        else:  # stop, print error message
            raise Exception("\tCANNOT WRITE to %s, it's already "
                            "exists" % abspath)

    else:  # if not exists, just write to it
        if fastmode:  # no sort and indent, do the fastest dumping
            if compress:
                with gzip.open(abspath, "wb") as f:
                    f.write(json.dumps(js).encode("utf-8"))
            else:
                with open(abspath, "wb") as f:
                    f.write(json.dumps(js).encode("utf-8"))
        else:
            if compress:
                with gzip.open(abspath, "wb") as f:
                    f.write(json.dumps(js, sort_keys=True,
                                       indent=4, separators=(",", ": ")).encode("utf-8"))
            else:
                with open(abspath, "wb") as f:
                    f.write(json.dumps(js, sort_keys=True,
                                       indent=4, separators=(",", ": ")).encode("utf-8"))

    msg.show("    Complete! Elapse %.6f sec" % (time.clock() - st))