<link rel="import" href="jso-nv-bar.html">
<link rel="import" href="jso-nv-edition-bar.html">
<link rel="import" href="jso-nv-tool-bar.html">
<link rel="import" href="jso-nv-status-bar.html">
<link rel="import" href="jso-nv-layout.html">
<link rel="import" href="../lib/components/jso-window.html">
<link rel="import" href="jso-nv-session-manager.html">
<link rel="import" href="../lib/components/jso-color-picker.html">
<link rel="import" href="../lib/components/jso-color-menu.html">

<script src="../lib/svg.js"></script>
<script src="../lib/utils.js"></script>

<script src="../lib/network/attributes/attribute-manager-memory.js"></script>
<script src="../lib/network/network.js"></script>
<script src="../lib/network/graph.js"></script>
<script src="../lib/network/point.js"></script>
<script src="../lib/network/edge.js"></script>
<script src="../lib/network/vertex.js"></script>
<!--<script src="../lib/network/default-vertex-renderer.js"></script>-->
<script src="../lib/network/circos-vertex-renderer.js"></script>
<script src="../lib/network/default-edge-renderer.js"></script>
<script src="../lib/network/graph-layout.js"></script>

<script src="../lib/data-adapter/network/attribute-network-data-adapter.js"></script>
<script src="../lib/data-adapter/network/json-network-data-adapter.js"></script>
<script src="../lib/data-adapter/network/sif-network-data-adapter.js"></script>
<script src="../lib/data-adapter/network/text-network-data-adapter.js"></script>
<script src="../lib/data-adapter/network/xlsx-network-data-adapter.js"></script>

<script src="../lib/data-source/data-source.js"></script>
<script src="../lib/data-source/file-data-source.js"></script>
<script src="../lib/data-source/string-data-source.js"></script>


<link rel="import" href="../lib/components/network/jso-sif-network-file-open.html">
<link rel="import" href="../lib/components/network/jso-text-network-file-open.html">
<link rel="import" href="../lib/components/network/jso-xlsx-network-file-open.html">
<link rel="import" href="../lib/components/network/jso-attribute-network-file-open.html">
<link rel="import" href="../lib/components/network/jso-network-edit.html">
<link rel="import" href="../lib/components/network/jso-attribute-edit.html">
<link rel="import" href="../lib/components/network/jso-nv-select-filter.html">
<link rel="import" href="../lib/components/network/render-settings/jso-attribute-node-render.html">
<link rel="import" href="../lib/components/network/render-settings/jso-attribute-edge-render.html">
<link rel="import" href="../lib/components/network/render-settings/jso-attribute-render-number-table.html">
<link rel="import" href="../lib/components/network/render-settings/jso-attribute-render-color-table.html">
<link rel="import" href="../lib/components/network/render-settings/jso-attribute-render-select-table.html">

<link rel="import" href="../lib/components/network/jso-cellbase-attribute-import.html">
<link rel="import" href="../lib/components/network/jso-intact-import.html">
<link rel="import" href="../lib/components/network/jso-communities-structure-detection.html">
<link rel="import" href="../lib/components/network/jso-topological-study.html">
<link rel="import" href="../lib/components/network/jso-kegg.html">
<link rel="import" href="../lib/components/network/jso-reactome.html">
<link rel="import" href="../lib/components/network/jso-configure-force-directed.html">

<link rel="import" href="jso-nv-snow.html">
<link rel="import" href="jso-nv-network-miner.html">
<link rel="import" href="jso-nv-fatigo.html">
<link rel="import" href="jso-nv-reactome-fi.html">


<script src="../lib/cellbase-manager.js"></script>

<script src="../../bower_components/d3/d3.min.js"></script>
<script src="../../bower_components/pako/dist/pako.min.js"></script>

<polymer-element name="jso-network-viewer"
                 attributes="hideBar hideToolBar hideEditionBar userData selectedStudy studies jsoHeader lite">
    <template>
        <style>
            :host {
                display: block;
                position: relative;
                height: 100%;
                background-color: #FFFFFF;
            }

            .left-side {
                top: 94px;
                left: 0px;
                position: absolute;
            }

            .right-side {
                top: 94px;
                right: 0px;
                position: absolute;
            }

            jso-nv-layout {
                height: calc(100% - 126px);
            }

            .context {
                min-width: 200px;
            }

            .attr-context {
                font-size: 13px;
            }

            .attrkey {
                color: #888888;
            }

            .attrvalue {
            }
        </style>

        <jso-nv-bar
                lite="{{lite}}"
                hidden?="{{hideBar == 'true'}}"
                columns="{{vAttr.columns}}"

                on-session-start="{{handleSessionStartMenu}}"
                on-session-open="{{handleSessionOpenMenu}}"
                on-session-save="{{handleSessionSaveMenu}}"
                on-session-manage="{{handleSessionManageMenu}}"

                on-import-sif="{{handleImportSifMenu}}"
                on-import-text="{{handleImportTextMenu}}"
                on-import-xlsx="{{handleImportXlsxMenu}}"
                on-import-node-attributes="{{handleImportNodeAttrMenu}}"
                on-import-edge-attributes="{{handleImportEdgeAttrMenu}}"

                on-export-sif="{{handleExportSifMenu}}"
                on-export-svg="{{handleExportSvgMenu}}"
                on-export-png="{{handleExportPngMenu}}"

                on-export-node-attributes="{{handleExportNodeAttrMenu}}"
                on-export-edge-attributes="{{handleExportEdgeAttrMenu}}"

                on-nodes-select-all="{{handleSelectMenu}}"
                on-nodes-select-first-neighbourhood="{{handleSelectMenu}}"
                on-nodes-select-invert="{{handleSelectMenu}}"
                on-edges-select-all="{{handleSelectMenu}}"
                on-edges-select-adjacent="{{handleSelectMenu}}"
                on-network-select-all="{{handleSelectMenu}}"


                on-layout-force-directed="{{handleLayoutMenu}}"
                on-layout-tree="{{handleLayoutMenu}}"
                on-layout-configure-force-directed="{{handleLayoutMenu}}"
                on-layout-circle="{{handleLayoutMenu}}"
                on-layout-random="{{handleLayoutMenu}}"


                on-network-edit="{{handleNetworkEditMenu}}"
                on-nodes-edit="{{handleNodesEditMenu}}"
                on-edges-edit="{{handleEdgesEditMenu}}"
                on-nodes-filter="{{handleNodesFilterMenu}}"
                on-edges-filter="{{handleEdgesFilterMenu}}"
                on-cellbase="{{handleCellbaseMenu}}"


                on-node-simple-rendering="{{handleNodeSimpleRenderingMenu}}"
                on-node-list-rendering="{{handleNodeListRenderingMenu}}"
                on-edge-simple-rendering="{{handleEdgeSimpleRenderingMenu}}"

                on-reactome="{{handleReactomeMenu}}"
                on-kegg="{{handleKeggMenu}}"
                on-intact="{{handleIntactMenu}}"

                on-communities-structure-detection="{{handleCommunitiesMenu}}"
                on-topological-study="{{handleTopologicalMenu}}"


                on-reactome-fi-microarray="{{handleReactomeFiMenu}}"

                on-snow="{{handleSnowMenu}}"
                on-network-miner="{{handleNetworkMinerMenu}}"
                on-fatigo="{{handleFatigoMenu}}"

                on-example="{{handleLoadExampleMenu}}"

                on-save="{{handleSave}}"
                on-configure="{{}}"
                >
        </jso-nv-bar>

        <jso-nv-tool-bar
                lite="{{lite}}"
                hidden?="{{hideToolBar == 'true'}}"
                backgroundColor="{{backgroundColor}}"
                mode="{{mode}}"
                zoom="{{zoom}}"

                on-layoutchange="{{handleLayoutChange}}"
                on-selectchange="{{handleSelectChange}}"
                on-rotatechange="{{handleRotateChange}}"
                on-importbackgroundimage="{{handleImportBackgroundImage}}"
                ></jso-nv-tool-bar>

        <jso-nv-edition-bar
                hidden?="{{hideEditionBar == 'true'}}"
                selectionColor="{{vertexDefaults.selectionColor}}"
                id="editionBar"

                vAttr="{{vAttr}}"
                eAttr="{{eAttr}}"

                on-vertexshape="{{handleVertexShape}}"
                on-vertexopacity="{{handleVertexOpacity}}"
                on-vertexsize="{{handleVertexSize}}"
                on-vertexcolor="{{handleVertexColor}}"
                on-vertexstrokesize="{{handleVertexStrokeSize}}"
                on-vertexstrokecolor="{{handleVertexStrokeColor}}"
                on-vertexlabelsize="{{handleVertexLabelSize}}"
                on-vertexsearch="{{handleVertexSearch}}"
                on-vertexnamefield="{{handleVertexNameField}}"

                on-edgeshape="{{handleEdgeShape}}"
                on-edgesize="{{handleEdgeSize}}"
                on-edgecolor="{{handleEdgeColor}}"
                on-edgelabelsize="{{handleEdgeLabelSize}}"
                on-edgesearch="{{handleEdgeSearch}}"
                on-edgenamefield="{{handleEdgeNameField}}"

                ></jso-nv-edition-bar>

        <jso-nv-layout
                id="networkLayout"
                mode="{{mode}}"
                scale="{{scale}}" tx="{{center.x}}" ty="{{center.y}}"
                zoom="{{zoom}}"
                graph="{{graph}}"

                backgroundColor="{{backgroundColor}}"

                on-createvertex="{{handleCreateVertex}}"
                on-selectvertex="{{handleSelectVertex}}"
                on-moveselectedvertices="{{handleMoveSelectedVertices}}"
                on-selectarea="{{handleSelectArea}}"
                on-createedge="{{handleCreateEdge}}"
                on-removevertex="{{handleRemoveVertex}}"
                on-leftclickvertex="{{handleLeftClickVertex}}"
                on-selectedge="{{handleSelectEdge}}"
                on-leftclickedge="{{handleLeftClickEdge}}"
                on-rightclickvertex="{{handleRightClickVertex}}"
                on-rightclickbackgroundimage="{{handleRightClickBackgroundImage}}"

                ></jso-nv-layout>

        <jso-nv-status-bar networkViewer="{{}}">
        </jso-nv-status-bar>

        <div class="right-side">
            <jso-attribute-node-render
                    id="nodeRender"
                    attributeManager="{{vAttr}}"
                    defaults="{{vertexDefaults}}"
                    visualSets="{{vertexVisualSets}}"
                    on-labelAttribute="{{handleVertexDefaultLabelAttribute}}"
                    on-labelsize="{{handleVertexDefaultLabelSize}}"
                    on-labelpositionx="{{handleVertexDefaultLabelPositionX}}"
                    on-labelpositiony="{{handleVertexDefaultLabelPositionY}}"
                    on-opacity="{{handleVertexDefaultOpacity}}"
                    on-shape="{{handleVertexDefaultShape}}"
                    on-color="{{handleVertexDefaultColor}}"
                    on-strokecolor="{{handleVertexDefaultStrokeColor}}"
                    on-size="{{handleVertexDefaultSize}}"
                    on-strokesize="{{handleVertexDefaultStrokeSize}}"
                    on-area="{{handleVertexDefaultArea}}"
                    on-strokeArea="{{handleVertexDefaultStrokeArea}}"
                    on-xattribute="{{handleVertexDefaultXAttribute}}"
                    on-yattribute="{{handleVertexDefaultYAttribute}}"
                    >
            </jso-attribute-node-render>

            <jso-attribute-edge-render
                    id="edgeRender"
                    attributeManager="{{eAttr}}"
                    defaults="{{edgeDefaults}}"
                    visualSets="{{edgeVisualSets}}"
                    on-labelattribute="{{handleEdgeDefaultLabelAttribute}}"
                    on-labelsize="{{handleEdgeDefaultLabelSize}}"
                    on-opacity="{{handleEdgeDefaultOpacity}}"
                    on-shaft="{{handleEdgeDefaultShaft}}"
                    on-shape="{{handleEdgeDefaultShape}}"
                    on-bidirectional="{{handleEdgeDefaultBidirectional}}"
                    on-color="{{handleEdgeDefaultColor}}"
                    on-size="{{handleEdgeDefaultSize}}"
                    >
            </jso-attribute-edge-render>
        </div>
        <div class="left-side">
            <jso-nv-select-filter
                    hidden
                    id="nodeSelectFilter"
                    filters="{{vertexDefaults.filters}}"
                    attributeManager="{{vAttr}}"
                    networkViewer="{{}}"
                    type="node">
            </jso-nv-select-filter>
            <jso-nv-select-filter
                    hidden
                    id="edgeSelectFilter"
                    filters="{{edgeDefaults.filters}}"
                    attributeManager="{{eAttr}}"
                    networkViewer="{{}}"
                    type="edge">
            </jso-nv-select-filter>
            <jso-network-edit
                    hidden
                    id="networkEdit"
                    networkViewer="{{}}">
            </jso-network-edit>
            <jso-attribute-edit
                    hidden
                    id="nodeAttributeEdit"
                    attributeManager="{{vAttr}}"
                    type="node">
            </jso-attribute-edit>
            <jso-attribute-edit
                    hidden
                    id="edgeAttributeEdit"
                    attributeManager="{{eAttr}}"
                    type="edge">
            </jso-attribute-edit>
            <jso-cellbase-attribute-import
                    hidden
                    id="cellbaseAttributeImport"
                    attributeManager="{{vAttr}}"
                    >
            </jso-cellbase-attribute-import>
            <jso-intact-import
                    hidden
                    id="intactImport"
                    networkViewer="{{}}"
                    >
            </jso-intact-import>
            <jso-communities-structure-detection
                    hidden
                    id="communitiesStructureDetection"
                    networkViewer="{{}}"
                    >
            </jso-communities-structure-detection>
            <jso-topological-study
                    hidden
                    id="topologicalStudy"
                    networkViewer="{{}}"
                    >
            </jso-topological-study>
            <jso-reactome
                    hidden
                    id="reactomeImport"
                    networkViewer="{{}}"
                    >
            </jso-reactome>
            <jso-kegg
                    hidden
                    id="keggImport"
                    networkViewer="{{}}"
                    >
            </jso-kegg>
            <jso-configure-force-directed
                    hidden
                    id="configureForceDirected"
                    networkViewer="{{}}"
                    >
            </jso-configure-force-directed>
            <jso-nv-session-manager
                    hidden
                    id="sessionManager"
                    userData="{{userData}}"
                    selectedMenu="{{selectedMenu}}" networkViewer="{{}}">
            </jso-nv-session-manager>


            <!--Menu file-->
            <template if="{{selectedMenu == 'import-sif'}}">
                <jso-sif-network-file-open
                        selectedMenu="{{selectedMenu}}"
                        on-graph="{{handleImportSif}}">
                </jso-sif-network-file-open>
            </template>

            <template if="{{selectedMenu == 'import-text'}}">
                <jso-text-network-file-open
                        selectedMenu="{{selectedMenu}}"
                        on-graph="{{handleImportText}}">
                </jso-text-network-file-open>
            </template>
            <template if="{{selectedMenu == 'import-xlsx'}}">
                <jso-xlsx-network-file-open selectedMenu="{{selectedMenu}}" on-graph="{{handleImportXlsx}}">
                </jso-xlsx-network-file-open>
            </template>
            <template if="{{selectedMenu == 'import-node-attributes'}}">
                <jso-attribute-network-file-open selectedMenu="{{selectedMenu}}" on-open="{{handleImportNodeAttr}}"
                                                 type="node">
                </jso-attribute-network-file-open>
            </template>
            <template if="{{selectedMenu == 'import-edge-attributes'}}">
                <jso-attribute-network-file-open selectedMenu="{{selectedMenu}}" on-open="{{handleImportEdgeAttr}}"
                                                 type="edge">
                </jso-attribute-network-file-open>
            </template>

        </div>


        <template if="{{selectedMenu == 'networkminer'}}">
            <jso-nv-network-miner
                    selectedOption="{{selectedMenu}}"
                    userData="{{userData}}"
                    selectedStudy="{{selectedStudy}}"
                    studies="{{studies}}"
                    networkViewer="{{}}"
                    >
            </jso-nv-network-miner>
        </template>
        <template if="{{selectedMenu == 'snow'}}">
            <jso-nv-snow
                    selectedOption="{{selectedMenu}}"
                    userData="{{userData}}"
                    selectedStudy="{{selectedStudy}}"
                    studies="{{studies}}"
                    networkViewer="{{}}"
                    >
            </jso-nv-snow>
        </template>
        <template if="{{selectedMenu == 'fatigo'}}">
            <jso-nv-fatigo
                    selectedOption="{{selectedMenu}}"
                    userData="{{userData}}"
                    selectedStudy="{{selectedStudy}}"
                    studies="{{studies}}"
                    networkViewer="{{}}"
                    >
            </jso-nv-fatigo>
        </template>
        <template if="{{selectedMenu == 'reactome-fi-microarray'}}">
            <jso-nv-reactome-fi
                    selectedOption="{{selectedMenu}}"
                    userData="{{userData}}"
                    selectedStudy="{{selectedStudy}}"
                    studies="{{studies}}"
                    networkViewer="{{}}"
                    >
            </jso-nv-reactome-fi>
        </template>


        <ul id="imagecontextmenu" class="context">
            <li on-click="{{handleContextRemoveBackGroundImage}}">Remove</li>
        </ul>

        <ul id="vertexcontextmenu" class="context">
            <li on-click="{{handleContextRemoveVertex}}">Delete</li>
            <li data-divider hidden?="{{ vAttr.selected.length < 2 }}"></li>
            <li on-click="{{handleContextRemoveSelectedVertices}}" hidden?="{{ vAttr.selected.length < 2 }}">Delete
                Selected
            </li>
            <li data-divider></li>
            <li on-click="{{handleContextSelectVerticesNeighbour}}">Select first neighbour nodes</li>
            <li on-click="{{handleContextSelectEdgesNeighbour}}">Select Adjacent edges</li>
            <li data-divider></li>
            <li data-text><u>Attributes</u></li>
            <li data-text>
                <div class="attr-context" vertical layout>
                    <template repeat="{{ attr in _lastContextVertexAttributes }}">
                        <div data-text><span class="attrkey">{{ attr.key }}:</span> <span class="attrvalue">{{ attr.value }}</span></div>
                    </template>
                </div>
            </li>
        </ul>

    </template>
    <script>
        Polymer({
            created: function () {
                this.lite = "false";

                this.lastLoadedFileName = "";

                this.serializeVersion = 'v1';
                this.serializeKey = 'NV_CURRENT_SESSION' + this.serializeVersion;

                this._init();

                this.mode = "select";
                this.scale;
            },
            ready: function () {
                var me = this;
                document.body.addEventListener('click', function (e) {
                    me.$.imagecontextmenu.style.opacity = "";
                    me.$.imagecontextmenu.style.visibility = "";
                    me.$.vertexcontextmenu.style.opacity = "";
                    me.$.vertexcontextmenu.style.visibility = "";
                });
            },
            domReady: function () {

            },
            _init: function () {
                this.lastLoadedFileName = "";

                this.zoom = 25;
                this.backgroundImages = [];
                this.backgroundColor = '#FFF';
                this.center = {
                    x: 0,
                    y: 0
                };

                this.vertexDefaults = {
                    shape: 'circle',
                    size: 40,
//            color: '#9fc6e7',
                    color: '#FFFFFF',
                    strokeSize: 2,
//            strokeColor: '#9fc6e7',
                    strokeColor: '#888888',
                    area: 1,
                    strokeArea: 1,
                    opacity: 1,
                    labelSize: 12,
                    labelColor: '#111111',
                    labelPositionX: 0,
                    labelPositionY: 0,
                    labelAttribute: 'id',
                    xAttribute: 'x',
                    yAttribute: 'y',
                    selectionColor: '#da6d1f',
                    filters: []
                };
                this.edgeDefaults = {
                    shape: 'directed',
                    shaft: 'solid',
                    bidirectional: 'false',
                    size: 1,
                    color: '#888888',
//            color: '#cccccc',
                    opacity: 1,
                    labelSize: 0,
                    labelColor: '#111111',
                    labelAttribute: 'relation',
                    filters: []
                };
                this.vertexVisualSets = {
                    labelSize: null,
                    opacity: null,
                    shape: null,
                    color: null,
                    strokeColor: null,
                    size: null,
                    strokeSize: null
                };
                this.edgeVisualSets = {
                    labelSize: null,
                    opacity: null,
                    shape: null,
                    shaft: null,
                    bidirectional: null,
                    color: null,
                    size: null
                };

                this.graph = new Graph();
                this.vAttr = new AttributeManagerMemory();
                this.eAttr = new AttributeManagerMemory();

                this._createAttrColumns();
            },
            _createAttrColumns: function () {
                this.vAttr.addColumn({
                    defaultValue: "",
                    name: "id",
                    title: "Id",
                    type: "string"
                });
                this.vAttr.addColumn({
                    defaultValue: "",
                    name: "name",
                    title: "Name",
                    type: "string",
                    cellTemplate: "inputTemplate"
                });

                this.eAttr.addColumn({
                    defaultValue: "",
                    name: "id",
                    title: "Id",
                    type: "string"
                });
                this.eAttr.addColumn({
                    defaultValue: "",
                    name: "name",
                    title: "Name",
                    type: "string",
                    cellTemplate: "inputTemplate"
                });
                this.eAttr.addColumn({
                    defaultValue: "",
                    name: "relation",
                    title: "Relation",
                    type: "string",
                    cellTemplate: "inputTemplate"
                });
            },
            handleSave: function () {
                this.saveLocalStorage();
            },
            startOver: function () {
                this.deleteLocalStorage();
                this.setGraph(new Graph());
                this._init();
                this.saveLocalStorage();
            },
            loadLocalStorage: function () {
                var item = localStorage.getItem(this.serializeKey);
                if (item !== null && item !== "null") {
                    try {
                        this.loadJSON(JSON.parse(pako.ungzip(localStorage.getItem(this.serializeKey), {to: 'string'})));
                    } catch (e) {
                        this.deleteLocalStorage();
                        return false;
                    }
                    return true;
                }
                return false;
            },
            saveLocalStorage: function () {
                localStorage.setItem(this.serializeKey, pako.gzip(JSON.stringify(this), {to: 'string'}));
                console.log('saved');
            },
            deleteLocalStorage: function () {
                //OLD keys
                localStorage.removeItem("NETWORKVIEWER" + this.serializeVersion);

                window.localStorage.setItem(this.serializeKey, null);
                localStorage.removeItem(this.serializeKey);
            },
            loadJSON: function (o) {
                this.startOver();

                //Version fix  selectionColor
                if (o.vertexDefaults.selectionColor == null) {
                    o.vertexDefaults.selectionColor = this.vertexDefaults.selectionColor;
                }
                //Version Fix filters
                if (o.vertexDefaults.filters == null) {
                    o.vertexDefaults.filters = this.vertexDefaults.filters;
                }
                if (o.edgeDefaults.filters == null) {
                    o.edgeDefaults.filters = this.edgeDefaults.filters;
                }

                this.backgroundImages = o.backgroundImages;
                this.backgroundColor = o.backgroundColor;
                this.center.x = o.center.x;
                this.center.y = o.center.y;
                this.vertexDefaults = o.vertexDefaults;
                this.edgeDefaults = o.edgeDefaults;
                this.vertexVisualSets = o.vertexVisualSets;
                this.edgeVisualSets = o.edgeVisualSets;

                var graph = new Graph();
                graph.fromJSON(o.graph);
                this.setGraph(graph);
//
                this.vAttr = new AttributeManagerMemory();
                this.eAttr = new AttributeManagerMemory();
                this.vAttr.fromJSON(o.vAttr);
                this.eAttr.fromJSON(o.eAttr);


                this.saveLocalStorage();

                this.setVertexDefaultLabelAttribute(this.vertexDefaults.labelAttribute);
                this.setEdgeDefaultLabelAttribute(this.edgeDefaults.labelAttribute);
                this.$.networkLayout.addBackgroundImages(this.backgroundImages);
                this.zoom = o.zoom;
            },
            toJSON: function () {
                return {
                    zoom: this.zoom,
                    backgroundImages: this.$.networkLayout.getBackgroundImages(),
                    backgroundColor: this.backgroundColor,
                    center: this.center,
                    vertexDefaults: this.vertexDefaults,
                    edgeDefaults: this.edgeDefaults,
                    vertexVisualSets: this.vertexVisualSets,
                    edgeVisualSets: this.edgeVisualSets,
                    graph: this.graph,
                    vAttr: this.vAttr,
                    eAttr: this.eAttr
                };
            },
            /** Display Properties - Attribute Handlers **/
            /** API **/
            setVertexDefaultLabelAttribute: function (attribute) {
                var row, vertex;
                for (var i = 0, l = this.graph.vertices.length; i < l; i++) {
                    vertex = this.graph.vertices[i];
                    row = this.vAttr.getRow(vertex.id);
                    vertex.renderer.setLabelContent(row[attribute]);
                }
            },
            selectVertexDefaultLabelAttribute: function (attribute) {
                this.vertexDefaults.labelAttribute = attribute;
                this.setVertexDefaultLabelAttribute(attribute);
            },
            setEdgeDefaultLabelAttribute: function (attribute) {
                var row, edge;
                for (var i = 0, l = this.graph.edges.length; i < l; i++) {
                    edge = this.graph.edges[i];
                    row = this.eAttr.getRow(edge.id);
                    edge.renderer.setLabelContent(row[attribute]);
                }
            },
            selectEdgeDefaultLabelAttribute: function (attribute) {
                this.vertexDefaults.labelAttribute = attribute;
                this.setEdgeDefaultLabelAttribute(attribute);
            },
            setVertexDefaultDisplayProperty: function (displayProperty, value) {
                var splitStr = ",";
                var visualSetEnabled = false;
                var visualSet = this.vertexVisualSets[displayProperty];
                if (visualSet != null && visualSet.enabled) {
                    visualSetEnabled = true;
                }
                if (visualSetEnabled == false) {
                    var row, vertex;
                    for (var i = 0, l = this.graph.vertices.length; i < l; i++) {
                        vertex = this.graph.vertices[i];
                        vertex.renderer.set(displayProperty, value);
                        this._updateEdgeCoords(vertex);
                    }
                } else {
                    if (visualSet.parse != 'list') {
                        var row, vertex, rowRenderValue;
                        for (var i = 0, l = this.graph.vertices.length; i < l; i++) {
                            vertex = this.graph.vertices[i];
                            row = this.vAttr.getRow(vertex.id);
                            rowRenderValue = visualSet.matches[row[visualSet.attribute]];
                            if (rowRenderValue != null) {
                                vertex.renderer.set(displayProperty, rowRenderValue);
                            } else {
                                vertex.renderer.set(displayProperty, value);
                            }
                            this._updateEdgeCoords(vertex);
                        }
                    } else {
                        var row, vertex, rowRenderValue, rowRenderValues, finalValues, rowValue, rowValues;
                        for (var i = 0, l = this.graph.vertices.length; i < l; i++) {
                            vertex = this.graph.vertices[i];
                            row = this.vAttr.getRow(vertex.id);
                            rowValue = row[visualSet.attribute];
                            if (rowValue == null) {
                                rowValue = "";
                            }
                            rowValues = rowValue.split(splitStr);
                            rowRenderValues = [];
                            for (var j = 0; j < rowValues.length; j++) {
                                rowRenderValue = visualSet.matches[rowValues[j]];
                                if (rowRenderValue != null) {
                                    rowRenderValues.push(rowRenderValue);
                                } else {
                                    rowRenderValues.push(value);
                                }
                            }
                            finalValues = rowRenderValues;

//                            //TODO rework, this is a temporal fix
//                            if(displayProperty.indexOf("stroke") == -1){
//                                vertex.renderer.pieLabelText = rowValues;
//                            }else{
//                            }
//                            //TODO end

                            vertex.renderer.set(displayProperty, finalValues);
                            this._updateEdgeCoords(vertex);
                        }
                    }
                }

            },
            setEdgeDefaultDisplayProperty: function (displayProperty, value) {
                var visualSetEnabled = false;
                var visualSet = this.edgeVisualSets[displayProperty];
                if (visualSet != null && visualSet.enabled) {
                    visualSetEnabled = true;
                }
                var row, edge, finalValue, rowRenderValue;
                for (var i = 0, l = this.graph.edges.length; i < l; i++) {
                    edge = this.graph.edges[i];
                    row = this.eAttr.getRow(edge.id);
                    finalValue = value;
                    if (visualSetEnabled) {
                        rowRenderValue = visualSet.matches[row[visualSet.attribute]];
                        if (rowRenderValue != null) {
                            finalValue = rowRenderValue;
                        }
                    }
                    edge.renderer.set(displayProperty, finalValue);
                }
            },
            setVertexDefaultPositionX: function (attribute, adjust, invertAxis) {
                adjust = (adjust == null) ? true : adjust;
                invertAxis = (invertAxis == null) ? false : invertAxis;
                this._calculateVertexAttributeNormalization(attribute, "x", "width", adjust, invertAxis);
            },
            _calculateVertexAttributeNormalization: function (coordAttr, coord, measure, adjust, invertAxis) {
                var margin = 100, midMargin = margin / 2;
                var max, min, c;
                var row, vertex;

                for (var i = 0; i < this.graph.vertices.length; i++) {
                    vertex = this.graph.vertices[i];
                    row = this.vAttr.getRow(vertex.id);
                    c = parseFloat(row[coordAttr]);
                    if (!isNaN(c)) {
                        if (!max) {
                            max = c;
                            min = c;
                        }
                        max = Math.max(c, max);
                        min = Math.min(c, min);
                    }
                }
                var range = (max === min) ? 1 : max - min;

                if (adjust == false) {
                    measure = range;
                } else {
                    measure = this.$.networkLayout.getBoundingClientRect()[measure] - margin;
                }

                var row, vertex, c;
                for (var i = 0; i < this.graph.vertices.length; i++) {
                    vertex = this.graph.vertices[i];
                    row = this.vAttr.getRow(vertex.id);
                    c = parseFloat(row[coordAttr]);
                    c = (c - min) * measure / range;
                    if (invertAxis) {
                        c = measure - c;
                    }
                    if (!isNaN(c)) {
                        vertex.position[coord] = c + midMargin;
                        vertex.renderer.move();
                        this._updateEdgeCoords(vertex);
                    }
                }
            },
            setVertexDefaultPositionY: function (attribute, adjust, invertAxis) {
                adjust = (adjust == null) ? true : adjust;
                invertAxis = (invertAxis == null) ? true : invertAxis;
                this._calculateVertexAttributeNormalization(attribute, "y", "height", adjust, invertAxis);
            },
            /** Handlers **/
            /* Vertex */
            handleVertexDefaultLabelAttribute: function () {
                this.setVertexDefaultLabelAttribute(this.vertexDefaults.labelAttribute);
            },
            handleVertexDefaultLabelSize: function () {
                this.setVertexDefaultDisplayProperty('labelSize', this.vertexDefaults.labelSize);
            },
            handleVertexDefaultLabelPositionX: function () {
                this.setVertexDefaultDisplayProperty('labelPositionX', this.vertexDefaults.labelPositionX);
            },
            handleVertexDefaultLabelPositionY: function () {
                this.setVertexDefaultDisplayProperty('labelPositionY', this.vertexDefaults.labelPositionY);
            },
            handleVertexDefaultOpacity: function () {
                this.setVertexDefaultDisplayProperty('opacity', this.vertexDefaults.opacity);
            },
            handleVertexDefaultShape: function () {
                this.setVertexDefaultDisplayProperty('shape', this.vertexDefaults.shape);
            },
            handleVertexDefaultColor: function () {
                this.setVertexDefaultDisplayProperty('color', this.vertexDefaults.color);
            },
            handleVertexDefaultStrokeColor: function () {
                this.setVertexDefaultDisplayProperty('strokeColor', this.vertexDefaults.strokeColor);
            },
            handleVertexDefaultSize: function () {
                this.setVertexDefaultDisplayProperty('size', this.vertexDefaults.size);
            },
            handleVertexDefaultStrokeSize: function () {
                this.setVertexDefaultDisplayProperty('strokeSize', this.vertexDefaults.strokeSize);
            },
            handleVertexDefaultArea: function () {
                this.setVertexDefaultDisplayProperty('area', this.vertexDefaults.area);
            },
            handleVertexDefaultStrokeArea: function () {
                this.setVertexDefaultDisplayProperty('strokeArea', this.vertexDefaults.strokeArea);
            },
            handleVertexDefaultXAttribute: function () {
                this.setVertexDefaultPositionX(this.vertexDefaults.xAttribute, true, false);
            },
            handleVertexDefaultYAttribute: function () {
                this.setVertexDefaultPositionY(this.vertexDefaults.yAttribute, true, true);
            },
            /* Edge */
            handleEdgeDefaultLabelAttribute: function () {
                this.setEdgeDefaultLabelAttribute(this.edgeDefaults.labelAttribute);
            },
            handleEdgeDefaultLabelSize: function () {
                this.setEdgeDefaultDisplayProperty('labelSize', this.edgeDefaults.labelSize);
            },
            handleEdgeDefaultOpacity: function () {
                this.setEdgeDefaultDisplayProperty('opacity', this.edgeDefaults.opacity);
            },
            handleEdgeDefaultShaft: function () {
                this.setEdgeDefaultDisplayProperty('shaft', this.edgeDefaults.shaft);
            },
            handleEdgeDefaultShape: function () {
                this.setEdgeDefaultDisplayProperty('shape', this.edgeDefaults.shape);
            },
            handleEdgeDefaultBidirectional: function () {
                this.setEdgeDefaultDisplayProperty('bidirectional', this.edgeDefaults.bidirectional);
            },
            handleEdgeDefaultColor: function () {
                this.setEdgeDefaultDisplayProperty('color', this.edgeDefaults.color);
            },
            handleEdgeDefaultSize: function () {
                this.setEdgeDefaultDisplayProperty('size', this.edgeDefaults.size);
            },
            /** END Display Properties - Attribute Handlers **/
            /** ** **/
            /** ** **/
            /** ** **/


            /* Observers */
            observe: {
                'vAttr.selected': 'handleVertexSelected',
                'eAttr.selected': 'handleEdgeSelected'
            },
            handleVertexSelected: function (oldValue, newValue) {
                //Set all not selected
                for (var i = 0; i < this.graph.vertices.length; i++) {
                    var vertex = this.graph.vertices[i];
                    vertex.renderer.deselect();
                }
                //Set selected ones
                for (var i = 0; i < this.vAttr.selected.length; i++) {
                    var row = this.vAttr.selected[i];
                    var vertex = this.graph.getVertexById(row.id);
                    vertex.renderer.select(this.vertexDefaults.selectionColor);
                }
            },
            handleEdgeSelected: function (oldValue, newValue) {
                //Set all not selected
                for (var i = 0; i < this.graph.edges.length; i++) {
                    var edge = this.graph.edges[i];
                    edge.renderer.deselect();
                }
                //Set selected ones
                for (var i = 0; i < this.eAttr.selected.length; i++) {
                    var row = this.eAttr.selected[i];
                    var edge = this.graph.getEdgeById(row.id);
                    edge.renderer.select();
                }
            },


            /* Bar Handlers*/
            handleNetworkEditMenu: function (e) {
                this.$.networkEdit.removeAttribute('hidden');
            },
            handleNodesEditMenu: function (e) {
                this.$.nodeAttributeEdit.removeAttribute('hidden')
            },
            handleEdgesEditMenu: function (e) {
                this.$.edgeAttributeEdit.removeAttribute('hidden')
            },
            handleNodesFilterMenu: function (e) {
                this.$.nodeSelectFilter.removeAttribute('hidden')
            },
            handleEdgesFilterMenu: function (e) {
                this.$.edgeSelectFilter.removeAttribute('hidden')
            },
            handleCellbaseMenu: function (e) {
                this.$.cellbaseAttributeImport.removeAttribute('hidden')
            },
            handleSessionStartMenu: function (e) {
                if (confirm('All changes will be lost. Are you sure?')) {
                    this.startOver();
                }
            },
            handleSessionOpenMenu: function (e) {
                var me = this;
                var input = document.createElement('input');
                input.setAttribute("type", "file");
                input.addEventListener("change", function (e) {
                    var file = e.currentTarget.files[0];
                    if (file) {
                        var reader = new FileReader();
                        reader.onload = function (evt) {
                            me.loadJSON(JSON.parse(evt.target.result));
                        };
                        reader.readAsText(file);
                        e.currentTarget.value = null;
                    }
                });
                var event = new MouseEvent('click', {
                    'view': window,
                    'bubbles': true,
                    'cancelable': true
                });
                input.dispatchEvent(event);
            },
            handleSessionSaveMenu: function (e) {
                var content = JSON.stringify(this);
                var blob = new Blob([content], {type: "application/json"});
                var url = URL.createObjectURL(blob);
                var link = document.createElement('a');
                link.href = url;
                link.download = "network.json";
                var fileName = window.prompt("Please enter file name", "network.json")
                if (fileName != null && fileName != "") {
                    link.download = fileName;
                }
                var event = new MouseEvent('click', {
                    'view': window,
                    'bubbles': true,
                    'cancelable': true
                });
                link.dispatchEvent(event);
            },
            handleSessionManageMenu: function (e) {
                this.$.sessionManager.removeAttribute('hidden')
            },
            handleImportSifMenu: function (e) {
                this.selectedMenu = 'import-sif';
            },
            handleImportTextMenu: function (e) {
                this.selectedMenu = 'import-text';
            },
            handleImportXlsxMenu: function (e) {
                this.selectedMenu = 'import-xlsx';
            },
            handleImportNodeAttrMenu: function (e) {
                this.selectedMenu = 'import-node-attributes';
            },
            handleImportEdgeAttrMenu: function (e) {
                this.selectedMenu = 'import-edge-attributes';
            },
            handleExportSifMenu: function (e) {
                var content = this.exportGraph();
                var blob = new Blob([content], {type: "data:text/tsv"});
                var url = URL.createObjectURL(blob);
                var link = document.createElement('a');
                link.href = url;
                link.download = "network.sif";
                var event = new MouseEvent('click', {
                    'view': window,
                    'bubbles': true,
                    'cancelable': true
                });
                link.dispatchEvent(event);
            },
            handleExportNodeAttrMenu: function (e) {
                var content = this.exportVertexAttributes();
                var blob = new Blob([content], {type: "data:text/tsv"});
                var url = URL.createObjectURL(blob);
                var link = document.createElement('a');
                link.href = url;
                link.download = "node.attr";
                var event = new MouseEvent('click', {
                    'view': window,
                    'bubbles': true,
                    'cancelable': true
                });
                link.dispatchEvent(event);
            },
            handleExportEdgeAttrMenu: function (e) {
                var content = this.exportEdgeAttributes();
                var blob = new Blob([content], {type: "data:text/tsv"});
                var url = URL.createObjectURL(blob);
                var link = document.createElement('a');
                link.href = url;
                link.download = "edge.attr";
                var event = new MouseEvent('click', {
                    'view': window,
                    'bubbles': true,
                    'cancelable': true
                });
                link.dispatchEvent(event);
            },
            handleExportSvgMenu: function (e) {
                var svg = new XMLSerializer().serializeToString(this.$.networkLayout.$.svg);
                var blob = new Blob([svg], {type: "image/svg+xml"});
                var url = URL.createObjectURL(blob);

                var link = document.createElement('a');
                link.href = url;
                link.download = "network.svg";
                var event = new MouseEvent('click', {
                    'view': window,
                    'bubbles': true,
                    'cancelable': true
                });
                link.dispatchEvent(event);
            },
            handleExportPngMenu: function (e) {
//            Deprecated
            },


            handleNodeSimpleRenderingMenu: function (e) {
                this.$.nodeRender.removeAttribute('hidden')
            },
            handleEdgeSimpleRenderingMenu: function (e) {
                this.$.edgeRender.removeAttribute('hidden')
            },

            handleReactomeMenu: function (e) {
                this.$.reactomeImport.removeAttribute('hidden')
            },
            handleKeggMenu: function (e) {
                this.$.keggImport.removeAttribute('hidden')
            },
            handleIntactMenu: function (e) {
                this.$.intactImport.removeAttribute('hidden')
            },

            handleCommunitiesMenu: function (e) {
                this.$.communitiesStructureDetection.removeAttribute('hidden')
            },
            handleTopologicalMenu: function (e) {
                this.$.topologicalStudy.removeAttribute('hidden')
            },

            handleSnowMenu: function (e) {
                if (this.jsoHeader) {
                    if (this.jsoHeader.isLogged == false) {
                        this.jsoHeader.anonymousSign();
                    }
                    this.selectedMenu = "snow";
                }
            },
            handleNetworkMinerMenu: function (e) {
                if (this.jsoHeader) {
                    if (this.jsoHeader.isLogged == false) {
                        this.jsoHeader.anonymousSign();
                    }
                    this.selectedMenu = "networkminer";
                }
            },
            handleFatigoMenu: function (e) {
                if (this.jsoHeader) {
                    if (this.jsoHeader.isLogged == false) {
                        this.jsoHeader.anonymousSign();
                    }
                    this.selectedMenu = "fatigo";
                }
            },
            handleReactomeFiMenu: function (e) {
                if (this.jsoHeader) {
                    if (this.jsoHeader.isLogged == false) {
                        this.jsoHeader.anonymousSign();
                    }
                    this.selectedMenu = "reactome-fi-microarray";
                }
            },


            /**/
            handleImportSif: function (e) {
//                _this.configuration.cleanVisualSets();
                this.setGraph(e.detail.graph);
                this.lastLoadedFileName = e.detail.fileName;
//                this.$.networkViewer.setLayout(e.detail.layout);
                this.setLayout('Force directed');
                this.saveLocalStorage();
            },
            handleImportText: function (e) {
//                _this.configuration.cleanVisualSets();
                this.setGraph(e.detail.graph);
                this.lastLoadedFileName = e.detail.fileName;
//                this.$.networkViewer.setLayout(e.detail.layout);
                this.setLayout('Force directed');
                this.saveLocalStorage();

            },
            handleImportXlsx: function (e) {
//                _this.configuration.cleanVisualSets();
                this.setGraph(e.detail.graph);
                this.lastLoadedFileName = e.detail.fileName;
//                this.$.networkViewer.setLayout(e.detail.layout);
                this.setLayout('Force directed');
                this.saveLocalStorage();

            },
            handleImportNodeAttr: function (e) {
                this.importVertexAttributeManager(e.detail.attributeManager);
            },
            handleImportEdgeAttr: function (e) {
                this.importEdgeAttributeManager(e.detail.attributeManager);
            },

            /** NETWORK **/
            /*SELECT*/
            handleSelectMenu: function (e) {
                switch (e.detail.value) {
                    case 'nodes-select-all' :
                        this.selectAllVertices();
                        break;
                    case 'edges-select-all' :
                        this.selectAllEdges();
                        break;
                    case 'network-select-all' :
                        this.selectAll();
                        break;
                    case 'nodes-select-first-neighbourhood' :
                        this.selectVerticesNeighbour();
                        break;
                    case 'nodes-select-invert' :
                        this.selectVerticesInvert();
                        break;
                    case 'edges-select-adjacent' :
                        this.selectEdgesNeighbour();
                        break;
                    default :
                        console.log(e.detail.value + " not defined");
                }
            },
            /*LAYOUT*/
            handleLayoutMenu: function (e) {
                switch (e.detail.value) {
                    case 'layout-force-directed' :
                        this.setLayout('Force directed');
                        break;
                    case 'layout-configure-force-directed' :
                        this.$.configureForceDirected.removeAttribute('hidden')
                        break;
                    case 'layout-tree' :
                        this.setLayout('Tree');
                        break;
                    case 'layout-circle' :
                        this.setLayout('Circle', {attributeName: e.detail.subvalue});
                        break;
                    case 'layout-random' :
                        this.setLayout('Random');
                        break;
                    default :
                        console.log(e.detail.value + " not defined");
                }
            },
            /* toolbar Handlers*/
            handleImportBackgroundImage: function (e) {
                this.$.networkLayout.addBackgroundImage(e.detail.image);
            },
            handleLayoutChange: function (e) {
                this.setLayout(e.detail.layout);
            },
            handleSelectChange: function (e) {
                this.select(e.detail.select);
            },
            handleRotateChange: function (e) {
                this.rotateNetwork(e.detail.angle);
            },

            /* editionbar Handlers*/
            handleVertexShape: function (e) {
                this.setSelectedVerticesDisplayAttr('shape', e.detail.value, true);
            },
            handleVertexOpacity: function (e) {
                this.setSelectedVerticesDisplayAttr('opacity', e.detail.value);
            },
            handleVertexSize: function (e) {
                this.setSelectedVerticesDisplayAttr('size', parseInt(e.detail.value), true);
            },
            handleVertexColor: function (e) {
                this.setSelectedVerticesDisplayAttr('color', e.detail.value);
            },
            handleVertexStrokeSize: function (e) {
                this.setSelectedVerticesDisplayAttr('strokeSize', parseInt(e.detail.value), true);
            },
            handleVertexStrokeColor: function (e) {
                this.setSelectedVerticesDisplayAttr('strokeColor', e.detail.value);
            },
            handleVertexLabelSize: function (e) {
                this.setSelectedVerticesDisplayAttr('labelSize', e.detail.value);
            },
            handleVertexSearch: function (e) {
                this.selectVerticesByAttribute(e.detail.columnName, e.detail.value);
                if (this.vAttr.selected.length == 0) {
                    e.detail.inputEl.style.color = '#ff0000';
                }
            },
            handleVertexNameField: function (e) {
                this.setVertexLabel(e.detail.value);
            },


            handleEdgeShape: function (e) {
                this.setSelectedEdgesDisplayAttr('shape', e.detail.value);
            },
            handleEdgeSize: function (e) {
                this.setSelectedEdgesDisplayAttr('size', parseInt(e.detail.value));
            },
            handleEdgeColor: function (e) {
                this.setSelectedEdgesDisplayAttr('color', e.detail.value);
            },
            handleEdgeLabelSize: function (e) {
                this.setSelectedEdgesDisplayAttr('labelSize', e.detail.value);
            },
            handleEdgeSearch: function (e) {
                this.selectEdgesByAttribute(e.detail.columnName, e.detail.value);
            },
            handleEdgeNameField: function (e) {
                this.setEdgeLabel(e.detail.value);
            },

            /*Layout Handlers*/
            handleCreateVertex: function (e) {
                this.createVertex(e.detail.x, e.detail.y);
            },
            handleSelectVertex: function (e) {
                var vertex = this.graph.getVertexById(e.detail.vertexId);
                this.selectVertex(vertex, e.detail.addToSelection);
            },
            handleSelectEdge: function (e) {
                var edge = this.graph.getEdgeById(e.detail.edgeId);
                this.selectEdge(edge, e.detail.addToSelection);
            },

            handleMoveSelectedVertices: function (e) {
                this.moveSelectedVertices(e.detail.dispX, e.detail.dispY);
            },
            handleSelectArea: function (e) {
                this.selectByArea(e.detail.x, e.detail.y, e.detail.width, e.detail.height);
            },
            handleCreateEdge: function (e) {
                var source = this.graph.getVertexById(e.detail.sourceId);
                var target = this.graph.getVertexById(e.detail.targetId);
                this.createEdge(source, target);

            },
            handleRemoveVertex: function (e) {
                var vertex = this.graph.getVertexById(e.detail.vertexId);
                this.removeVertex(vertex);
            },
            handleLeftClickVertex: function (e) {
                var vertex = this.graph.getVertexById(e.detail.vertexId);
//                this.$.editionBar.vertexColor = vertex.renderer.color;
//                this.$.editionBar.vertexStrokeColor = vertex.renderer.strokeColor;
//                this.$.editionBar.vertexNameField = vertex.renderer.labelText;
//                this.$.editionBar.vertexSizeField = vertex.renderer.size;
//                this.$.editionBar.vertexStrokeSizeField = vertex.renderer.strokeSize;
//                this.$.editionBar.selectedBar = 'vertex';
            },
            handleLeftClickEdge: function (e) {
                var edge = this.graph.getEdgeById(e.detail.edgeId);
//                this.$.editionBar.edgeColor = edge.renderer.color;
//                this.$.editionBar.edgeSizeField = edge.renderer.size;
//                this.$.editionBar.edgeNameField = edge.renderer.labelText;
//                this.$.editionBar.selectedBar = 'edge';
            },
            handleRightClickVertex: function (e) {
                this._lastContextVertexAttributes = [];

                var bcrnl = this.$.networkLayout.getBoundingClientRect();
                this.$.vertexcontextmenu.style.opacity = "1";
                this.$.vertexcontextmenu.style.visibility = "visible";
                this.$.vertexcontextmenu.style.top = (bcrnl.top + e.detail.y + 10) + "px";
                this.$.vertexcontextmenu.style.left = (bcrnl.left + e.detail.x + 10) + "px";
                this._lastContextVertex = this.graph.getVertexById(e.detail.vertexId);


                var vertexAttributes = this.vAttr.getRow(e.detail.vertexId);
                this._lastContextVertexAttributes = Object.keys(vertexAttributes).map(function (key) {
                    return {key: key, value: vertexAttributes[key]};
                });
            },
            handleContextRemoveVertex: function (e) {
                this.$.vertexcontextmenu.style.opacity = "";
                this.$.vertexcontextmenu.style.visibility = "";
                this.removeVertex(this._lastContextVertex);
            },
            handleContextRemoveSelectedVertices: function (e) {
                this.removeSelectedVertices();
            },
            handleContextSelectVerticesNeighbour: function (e) {
                this.selectVertex(this._lastContextVertex);
                this.selectVerticesNeighbour();
            },
            handleContextSelectEdgesNeighbour: function (e) {
                this.selectVertex(this._lastContextVertex);
                this.selectEdgesNeighbour();
            },

            _hideImageContextMenu: function () {
                this.$.imagecontextmenu.style.opacity = "";
                this.$.imagecontextmenu.style.visibility = "";
            },
            handleRightClickBackgroundImage: function (e) {
                //                var bcr = e.detail.targetEl.getBoundingClientRect()
                var bcrnl = this.$.networkLayout.getBoundingClientRect();
//                console.log(bcr)
//                console.log(bcrnl.top)
//                console.log(e.detail)
//                console.log(e.detail.targetEl)
//                console.log(this.$.networkLayout.targetEl)
                this.$.imagecontextmenu.style.opacity = "1";
                this.$.imagecontextmenu.style.visibility = "visible";
                this.$.imagecontextmenu.style.top = (bcrnl.top + e.detail.y) + "px";
                this.$.imagecontextmenu.style.left = (bcrnl.left + e.detail.x) + "px";
                this._lastImageElClicked = e.detail.targetEl;
            },
            handleContextRemoveBackGroundImage: function (e) {
                this._hideImageContextMenu();
                this.removeBackGroundImage(this._lastImageElClicked);
            },
            /* Methods */
            selectAll: function () {
                this.vAttr.selectAll();
                this.eAttr.selectAll();
            },
            selectVertex: function (vertex, addToSelection) {
                if (!vertex.renderer.selected) {
                    if (addToSelection) {
                        this.vAttr.addToSelection(vertex.id);
                    } else {
                        this.vAttr.select(vertex.id);
                    }
                } else {
                    if (addToSelection) {
                        this.vAttr.removeFromSelection(vertex.id);
                    }
                }
            },
            selectAllVertices: function () {
//                this.deselectAllEdges();
                this.vAttr.selectAll();
            },
            deselectAllVertices: function () {
                this.vAttr.deselectAll();
            },
            selectEdge: function (edge, addToSelection) {
                if (!edge.renderer.selected) {
                    if (addToSelection) {
                        this.eAttr.addToSelection(edge.id);
                    } else {
                        this.eAttr.select(edge.id);
                    }
                } else {
                    if (addToSelection) {
                        this.eAttr.removeFromSelection(edge.id);
                    }
                }
            },
            selectAllEdges: function () {
//                this.deselectAllVertices();
                this.eAttr.selectAll();
            },
            deselectAllEdges: function () {
                this.eAttr.deselectAll();
            },

            selectVerticesNeighbour: function () {
                var selectedVertices = [];
                var selectedVerticesMap = {};
                for (var i = 0; i < this.vAttr.selected.length; i++) {
                    var row = this.vAttr.selected[i];
                    var vertex = this.graph.getVertexById(row.id);
                    selectedVertices.push(vertex);
                    selectedVerticesMap[vertex.id] = vertex;
                    for (var j = 0; j < vertex.edges.length; j++) {
                        var edge = vertex.edges[j];
                        if (!selectedVerticesMap[edge.source.id]) {
                            selectedVertices.push(edge.source);
                            selectedVerticesMap[edge.source.id] = edge.source;
                        }
                        if (!selectedVerticesMap[edge.target.id]) {
                            selectedVertices.push(edge.target);
                            selectedVerticesMap[edge.target.id] = edge.target;
                        }
                    }
                }
                this.vAttr.selected = selectedVertices;
            },
            selectEdgesNeighbour: function () {
                for (var i = 0; i < this.vAttr.selected.length; i++) {
                    var row = this.vAttr.selected[i];
                    var vertex = this.graph.getVertexById(row.id);
                    for (var j = 0; j < vertex.edges.length; j++) {
                        var edge = vertex.edges[j];
                        if (!edge.renderer.selected) {
                            this.eAttr.addToSelection(edge.id);
                        }
                    }
                }
            },
            selectVerticesInvert: function () {
                var selected = [];
                for (var i = 0; i < this.graph.vertices.length; i++) {
                    var vertex = this.graph.vertices[i];
                    if (!vertex.renderer.selected) {
                        selected.push(this.vAttr.getRow(vertex.id));
                    }
                }
                this.vAttr.selected = selected;
            },
            selectEdgesInvert: function () {
                var selected = [];
                for (var i = 0; i < this.graph.edges.length; i++) {
                    var edge = this.graph.edges[i];
                    if (!edge.renderer.selected) {
                        selected.push(this.eAttr.getRow(edge.id));
                    }
                }
                this.eAttr.selected = selected;
            },
            selectByArea: function (x, y, width, height) {
                this.deselectAllVertices();
                this.deselectAllEdges();
                if (width > 0 && height > 0) {
                    x -= this.center.x;
                    y -= this.center.y;
                    x /= this.scale;
                    y /= this.scale;

                    width /= this.scale;
                    height /= this.scale;

                    var vSelected = [];
                    var eSelected = [];
                    for (var i = 0; i < this.graph.vertices.length; i++) {
                        var vertex = this.graph.vertices[i];
                        if (vertex.position.x >= x && vertex.position.x <= x + width && vertex.position.y >= y && vertex.position.y <= y + height) {
                            vSelected.push(this.vAttr.getRow(vertex.id));

                            for (var j = 0; j < vertex.edges.length; j++) {
                                var edge = vertex.edges[j];
                                eSelected.push(this.eAttr.getRow(edge.id));
                            }

                        }
                    }
                    this.vAttr.selected = vSelected;
                    this.eAttr.selected = eSelected;
                }
            },
            _updateEdgeCoords: function (vertex) {
                for (var i = 0; i < vertex.edges.length; i++) {
                    var edge = vertex.edges[i];
                    if (vertex === edge.source) {
                        edge.renderer.move();
                    }
                    if (vertex === edge.target) {
                        edge.renderer.move();
                    }
                }
            },
            moveSelectedVertices: function (dispX, dispY) {
                dispX /= this.scale;
                dispY /= this.scale;
                for (var i = 0; i < this.vAttr.selected.length; i++) {
                    var row = this.vAttr.selected[i];
                    var vertex = this.graph.getVertexById(row.id);
                    vertex.position.x += dispX;
                    vertex.position.y += dispY;
                    vertex.renderer.move();
                    this._updateEdgeCoords(vertex);
                }
            },

            selectVerticesByIds: function (vertexIds) {
                this.deselectAllVertices();
                this.vAttr.selectByIds(vertexIds);
            },
            selectVerticesByAttribute: function (attributeName, attributeValue) {
                this.deselectAllVertices();
                this.vAttr.selectByColumnValue(attributeName, attributeValue);
            },
            centerVertex: function (vertex) {

//                var clientRect = this.$.networkLayout.getBoundingClientRect();
//                var centerX = clientRect.width / 2;
//                var centerY = clientRect.height / 2;
//                this.tx = this.x + (-centerX * (this.scale - 1));
//                this.ty = this.y + (-centerY * (this.scale - 1));
//
//                var dx = centerX - vertex.position.x
//                var dy = centerY - vertex.position.y;
//                this.center.x = dx;
//                this.center.y = dy;

                vertex.position.x = this.center.x;
                vertex.position.y = this.center.y;
                vertex.renderer.move();

            },
            selectEdgesByAttribute: function (attributeName, attributeValue) {
                this.deselectAllEdges();
                this.eAttr.selectByColumnValue(attributeName, attributeValue);
            },
            setVertexCoords: function (vertexId, x, y) {
                var vertex = this.graph.getVertexById(vertexId);
                vertex.position.x = x;
                vertex.position.y = y;
                vertex.renderer.move();
                this._updateEdgeCoords(vertex);
            },
            removeVertex: function (vertex) {
                for (var i = 0; i < vertex.edges.length; i++) {
                    var edge = vertex.edges[i];
                    edge.renderer.remove();
                    this.eAttr.removeRowById(edge.id);
                }
                vertex.renderer.remove();
                this.vAttr.removeRowById(vertex.id);
                this.graph.removeVertex(vertex);
                this.deselectAllVertices();
            },
            removeSelectedVertices: function () {
                this._removeVertexRows(this.vAttr.selected);
            },
            _removeVertexRows: function (vertexRows) {
                var edgeRowsToDelete = [];
                var edgeRowsToDeleteMap = {};
                var selectedVertices = [];
                for (var i = 0; i < vertexRows.length; i++) {
                    var row = vertexRows[i];
                    var vertex = this.graph.getVertexById(row.id);
                    selectedVertices.push(vertex);
                    for (var j = 0; j < vertex.edges.length; j++) {
                        var edge = vertex.edges[j];
                        edge.renderer.remove();
                        if (edgeRowsToDeleteMap[edge.id] != true) {
                            edgeRowsToDeleteMap[edge.id] = true;
                            edgeRowsToDelete.push(this.eAttr.getRow(edge.id));
                        }
                    }
                    vertex.renderer.remove();
                }
                this.graph.removeVertices(selectedVertices);
                this.vAttr.removeSelected();
                this.eAttr.removeRows(edgeRowsToDelete);
            },
            removeSelectedEdges: function () {
                var edgeRowsToDelete = [];
                var edgesToDelete = [];
                var edgeMap = {};
                for (var i = 0; i < this.eAttr.selected.length; i++) {
                    var row = this.eAttr.selected[i];
                    var edge = this.graph.getEdgeById(row.id);
                    if (edgeMap[edge.id] != true) {
                        edgeMap[edge.id] = true;
                        edgeRowsToDelete.push(this.eAttr.getRow(edge.id));
                        edgesToDelete.push(edge);
                        edge.renderer.remove();
                    }
                }
                this.graph.removeEdges(edgesToDelete);
                this.eAttr.removeRows(edgeRowsToDelete);
                this.eAttr.deselectAll();
            },
            setSelectedVerticesDisplayAttr: function (displayProperty, value, updateEdges) {
                var vertex, row;
                for (var i = 0, li = this.vAttr.selected.length; i < li; i++) {
                    row = this.vAttr.selected[i];
                    vertex = this.graph.getVertexById(row.id);
                    vertex.renderer.set(displayProperty, value);
                    if (updateEdges) {
                        this._updateEdgeCoords(vertex);
                    }
                }
            },
            setSelectedEdgesDisplayAttr: function (displayProperty, value) {
                var edge, row;
                for (var i = 0, li = this.eAttr.selected.length; i < li; i++) {
                    row = this.eAttr.selected[i];
                    edge = this.graph.getEdgeById(row.id);
                    edge.renderer.set(displayProperty, value);
                }
            },
            setVertexLabel: function (label) {
                //TODO
//                if (this.selectedVertices.length == 1) {
//                    var vertex = this.selectedVertices[0];
//                    this.network.setVertexLabel(vertex, label);
//                }
            },
            setEdgeLabel: function (label) {
                //TODO
//                if (this.selectedEdges.length == 1) {
//                    var edge = this.selectedEdges[0];
//                    this.network.setEdgeLabel(edge, label);
//                }
            },
            createVertex: function (x, y, id) {
                if (x == null) {
                    x = this.center.x;
                } else {
                    x -= this.center.x;
                    x /= this.scale;

                }
                if (y == null) {
                    x = this.center.y;
                } else {
                    y -= this.center.y;
                    y /= this.scale;
                }

                if (id == null) {
                    id = 'n' + Math.floor(Math.random() * (999999 - 100000 + 1));
                }

                /* vertex graph */
                var vertex = new Vertex({
                    id: id,
                    position: new Point(x, y),
                    renderer: new CircosVertexRenderer(this.vertexDefaults)
                });
                var added = this.graph.addVertex(vertex);
                if (added) {
                    this.vAttr.addRow({
                        'id': vertex.id,
                        'name': vertex.id
                    });
                    vertex.render({
                        target: this.$.networkLayout.$.scaleFrontGroup
                    });
                } else {
                    vertex = this.graph.getVertexById(id);
                }
                return vertex;
            },
            createVertices: function (idList) {
                for (var i = 0; i < idList.length; i++) {
                    var id = idList[i];
                    this.createVertex(0, 0, id);
                }
            },
            createEdge: function (vertexSource, vertexTarget, relation) {
                if (relation == null) {
                    relation = 'i';
                }
                var id = vertexSource.id + '_' + relation + '_' + vertexTarget.id
                /* edge graph */
                var edge = new Edge({
                    id: id,
                    relation: relation,
                    source: vertexSource,
                    target: vertexTarget,
                    renderer: new DefaultEdgeRenderer(this.edgeDefaults)
                });

                var added = this.graph.addEdge(edge);
                if (added) {
                    this.eAttr.addRow({
                        'id': edge.id,
                        'name': edge.id,
                        'relation': edge.relation
                    });
                    edge.render({
                        target: this.$.networkLayout.$.scaleFrontGroup
                    });
                }
                else {
                    edge = this.graph.getEdgeById(id);
                }
                return edge;
            },
            removeBackGroundImage: function (imageEl) {
                if (imageEl && imageEl.parentNode) {
                    imageEl.parentNode.removeChild(imageEl);
                }
            },
            rotateNetwork: function (angle) {
                var intPattern = /^-?\d+$/;
                if (angle && intPattern.test(angle)) {
                    var clientRect = this.$.networkLayout.getBoundingClientRect();
                    var centerX = clientRect.width / 2;
                    var centerY = clientRect.height / 2;
                    var vertices = this.graph.vertices;

                    var rotationInRadians = angle * Math.PI / 180.0;

                    for (var i = 0, l = vertices.length; i < l; i++) {
                        var vertex = vertices[i];
                        var vCoords = vertex.position;

                        //Detect angle and radius using width/2 and height/2 as center
                        var deltaX = vCoords.x - centerX;
                        var deltaY = vCoords.y - centerY;
                        var radius = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
                        var delta = deltaY / deltaX;
                        var angleRad = (isNaN(delta)) ? 0 : Math.atan(delta) + rotationInRadians;
                        //Fix Quadrant
                        angleRad = (vCoords.x < centerX) ? angleRad += Math.PI : angleRad;

                        var x = centerX + (radius * Math.cos(angleRad));
                        var y = centerY + (radius * Math.sin(angleRad));
                        //
                        this.setVertexCoords(vertex.id, x, y);
                    }
                }
            },
            getOrderedIdsByAttribute: function (attributeName) {
                var type = 'float';
                var checkType = true;
                var values = [];
                var row, value, l = this.vAttr.data.length;
                for (var i = 0; i < l; i++) {
                    row = this.vAttr.data[i];
                    value = row[attributeName];
                    if (!value) {
                        value = '';
                    }
                    /* detect number or string */
                    if (checkType) {
                        var parseResult = parseFloat(value);
                        if (isNaN(parseResult)) {
                            var type = 'string';
                            checkType = false;
                        }
                    }
                    /* - - - - - - - - - - - - */
                    values.push({id: row["id"], value: value});
                }
                switch (type) {
                    case 'float':
                        values.sort(function (a, b) {
                            return parseFloat(a.value) - parseFloat(b.value);
                        });
                        break;
                    /* string */
                    default:
                        values.sort(function (a, b) {
                            return a.value.localeCompare(b.value);
                        });
                }
                return values;
            },
            setLayout: function (type, e) {
                var me = this;
                this.x = 0;
                this.y = 0;
                var graph = this.graph;
                var dot = graph.getAsDOT();
                var clientRect = this.$.networkLayout.getBoundingClientRect();
                var width = (clientRect.width == 0) ? window.innerWidth : clientRect.width;
                var height = (clientRect.height == 0) ? window.innerHeight : clientRect.height;
                switch (type) {
                    case "Circle":
                        if (e && typeof e.attributeName !== 'undefined') {
                            GraphLayout.circle(me, width, height, this.getOrderedIdsByAttribute(e.attributeName));
                        } else {
                            GraphLayout.circle(me, width, height);
                        }
                        break;
                    case "Random":
                        GraphLayout.random2d(me, width, height);
                        break;
                    case "none":
                        break;
                    case "Force directed":
                        GraphLayout.force({
                            network: me,
                            width: width,
                            height: height,
                            end: function (verticesArray) {
                                for (var i = 0, l = verticesArray.length; i < l; i++) {
                                    var v = verticesArray[i];
                                    var vertex = me.graph.getVertexById(v.id);
                                    vertex.position.x = v.x;
                                    vertex.position.y = v.y;
                                    vertex.renderer.move();
                                    me._updateEdgeCoords(vertex);
                                }
                            }
                        });
                        break;
                    case "Force directed (simulation)":
                        GraphLayout.force({
                            network: me,
                            width: width,
                            height: height,
                            simulation: true,
                            end: function (verticesArray) {
                                for (var i = 0, l = verticesArray.length; i < l; i++) {
                                    var v = verticesArray[i];
                                    var vertex = me.graph.getVertexById(v.id);
                                    vertex.position.x = v.x;
                                    vertex.position.y = v.y;
                                    vertex.renderer.move();
                                    me._updateEdgeCoords(vertex);
                                }
                            }
                        });
                        break;
                    case "Tree":
                        if (this.vAttr.selected.length == 1) {
                            GraphLayout.tree({
                                network: me,
                                width: width,
                                height: height - 100,
                                root: this.graph.getVertexById(this.vAttr.selected[0].id),
                                end: function (verticesArray) {
                                    for (var i = 0, l = verticesArray.length; i < l; i++) {
                                        var v = verticesArray[i];
//                                        var vertex = me.graph.getVertexById(v.id);
                                        var vertex = me.graph.getVertexById(v.name);
                                        vertex.position.x = -v.x + (width);
                                        vertex.position.y = v.y + 50;
//                                        vertex.position.x = v.x;
//                                        vertex.position.y = v.y;
                                        vertex.renderer.move();
                                        me._updateEdgeCoords(vertex);
                                    }
                                }
                            });
                        } else {
                            alert("Please select only one vertex to use it as root");
                        }
                        break;
                    default:
                        console.log(dot);
//                var url = "http://bioinfo.cipf.es/utils/ws/rest/network/layout/" + type.toLowerCase() + ".coords";
////        		var url = "http://localhost:8080/opencga/rest/utils/network/layout/"+type+".coords";
////                var url = "http://ws-beta.bioinfo.cipf.es/opencga-staging/rest/utils/network/layout/" + type.toLowerCase() + ".coords";
//                $.ajax({
//                    async: false,
//                    type: "POST",
//                    url: url,
//                    dataType: "json",
//                    data: {
//                        dot: dot
//                    },
//                    cache: false,
//                    success: function (data) {
//                        console.log('Layout back')
//                        for (var vertexId in data) {
//                            var x = _this.getLayoutWidth() * (0.05 + 0.85 * data[vertexId].x);
//                            var y = _this.getLayoutHeight() * (0.05 + 0.85 * data[vertexId].y);
//                            _this.setVertexCoords(vertexId, x, y);
//                        }
//                    },
//                    error: function (data) {
//                        debugger
//                    },
//
//                });
                        break;
                }
            },
            select: function (option) {
                switch (option) {
                    case 'All nodes' :
                        this.selectAllVertices();
                        break;
                    case 'All edges' :
                        this.selectAllEdges();
                        break;
                    case 'Everything' :
                        this.selectAll();
                        break;
                    case 'First neighbour nodes' :
                        this.selectVerticesNeighbour();
                        break;
                    case 'Invert node selection' :
                        this.selectVerticesInvert();
                        break;
                    case 'Adjacent edges' :
                        this.selectEdgesNeighbour();
                        break;
                    default :
                        console.log(option + " not defined");
                }
            },
            exportGraph: function (separator) {
                return this.graph.getAsSIF(separator);
            },
            getAsSIFCustomRelation: function (separator, relationColumn) {
                if (typeof separator === 'undefined') {
                    separator = '\t';
                }

                var vertices = this.graph.vertices;
                var edges = this.graph.edges;

                var sifText = '', edge, line, row;
                for (var i = 0; i < edges.length; i++) {
                    edge = edges[i];
                    line = "";
                    row = this.eAttr.getRow(edge.id);
                    line = edge.source.id + separator + row[relationColumn] + separator + edge.target.id + "\n";
                    sifText += line;
                }
                var vertex;
                for (var i = 0; i < vertices.length; i++) {
                    vertex = vertices[i];
                    line = "";
                    if (vertex.edges.length == 0) {
                        line = vertex.id + separator + separator + "\n";
                    }
                    sifText += line;
                }
                return sifText;
            },
            exportVertexAttributes: function (separator) {
                return this.vAttr.getAsFile(separator);
            },
            exportEdgeAttributes: function (separator) {
                return this.eAttr.getAsFile(separator);
            },
            setGraph: function (graph) {
                this.graph = graph;
                this.vAttr = new AttributeManagerMemory();
                this.eAttr = new AttributeManagerMemory();
                this._createAttrColumns();
                this.$.networkLayout.clean();

                this.$.networkLayout.removeDom();
                var edges = this.graph.edges;
                var vertices = this.graph.vertices;
                for (var i = 0, l = vertices.length; i < l; i++) {
                    var vertex = vertices[i];
                    this.vAttr.addRow({
                        'id': vertex.id,
                        'name': vertex.id
                    });
//                    vertex.setRenderer(new CircosVertexRenderer(this.vertexDefaults));
                    vertex.render({
                        target: this.$.networkLayout.$.scaleFrontGroup
                    });
                }
                for (var i = 0, l = edges.length; i < l; i++) {
                    var edge = edges[i];
                    this.eAttr.addRow({
                        'id': edge.id,
                        'name': edge.id,
                        'relation': edge.relation
                    });
//                    edge.setRenderer(new DefaultEdgeRenderer(this.edgeDefaults));
                    edge.render({
                        target: this.$.networkLayout.$.scaleFrontGroup
                    });
                }
                this.$.networkLayout.appendDom();
            },

            importVertexAttributeManager: function (attributeManager) {
                var columns = attributeManager.columns;
                var data = attributeManager.data;
                for (var i = 0; i < columns.length; i++) {
                    var column = columns[i];
                    this.vAttr.addColumn(column);
                }
                for (var i = 0; i < data.length; i++) {
                    var row = data[i];
                    if (this.graph.containsVertex({id: row.id})) {
                        var added = this.vAttr.addRow(row);
                        if (added == false) {
                            var currentRow = this.vAttr.getRow(row.id);
                            for (key in row) {
                                currentRow[key] = row[key];
                            }
                        }
                    }
                }
                this.handleVertexDefaultXAttribute();
                this.handleVertexDefaultYAttribute();
            },
            importEdgeAttributeManager: function (attributeManager) {
                var columns = attributeManager.columns;
                var data = attributeManager.data;
                for (var i = 0; i < columns.length; i++) {
                    var column = columns[i];
                    this.eAttr.addColumn(column);
                }
                for (var i = 0; i < data.length; i++) {
                    var row = data[i];
                    if (this.graph.containsEdge({id: row.id})) {
                        var added = this.eAttr.addRow(row);
                        if (added == false) {
                            var currentRow = this.eAttr.getRow(row.id);
                            for (key in row) {
                                currentRow[key] = row[key];
                            }
                        }
                    }
                }
            },
            __iliketomoveit: function () {
                this.setLayout('Force directed (simulation)');
            },
            handleLoadExampleMenu: function (e) {
                var me = this;
                if (e.detail.subvalue == 1) {
                    $.ajax({
                        url: './example-files/ppi_histone_network.json',
                        dataType: 'json',
                        success: function (data) {
                            me.loadJSON(data);
                        }
                    })
                }
                if (e.detail.subvalue == 2) {
                    $.ajax({
                        url: './example-files/reactome_network.json',
                        dataType: 'json',
                        success: function (data) {
                            me.loadJSON(data);
                        }
                    })
                }
                if (e.detail.subvalue == 3) {
                    $.ajax({
                        url: './example-files/ppi_network.json',
                        dataType: 'json',
                        success: function (data) {
                            me.loadJSON(data);
                            me.setLayout("Force directed");
                        }
                    })
                }
            }
        });
    </script>
</polymer-element>