from browser import document
import json
from visualife.core import CanvasViewport,HtmlViewport
from visualife.core.styles import make_brighter
from visualife.widget import SequenceViewer, SecondaryStructureViewer, AjaxCommunication, StructureViewer

residues_clicked = {}       # --- Dictionary stores residues that are currently in "stick" representations
first_res_id = 1
N_res = 0
sec, panel3d, ss2_ajax = None, None, None
sequence, ss2_str, pdb_name = "", "", ""
E, H = [], []


def sse_to_regions(sse_list, ss_name, ss_color):
    """Creates clickable sequence regions based on a protein's secondary structure"""
    global sec
    i = 1
    for sse in sse_list:
        name = "%s %d" % (ss_name, i)
        sec.add_to_region(name.replace(' ', '-'), first_pos=sse[0], last_pos=sse[1],
                          color=ss_color, tooltip=name, show_in_legend=False, by_residue_id=True)
        i += 1


def click_on_block(evt):
    """Function called when you click on a secondary structure block"""
    global sec, panel3d, sequence
    # Check which region was clicked
    pos = int(evt.target.id.split("-")[3])  # evt.target.is is like: "ch-1-show_sequence-15" for pos 15
    reg_name, region = sec.region_for_position(pos)
    if region is None: return
    color = "red" if reg_name.startswith("helix") else "blue"
    panel3d.remove_style("1")

    panel3d.add_style("1", 'cartoon',
                      {"color": "white", "sele": "%d-%d" % (first_res_id, first_res_id + len(sequence))})
    if region[0][2] - region[0][1] <= 2:
        panel3d.add_style("1", 'cartoon', {"color": color, "sele": "%d-%d" % (region[0][1] + first_res_id - 1, region[0][2] + first_res_id + 1)})
    else:
        panel3d.add_style("1", 'cartoon', {"color": color, "sele": "%d-%d" % (region[0][1] + first_res_id, region[0][2] + first_res_id)})


def click_on_aa(evt):
    """Function called when you click on a letter in amino acid sequence"""
    global panel3d, sequence, resi_repr
    pos = int(evt.target.id.split("-")[3]) - 1 # evt.target.id is like: "ch-show_sequence-15" for pos 15
    if pos in residues_clicked:
        evt.target.style.backgroundColor = residues_clicked[pos]
        panel3d.remove_style("1",resi_repr[pos])
        del(residues_clicked[pos])
    else:
        resi_repr[pos] = panel3d.add_style("1", "licorice", {"color": "atomindex", "sele": "%d" % (pos + first_res_id)})
        residues_clicked[pos] = evt.target.style.backgroundColor
        evt.target.style.backgroundColor = "yellow"


def binding_site(req):
    """Gets info about binding sites and creates according regions on SequenceViewer"""
    global sequence, pdb_name, ss2_str, E, H
    seq = SequenceViewer("show_sequence", pdb_name, sequence, n_columns_of_ten=4, first_residue_id=first_res_id)
    seq.secondary_structure = ss2_str
    seq.set_event_callback("CLICK_ON_LETTER", click_on_aa)

    seq.regions_palette = "accent"
    output = json.loads(req.text)[pdb_name]
    for site in output:
        desc = site["details"].split()
        desc_str = ""
        for i in desc[:4]:
            desc_str += i.lower() + " "
        for i in desc[4:]:
            desc_str += i + " "
        i = 0
        if desc[-3] in ["GOL", "PO4", "SO4", "HOH"]: continue  # --- remove obvious buffer compounds from the list of ligands
        for res in site["site_residues"]:
            i += 1
            aa = res["author_residue_number"]
            seq.add_to_region(desc_str, first_pos=aa, by_residue_id=True, tooltip=desc_str)


def receive_secondary(ss2_req):
    """Gets secondary structure, creates ss2 string and SecondaryStructureViewer widget"""
    global N_res, pdb_name, sec, ss2_str, E, H, first_res_id
    ss_dic = json.loads(ss2_req.text)[pdb_name]["molecules"][0]["chains"][0]["secondary_structure"]
    for i in ss_dic.get("strands", []):
        E.append([i["start"]["author_residue_number"], i["end"]["author_residue_number"]])
    for i in ss_dic.get("helices", []):
        H.append([i["start"]["author_residue_number"], i["end"]["author_residue_number"]])

    ss2 = ["C" for i in range(N_res)]
    for i in E:
        for n in range(i[0], i[1] + 1):
            ss2[n - first_res_id] = "E"
    for i in H:
        for n in range(i[0], i[1] + 1):
            ss2[n - first_res_id] = "H"
    ss2_str = ""
    for i in ss2:
        ss2_str += i
    sec = SecondaryStructureViewer("show_secondary", "%s - secondary structure" % pdb_name, ss2_str, n_columns_of_ten=4,
                                   first_residue_id=first_res_id)
    sec.set_event_callback("CLICK_ON_LETTER", click_on_block)
    sse_to_regions(H, "helix", make_brighter("red", 0.9))
    sse_to_regions(E, "strand", make_brighter("blue", 0.9))


def receive_structure(ajax_pdb):
    """Gets PDB file and creates StructureViewer """
    global N_res, panel3d, sequence, ss2_ajax, pdb_name, first_res_id
    # Definition of  menu buttons for the 3D protein viewer
    menu = {"sticks": "as_sticks", "lines": "as_lines", "cartoon": "as_cartoon", "center": "center"}

    panel3d = StructureViewer("show_3d", backgroundColor="white", width=350, height=350, menu_buttons=menu)
    panel3d.add_model("1", ajax_pdb.text)


def receive_sequence(ajax):
    """Sets the sequence and calls download of binding site and secondary structure"""
    global N_res, sequence, resi_repr, pdb_name
    d = json.loads(ajax.text)
    sequence = d[pdb_name][0]["sequence"]
    N_res = len(sequence)
    resi_repr = [None for i in range(N_res)]
    binding = AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/binding_sites/%s" % pdb_name, binding_site, "GET")
    ss2_ajax()
    binding()


def set_first_res(req):
    """Sets the number of first residue in the chain"""
    global pdb_name, first_res_id
    data = json.loads(req.text)
    first_res_id = data[pdb_name]["molecules"][0]["chains"][0]["residues"][0]["author_residue_number"]


def receive_protein_description(req):
    """Gets the description of the protein"""
    data = json.loads(req.text)
    description = data[pdb_name][0]["title"]
    document["loading"].text = description.lower().capitalize()


def download_data(evt=None):
    """Downloads sequence, structure and description of the protein"""
    global pdb_name, ss2_ajax, panel3d, residues_clicked, first_res_id, N_res, sec, sequence, ss2_str, E, H
    residues_clicked = {}
    first_res_id = 1
    N_res = 0
    sec, panel3d, ss2_ajax = None, None, None
    sequence, ss2_str, pdb_name = "", "", ""
    E, H = [], []
    if panel3d:
        panel3d.remove_model("1")
    document["loading"].text="Downloading structure..."
    pdb_name = document["name"].value
    pdb_ajax = AjaxCommunication("https://files.rcsb.org/view/%s.pdb" % pdb_name, receive_structure)
    pdb_ajax()                          # --- call the object that has been just created in the line above
    # --- the remaining AJAX calls in a shorter, single-line syntax
    AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/residue_listing/%s" % pdb_name, set_first_res, "GET")()
    AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/molecules/%s" % pdb_name, receive_sequence, "GET")()
    AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary/%s" % pdb_name, receive_protein_description, "GET")()
    # --- AJAX object for secondary structure will be called later
    ss2_ajax = AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/secondary_structure/%s" % pdb_name, receive_secondary, "GET")


document["load"].bind("click", download_data)
