"""
Tools for using google chart.
Copyright Schrodinger, LLC. All rights reserved.
"""
# Contributors: Yujie Wu
from past.utils import old_div
SIMPLE_ENCODING_RESOLUTION = 62
SIMPLE_ENCODING_RANGE = (0, SIMPLE_ENCODING_RESOLUTION - 1)
SIMPLE_ENCODING_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
SIMPLE_CODE = []
for c in SIMPLE_ENCODING_CHAR:
    SIMPLE_CODE.append(c)
EXTENDED_ENCODING_RESOLUTION = 4096
EXTENDED_ENCODING_RANGE = (0, EXTENDED_ENCODING_RESOLUTION - 1)
EXTENDED_ENCODING_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-"
EXTENDED_CODE = []
for c in EXTENDED_ENCODING_CHAR:
    for d in EXTENDED_ENCODING_CHAR:
        EXTENDED_CODE.append(c + d)
# Color code: RRGGBBTT. Examples:
#
#    FF0000 = Red
#    00FF00 = Green
#    0000FF = Blue
#    000000 = Black
#    FFFFFF = White
#
# TT is an optional field, indicating the transparency. Value 00 is completely transparent, and FF is completely opaque.
#
#    0000FFFF = Solid blue
#    0000FF66 = Transparent blue
COLOR_CODE = [
    "000000",
    "FF0000",
    "00FF00",
    "0000FF",
    "800080",
    "FFFF00",
    "FFA500",
    "FF00FF",
    "87CEEB",
    "FFD700",
    "C0C0C0",
]
COLOR_NAME = [
    "black",
    "red",
    "green",
    "blue",
    "purple",
    "yellow",
    "orange",
    "violet",
    "skyblue",
    "gold",
    "grey",
]
URL_CHAR_MAP = {
    "$": "%24",
    "&": "%26",
    "+": "%2B",
    ",": "%2C",
    "/": "%2F",
    ":": "%3A",
    ";": "%3B",
    "=": "%3D",
    "?": "%3F",
    "@": "%40",
    "|": "%7C",
    " ": "+",
    "\n": "|",
    "#": "%23",
    "%": "%25",
}
[docs]def urlencode(s):
    """
    """
    ret = ""
    n = len(s)
    for i in range(n):
        if (s[i] < " " and s[i] != "\n"):
            continue
        if (s[i] in URL_CHAR_MAP):
            ret += URL_CHAR_MAP[s[i]]
        else:
            ret += s[i]
    return ret 
[docs]def encode_simple(values):
    """
    """
    ret = ""
    for v in values:
        if (v is None or v < 0):
            ret += "_"
        else:
            ret += SIMPLE_CODE[int(v)]
    return ret 
[docs]def encode_extended(values):
    """
    """
    ret = ""
    for v in values:
        if (v is None or v < 0):
            ret += "__"
        else:
            ret += EXTENDED_CODE[int(v)]
    return ret 
[docs]def compile_xy(x, *y, **kw):
    """
    """
    encoding_scheme = kw["encoding_scheme"] if ("encoding_scheme"
                                                in kw) else "simple"
    shown_data = kw["shown_data"] if ("shown_data" in kw) else -1
    show_x = kw["show_x"] if ("show_x" in kw) else False
    x_min, x_max = kw["x_range"] if ("x_range" in kw) else (
        min(x),
        max(x),
    )
    y_min, y_max = kw["y_range"] if ("y_range" in kw) else (
        min([min(e) for e in y]),
        max([max(e) for e in y]),
    )
    x_span = x_max - x_min
    y_span = y_max - y_min
    plot_x_min = x_min - x_span * 0.0
    plot_x_max = x_max + x_span * 0.1
    plot_x_span = plot_x_max - plot_x_min
    plot_y_min = y_min - y_span * 0.0
    plot_y_max = y_max + y_span * 0.1
    plot_y_span = plot_y_max - plot_y_min
    resolution = EXTENDED_ENCODING_RESOLUTION if (
        encoding_scheme == "extended") else SIMPLE_ENCODING_RESOLUTION
    x_delta = old_div(plot_x_span, resolution)
    y_delta = old_div(plot_y_span, resolution)
    if (show_x):
        x_ = []
        for e in x:
            x_.append(int(old_div((e - plot_x_min), x_delta)))
    data = []
    for this_y in y:
        d = []
        for e in this_y:
            d.append(int(old_div((e - plot_y_min), y_delta)))
        data.append(d)
    num_data = len(x_) if (show_x) else 0
    for d in data:
        num_data += len(d)
    if (num_data > 1792):
        # Too many data. We have to shrink the amount of data.
        sample_rate = old_div(num_data, 1792.0)
        new_data = []
        for d in data:
            new_d = []
            num_d = len(d)
            i = 0
            while (i < num_d):
                new_d.append(d[int(i)])
                i += sample_rate
            new_data.append(new_d)
        data = new_data
        if (show_x):
            new_x_ = []
            num_x_ = len(x_)
            i = 0
            while (i < num_x_):
                new_x_.append(x_[int(i)])
                i += sample_rate
            x_ = new_x_
    if (encoding_scheme == "extended"):
        s = "chd=e:" if (shown_data < 0) else "chd=e%d:" % (
            (shown_data + 1) if (show_x) else shown_data)
        if (show_x):
            s += encode_extended(x_) + ","
        for d in data:
            s += encode_extended(d) + ","
    else:
        s = "chd=s:" if (shown_data < 0) else "chd=s%d:" % (
            (shown_data + 1) if (show_x) else shown_data)
        if (show_x):
            s += encode_simple(x_) + ","
        for d in data:
            s += encode_simple(d) + ","
    return x_min, x_max, plot_y_min, plot_y_max, s[0:-1] 
MARKER_SYMBOL = None
[docs]def get_xy_url(x, *y, **kw):
    """
    """
    chart_type = "lc"
    if ("chart_type" in kw):
        if (kw["chart_type"] == "scatter"):
            url = "http://chart.apis.google.com/chart?cht=s&"
            chart_type = "s"
            global MARKER_SYMBOL
            if (MARKER_SYMBOL is None):
                MARKER_SYMBOL = {
                    "arrow": "a",
                    "cross": "c",
                    "rectangle": "C",
                    "diamond": "d",
                    "circle": "o",
                    "square": "s",
                    "x": "x",
                }
            if ("marker" in kw):
                symbol, color, size = kw["marker"]
                j = COLOR_NAME.index(color)
                color = COLOR_CODE[j]
                url += "chm=%s,%s,0,-1,%d&" % (
                    MARKER_SYMBOL[symbol],
                    color,
                    size,
                )
        elif (kw["chart_type"] == "line"):
            url = "http://chart.apis.google.com/chart?cht=lc&"
        else:
            raise ValueError("Unsupported chart type: %s" % kw["chart_type"])
    else:
        url = "http://chart.apis.google.com/chart?cht=lc&"
    num_y = len(y)
    err_y = kw["err_y"] if ("err_y" in kw) else []
    if (err_y):
        new_err_y = []
        err_top = []
        err_bot = []
        for this_y, this_err_y in zip(y, err_y):
            for e, f in zip(this_y, this_err_y):
                err_top.append(e + f)
                err_bot.append(e - f)
            new_err_y += [
                err_top,
                err_bot,
            ]
        err_y = new_err_y
    y += tuple(err_y)
    if (chart_type == "s"):
        y_ = y
        y = []
        for e in y_:
            y += e
        x_min, x_max, y_min, y_max, dat_str = compile_xy(x,
                                                         *[
                                                             y,
                                                         ],
                                                         show_x=True,
                                                         **kw)
    else:
        kw["shown_data"] = num_y
        x_min, x_max, y_min, y_max, dat_str = compile_xy(x, *y, **kw)
    size = kw["size"] if ("size" in kw) else (
        300,
        200,
    )
    url += "chs=%dx%d&" % tuple(size)
    x_label = None
    y_label = None
    url += "chxt=x,y"
    if ("x_label" in kw):
        url += ",x"
        x_label = urlencode(kw["x_label"])
    if ("y_label" in kw):
        url += ",y"
        y_label = urlencode(kw["y_label"])
    url += "&"
    if (x_label and y_label):
        url += "chxl=2:|%s|3:|%s&chxp=2,50|3,50&" % (
            x_label,
            y_label,
        )
    elif (x_label):
        url += "chxl=2:|%s&chxp=2,50&" % x_label
    elif (y_label):
        url += "chxl=2:|%s&chxp=2,50&" % y_label
    x_min, x_max = kw["x_range"] if ("x_range" in kw) else (
        x_min,
        x_max,
    )
    y_min, y_max = kw["y_range"] if ("y_range" in kw) else (
        y_min,
        y_max,
    )
    axis_range = "chxr=0,%.4g,%.4g|1,%.4g,%.4g&" % (
        x_min,
        x_max,
        y_min,
        y_max,
    )
    axis_range = axis_range.replace("e+0", "e")
    axis_range = axis_range.replace("e+", "e")
    url += axis_range
    if (chart_type == "lc" or "color" in kw):
        color = kw["color"] if ("color" in kw) else COLOR_CODE
        color_used = []
        num_color = len(color)
        url += "chco="
        for i in range(num_y):
            c = color[i % num_color]
            if (c in COLOR_NAME):
                j = COLOR_NAME.index(c)
                c = COLOR_CODE[j]
            url += "%s," % c
            color_used.append(c)
        url = url[0:-1] + "&"
    # Compiles error bars.
    err_series_index = num_y
    if (err_y):
        url += "chm=E,"
        for i in range(old_div(len(err_y), 2)):
            url += "%s,%d,,1:5" % (
                color_used[i],
                err_series_index,
            )
            err_series_index += 2
        url += "&"
    if ("bg" in kw):
        c = kw["bg"]
        if (c in COLOR_NAME):
            j = COLOR_NAME.index(c)
            c = COLOR_CODE[j]
        url += "chf=bg,s,%s&" % c
    if ("legend" in kw and kw["legend"] is not None):
        legend = kw["legend"]
        url += "chdl="
        for e in legend:
            url += "%s|" % urlencode(e)
        url = url[0:-1] + "&"
    if ("title" in kw):
        url += "chtt=%s&" % urlencode(kw["title"])
    url += dat_str
    return url 
if ("__main__" == __name__):
    import os
    import sys
    argc = len(sys.argv)
    if (1 == argc):
        print(
            "Usage: $SCHRODINGER/run %s <data-file> [x_label [y_label [title [y_range]]]]"
            % sys.argv[0])
        sys.exit(0)
    if (not os.path.isfile(sys.argv[1])):
        print("Data file not found: %s" % sys.argv[1])
        sys.exit(0)
    try:
        x_label = sys.argv[2]
    except IndexError:
        x_label = ""
    try:
        y_label = sys.argv[3]
    except IndexError:
        y_label = ""
    try:
        title = sys.argv[4]
    except IndexError:
        title = ""
    try:
        y_range = sys.argv[5]
        y_range = [float(e) for e in y_range.split()]
    except IndexError:
        y_range = ()
    lines = open(sys.argv[1], "r").read().split("\n")
    x = []
    y = []
    y_err = []
    for line in lines:
        line = line.strip()
        if (line != "" and line[0] != "#"):
            token = line.split()
            x.append(float(token[0]))
            y.append(float(token[1]))
            try:
                y_err.append(float(token[2]))
            except IndexError:
                pass
    if (y_err):
        if (y_range):
            url = get_xy_url(x,
                             y,
                             err_y=[y_err],
                             x_label=x_label,
                             y_label=y_label,
                             title=title,
                             y_range=y_range)
        else:
            url = get_xy_url(x,
                             y,
                             err_y=[y_err],
                             x_label=x_label,
                             y_label=y_label,
                             title=title)
    else:
        if (y_range):
            url = get_xy_url(x,
                             y,
                             x_label=x_label,
                             y_label=y_label,
                             title=title,
                             y_range=y_range)
        else:
            url = get_xy_url(x,
                             y,
                             x_label=x_label,
                             y_label=y_label,
                             title=title)
    print("number of chars in the url:", len(url))
    print(url)
    import schrodinger.application.desmond.util as util
    print(util.html_embed_image(url))