import requests
import json
from IPython.display import display
from IPython.display import Image

# Basic Setup
PORT_NUMBER = 1234
BASE = 'http://localhost:' + str(PORT_NUMBER) + '/v1/'
HEADERS = {'Content-Type': 'application/json'}

# Utility function to print result (JSON Printer)
def jp(data):
    print(json.dumps(data, indent=4))

"""
Explanation: cyREST Cookbook for Python Users
by Keiichiro Ono
Ver. 0.0.3
Introduction
This is a collection of small sample code to call basic cyREST API.
IMPORTANT: Please Try py2cytoscape
Using raw REST API is OK, but you can use py2cytoscape wrapper to call it.  You can write your code more Pythonic-way!

py2cytoscape Project Web Site
End of explanation
"""


res = requests.delete(BASE + 'session')
jp(res.json())

"""
Explanation: 0. Start from scratch: Delete current session
End of explanation
"""


# URL Parameters
url_params = {
    'source': 'url',
    'collection': 'Your Collection Name'
}

# Array of data source.  URL of the file (remote or local) 
network_files = [
    'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif'
    # And of course, you can add as many files as you need...
]

# Load network from URLs
res = requests.post(BASE + 'networks', params=url_params, data=json.dumps(network_files), headers=HEADERS)
jp(res.json())

suid = res.json()[0]['networkSUID'][0]

# Make a utility to get first SUID
def get_suid(response):
    return res.json()[0]['networkSUID'][0]

"""
Explanation: 1. Load a network from file / URL
End of explanation
"""


# Let's make a utility function
def show(network_id):
    url = BASE+'networks/' + str(network_id) + '/views/first.png'
    print('Your image is available here: ' + url)
    display(Image(url=url, embed=True))

# Call it!
show(suid)

"""
Explanation: 2. Get the current network view as a PNG image (embedded)
End of explanation
"""


res = requests.get(BASE + 'apply/layouts')
jp(res.json())

"""
Explanation: 3. Get list of available layout algorithms
End of explanation
"""


res = requests.get(BASE + 'apply/layouts/force-directed/' + str(suid))
show(suid)

"""
Explanation: 4. Apply layout
End of explanation
"""


res = requests.get(BASE + 'styles')
jp(res.json())

"""
Explanation: 5. Get all Visual Style Names
End of explanation
"""


res = requests.get(BASE + 'apply/styles/Directed/' + str(suid))
show(suid)

"""
Explanation: 6. Apply a Visual Style to a network view
End of explanation
"""


res = requests.get(BASE + 'styles/Directed')
#jp(res.json())

"""
Explanation: 7. Get all details of a Visual Style
End of explanation
"""


res = requests.get(BASE + 'styles/Directed/defaults')
#jp(res.json())

"""
Explanation: 8. Get all default values of a Visual Style
End of explanation
"""


res = requests.get(BASE + 'styles/Directed/mappings')
jp(res.json())

"""
Explanation: 9. Get all mappings for a Visual Style
End of explanation
"""


# Simply define a key-value pairs of visual properties
new_defaults = [
    {
        'visualProperty': 'EDGE_WIDTH',
        'value': 12
    },
    {
        'visualProperty': 'EDGE_STROKE_UNSELECTED_PAINT',
        'value': '#00abff'
    }
]

res = requests.put(BASE + 'styles/Directed/defaults', data=json.dumps(new_defaults), headers=HEADERS)
show(suid)

"""
Explanation: 10. Change default value(s) of a Visual Style
End of explanation
"""


res = requests.get(BASE + 'networks/' + str(suid) + '/views')
jp(res.json())
view_id = res.json()[0]

"""
Explanation: 11. Get network view object IDs
End of explanation
"""


view_url = BASE + 'networks/' + str(suid) + '/views/' + str(view_id)

res = requests.get(view_url)
cyjs_network = res.json()
# jp(cyjs_network)

"""
Explanation: 12. Get a view object in Cytoscape.js format
End of explanation
"""


# Pick a node from the network
node_suid = cyjs_network['elements']['nodes'][0]['data']['SUID']

new_values = [
    {
        'visualProperty': 'NODE_WIDTH',
        'value': 300
    },
    {
        'visualProperty': 'NODE_HEIGHT',
        'value': 300
    },
    {
        'visualProperty': 'NODE_FILL_COLOR',
        'value': 'orange'
    },
    {
        'visualProperty': 'NODE_SHAPE',
        'value': 'diamond'
    }
]

res = requests.put(view_url + '/nodes/' + str(node_suid), data=json.dumps(new_values), headers=HEADERS)
show(suid)

# Update network view values
scale_url = view_url + '/network/NETWORK_SCALE_FACTOR'
res = requests.get(scale_url)

print(scale_url)
jp(res.json())

new_values = [
    {
        'visualProperty': 'NETWORK_BACKGROUND_PAINT',
        'value': '#aaaaaa'
    },
    {
        'visualProperty': 'NETWORK_SCALE_FACTOR',
        'value': 2.7
    }
]

res = requests.put(view_url + '/network', data=json.dumps(new_values), headers=HEADERS)

"""
Explanation: 13. Set value(s) to a view object
End of explanation
"""


# Essentially, this is just a new value in selection
new_values = [
    {
        'SUID': node_suid,
        'value': True
    }
]

res = requests.put(BASE + 'networks/' + str(suid) + '/tables/defaultnode/columns/selected', data=json.dumps(new_values), headers=HEADERS)
show(suid)

# Deselect
new_values = [
    {
        'SUID': node_suid,
        'value': False
    }
]

res = requests.put(BASE + 'networks/' + str(suid) + '/tables/defaultnode/columns/selected', data=json.dumps(new_values), headers=HEADERS)
show(suid)

"""
Explanation: 14. Select/ Deselect a node
End of explanation
"""


res = requests.put(BASE + 'networks/' + str(suid) + '/tables/defaultnode/columns/selected?default=true', data={}, headers=HEADERS)
show(suid)

"""
Explanation: 15. Set a value to the entire column
New in 0.9.11
End of explanation
"""


# TODO

"""
Explanation: 16. Create Visual Mappings
End of explanation
"""


matched_url = BASE + 'networks/' +str(suid) + '/nodes?column=selected&query=true'
res = requests.get(matched_url)

print(matched_url)

# This is an array
result = res.json()
print('Number of selected nodes = ' + str(len(result)))

"""
Explanation: 17. Select nodes or edges by query
End of explanation
"""


# Prepare new table data.  This format is a bit redundant, but is a standard JSON way to store values.
new_table_data = {
    'key': 'name',  # Key in the existing table.  In this case, "name" column in default node table.
    'dataKey': 'uniprot_id',  # Mapping key ih the new data.  If this value maches to the "name" value, data will be assigned to the row.
    'data': [
         {
            'uniprot_id': 'YBR190W',
            'sgd':'S000000394',
            'description': 'Dubious open reading frame',
            'molecular_weight': 11036.8
        }, {
            'uniprot_id': 'YOL059W',
            'sgd':'S000005420',
            'description': 'NAD-dependent glycerol 3-phosphate dehydrogenase',
            'molecular_weight': 49418.2
        }
    ]
}


# PUT the new data to default node table
res = requests.put(BASE + 'networks/' + str(suid) + '/tables/defaultnode', data=json.dumps(new_table_data), headers=HEADERS)

"""
Explanation: 18. Upload new values to table
End of explanation
"""


res = requests.get(BASE + 'apply/layouts/force-directed')
jp(res.json())

params= [
    {
        'name': 'defaultNodeMass',
        'value': 10
    },
        {
        'name': 'defaultSpringLength',
        'value': 100
    },
    {
        'name': 'isDeterministic',
        'value': True
    }
]
res = requests.put(BASE + 'apply/layouts/force-directed', data=json.dumps(params), headers=HEADERS)


"""
Explanation: Advanced Features
Get optional layout parameters
End of explanation
"""


res = requests.get(BASE + 'ui/panels')
jp(res.json())

panel_state = [
    {
        "state": "DOCK", 
        "name": "SOUTH"
    }, 
    {
        "state": "FLOAT", 
        "name": "SOUTH_WEST"
    }
]
res = requests.put(BASE + 'ui/panels', data=json.dumps(panel_state), headers=HEADERS)

"""
Explanation: Get and Set GUI Panel States
End of explanation
"""


