<commit_before>define([
    'arches',
    'knockout',
    'views/components/workbench',
    'bindings/cytoscape'
], function(arches, ko, WorkbenchViewmodel) {
    return ko.components.register('related-resources-graph', {
        viewModel: function(params) {
            var self = this;
            var layout = {
                name: "cose",
                animate: true,
                animationThreshold: 10
            };
            var fitPadding = 100;

            this.viz = ko.observable();
            this.cytoscapeConfig = ko.observable();
            this.focusResourceId = ko.isObservable(params.resourceId) ? params.resourceId : ko.observable(params.resourceId);
            this.selection = ko.observable();
            this.selectionMode = ko.observable('information');
            this.elements = ko.observableArray();
            this.informationElement = ko.observable();
            this.legendEntries = ko.observableArray();
            this.nodeSearchFilter = ko.observable('');
            this.expandedSearchId = ko.observable();
            this.searchNodes = ko.computed(function() {
                var filter = self.nodeSearchFilter();
                var elements = self.elements();
                var viz = self.viz();
                var filteredNodes = [];
                elements.forEach(function(element) {
                    if (element.isNode()) {
                        var data = element.data();
                        if (!data.shownRelationsCount) data.shownRelationsCount = ko.observable();
                        if (data.displayname.toLowerCase().indexOf(filter) !== -1) {
                            data.graph = resourceTypeLookup[data.graph_id];
                            data.shownRelationsCount(viz.edges('[source = "' + data.id + '"]').length +
                                viz.edges('[target = "' + data.id + '"]'). length);
                            filteredNodes.push(data);
                        }
                    }
                });
                return filteredNodes;
            });
            // strips URL from relationship labels, if present, for presentation
            var getRelationshipLabel = function(edgeData) {
                var label;
                try {
                    var url = new window.URL(edgeData.relationshiptype_label);
                    label = url.pathname.split('/')[url.pathname.split('/').length - 1];
                } catch (e) {
                    label = edgeData.relationshiptype_label;
                }
                return label;
            };
            this.informationElementRelationships = ko.computed(function() {
                var relationships = [];
                var informationElement = self.informationElement();
                var viz = self.viz();
                self.elements();
                if (informationElement && viz && !informationElement.source) {
                    var sourceEdges = viz.edges('[source = "' + informationElement.id + '"]');
                    var targetEdges = viz.edges('[target = "' + informationElement.id + '"]');
                    var addRelationship = function(edge, nodeType) {
                        var edgeData = edge.data();
                        var nodeData = edge[nodeType]().data();
                        var label = getRelationshipLabel(edgeData);

                        relationships.push({
                            label: label,
                            node: nodeData,
                            edge: edgeData,
                            informationElement: self.informationElement
                        });
                    };
                    sourceEdges.forEach(function(edge) {
                        addRelationship(edge, 'target');
                    });
                    targetEdges.forEach(function(edge) {
                        addRelationship(edge, 'source');
                    });
                }
                return relationships;
            });
            this.edgeInformation = ko.computed(function() {
                var informationElement = self.informationElement();
                var viz = self.viz();
                if (informationElement && viz && informationElement.source) {
                    var sourceData = viz.getElementById(informationElement.source).data();
                    var targetData = viz.getElementById(informationElement.target).data();
                    return {
                        label: getRelationshipLabel(informationElement),
                        source: sourceData,
                        sourceGraph: resourceTypeLookup[sourceData['graph_id']],
                        target: targetData,
                        targetGraph: resourceTypeLookup[targetData['graph_id']]
                    };
                }
            });

            WorkbenchViewmodel.apply(this, [params]);

            var getResourceRelations = function(resourceId) {
                var url = arches.urls.related_resources + resourceId + '?paginate=false';
                return window.fetch(url);
            };
            var resourceTypeLookup = {};
            var dataToElement = function(data) {
                data.source = data.resourceinstanceidfrom;
                data.target = data.resourceinstanceidto;
                if (data.source) {
                    data.id = data.source + data.target;
                } else {
                    data.id = data.resourceinstanceid;
                    data.totalRelations = data.total_relations.value;
                }
                var classes = [];
                if (data.graph_id) classes.push(resourceTypeLookup[data.graph_id].className);
                if (data.focus) classes.push('focus');
                return {
                    data: data,
                    classes: classes,
                    selected: data.focus
                };
            };
            this.expandNode = function(node) {
                if (node.id) getResourceRelations(node.id)
                    .then(function(response) {
                        return response.json();
                    })
                    .then(function(result) {
                        var viz = self.viz();
                        var elements = result.related_resources.concat(result.resource_relationships)
                            .map(dataToElement)
                            .filter(function(element) {
                                var elements = viz.getElementById(element.data.id);
                                if (element.source) elements = elements.concat(
                                    viz.getElementById(element.source + element.target),
                                    viz.getElementById(element.target + element.source)
                                );
                                return elements.length === 0;
                            });
                        viz.add(elements);
                        self.elements(viz.elements());
                        viz.layout(layout).run();
                        viz.fit(null, fitPadding);
                    });
            };
            var getStyle = function() {
                self.legendEntries([]);
                var nodeSize = 86;
                var lineColor = '#606060';
                var styles = [{
                    "selector": "node",
                    "style": {
                        "content": "data(displayname)",
                        "font-size": "18px",
                        "width": nodeSize,
                        "height": nodeSize,
                        "text-valign": "center",
                        "text-halign": "center",
                        "border-color": lineColor,
                        "border-width": 1
                    }
                }, {
                    "selector": "node.focus",
                    "style": {
                        "font-weight": "bold"
                    }
                }, {
                    "selector": "node:selected",
                    "style": {
                        "border-width": 5
                    }
                }, {
                    "selector": "edge",
                    "style": {
                        "line-color": lineColor
                    }
                }, {
                    "selector": "edge:selected",
                    "style": {
                        "width": 6,
                        "line-color": lineColor
                    }
                }];
                for (var resourceId in resourceTypeLookup) {
                    var color = resourceTypeLookup[resourceId].fillColor || '#CCCCCC';
                    var style = {
                        "selector": "node." + resourceTypeLookup[resourceId].className,
                        "style": {
                            "background-color": color
                        }
                    };
                    styles.push(style);
                    self.legendEntries.push(resourceTypeLookup[resourceId]);
                }
                return styles;
            };
            var updateCytoscapeConfig = function(elements) {
                self.cytoscapeConfig({
                    selectionType: 'single',
                    elements: elements,
                    layout: layout,
                    style: getStyle()
                });
            };
            var updateFocusResource = function() {
                var resourceId = self.focusResourceId();
                if (resourceId) {
                    self.viz(null);
                    getResourceRelations(resourceId)
                        .then(function(response) {
                            return response.json();
                        })
                        .then(function(result) {
                            var i = 0;
                            for (var resourceId in result.node_config_lookup) {
                                result.node_config_lookup[resourceId].className = 'resource-type-' + i;
                                i++;
                            }
                            resourceTypeLookup = result.node_config_lookup;
                            result.resource_instance.focus = true;
                            result.resource_instance['total_relations'] = {
                                value: result.resource_relationships.length
                            };
                            var elements = [dataToElement(result.resource_instance)]
                                .concat(
                                    result.related_resources.concat(result.resource_relationships)
                                        .map(dataToElement)
                                );
                            self.selection(elements[0].data);
                            updateCytoscapeConfig(elements);
                            self.elements(self.viz().elements());
                        });
                }
            };

            this.focusResourceId.subscribe(updateFocusResource);
            this.viz.subscribe(function(viz) {
                if (!viz) {
                    self.cytoscapeConfig(null);
                    self.selection(null);
                }
                else {
                    viz.on('select', 'node, edge', function(e) {
                        // prevents multiple selection
                        viz.elements().not(e.target).unselect();

                        self.selection(e.target.data());
                    });
                    viz.on('unselect', 'node, edge', function() {
                        self.selection(null);
                    });
                }
            });

            this.activeTab.subscribe(function() {
                var viz = self.viz();
                if (viz) viz.resize();
            });

            this.selection.subscribe(function(selection) {
                var mode = self.selectionMode();
                var viz = self.viz();
                if (selection) switch (mode) {
                case 'expand':
                    if (selection.source) viz.elements().unselect();
                    else self.expandNode(selection);
                    break;
                case 'delete':
                    var element = viz.getElementById(selection.id);
                    var informationElement = self.informationElement();
                    var informationElementId = informationElement ? informationElement.id : null;
                    if (!selection.source) viz.edges().forEach(function(edge) {
                        if (edge.source().id() === selection.id ||
                            edge.target().id() === selection.id) {
                            if (edge.id() === informationElementId) self.informationElement(null);
                            viz.remove(edge);
                            self.elements.remove(edge);
                        }
                    });
                    if (selection.id === informationElementId) self.informationElement(null);
                    viz.remove(element);
                    self.elements.remove(element);
                    viz.fit(null, fitPadding);
                    break;
                case 'focus':
                    if (selection.source) viz.elements().unselect();
                    else {
                        self.focusResourceId(selection.id);
                        self.informationElement(selection);
                    }
                    break;
                default:
                    self.informationElement(selection);
                    break;
                }
            });

            self.informationElement.subscribe(function(data) {
                var viz = self.viz();
                if (data) {
                    if (viz) {
                        var element = viz.getElementById(data.id);
                        if (!element.selected()) {
                            self.selectionMode('information');
                            element.select();
                        }
                    }
                    self.activeTab('information');
                }
            });

            this.selectionMode.subscribe(function() {
                var viz = self.viz();
                viz.elements().unselect();
            });

            updateFocusResource();
        },
        template: { require: 'text!templates/views/components/related-resources-graph.htm' }
    });
});
<commit_msg>nit re: #7360<commit_after>define([
    'arches',
    'knockout',
    'views/components/workbench',
    'bindings/cytoscape'
], function(arches, ko, WorkbenchViewmodel) {
    return ko.components.register('related-resources-graph', {
        viewModel: function(params) {
            var self = this;
            var layout = {
                name: "cose",
                animate: true,
                animationThreshold: 10
            };
            var fitPadding = 100;

            this.viz = ko.observable();
            this.cytoscapeConfig = ko.observable();
            this.focusResourceId = ko.isObservable(params.resourceId) ? params.resourceId : ko.observable(params.resourceId);
            this.selection = ko.observable();
            this.selectionMode = ko.observable('information');
            this.elements = ko.observableArray();
            this.informationElement = ko.observable();
            this.legendEntries = ko.observableArray();
            this.nodeSearchFilter = ko.observable('');
            this.expandedSearchId = ko.observable();
            this.searchNodes = ko.computed(function() {
                var filter = self.nodeSearchFilter();
                var elements = self.elements();
                var viz = self.viz();
                var filteredNodes = [];
                if (viz) elements.forEach(function(element) {
                    if (element.isNode()) {
                        var data = element.data();
                        if (!data.shownRelationsCount) data.shownRelationsCount = ko.observable();
                        if (data.displayname.toLowerCase().indexOf(filter) !== -1) {
                            data.graph = resourceTypeLookup[data.graph_id];
                            data.shownRelationsCount(viz.edges('[source = "' + data.id + '"]').length +
                                viz.edges('[target = "' + data.id + '"]'). length);
                            filteredNodes.push(data);
                        }
                    }
                });
                return filteredNodes;
            });
            // strips URL from relationship labels, if present, for presentation
            var getRelationshipLabel = function(edgeData) {
                var label;
                try {
                    var url = new window.URL(edgeData.relationshiptype_label);
                    label = url.pathname.split('/')[url.pathname.split('/').length - 1];
                } catch (e) {
                    label = edgeData.relationshiptype_label;
                }
                return label;
            };
            this.informationElementRelationships = ko.computed(function() {
                var relationships = [];
                var informationElement = self.informationElement();
                var viz = self.viz();
                self.elements();
                if (informationElement && viz && !informationElement.source) {
                    var sourceEdges = viz.edges('[source = "' + informationElement.id + '"]');
                    var targetEdges = viz.edges('[target = "' + informationElement.id + '"]');
                    var addRelationship = function(edge, nodeType) {
                        var edgeData = edge.data();
                        var nodeData = edge[nodeType]().data();
                        var label = getRelationshipLabel(edgeData);

                        relationships.push({
                            label: label,
                            node: nodeData,
                            edge: edgeData,
                            informationElement: self.informationElement
                        });
                    };
                    sourceEdges.forEach(function(edge) {
                        addRelationship(edge, 'target');
                    });
                    targetEdges.forEach(function(edge) {
                        addRelationship(edge, 'source');
                    });
                }
                return relationships;
            });
            this.edgeInformation = ko.computed(function() {
                var informationElement = self.informationElement();
                var viz = self.viz();
                if (informationElement && viz && informationElement.source) {
                    var sourceData = viz.getElementById(informationElement.source).data();
                    var targetData = viz.getElementById(informationElement.target).data();
                    return {
                        label: getRelationshipLabel(informationElement),
                        source: sourceData,
                        sourceGraph: resourceTypeLookup[sourceData['graph_id']],
                        target: targetData,
                        targetGraph: resourceTypeLookup[targetData['graph_id']]
                    };
                }
            });

            WorkbenchViewmodel.apply(this, [params]);

            var getResourceRelations = function(resourceId) {
                var url = arches.urls.related_resources + resourceId + '?paginate=false';
                return window.fetch(url);
            };
            var resourceTypeLookup = {};
            var dataToElement = function(data) {
                data.source = data.resourceinstanceidfrom;
                data.target = data.resourceinstanceidto;
                if (data.source) {
                    data.id = data.source + data.target;
                } else {
                    data.id = data.resourceinstanceid;
                    data.totalRelations = data.total_relations.value;
                }
                var classes = [];
                if (data.graph_id) classes.push(resourceTypeLookup[data.graph_id].className);
                if (data.focus) classes.push('focus');
                return {
                    data: data,
                    classes: classes,
                    selected: data.focus
                };
            };
            this.expandNode = function(node) {
                if (node.id) getResourceRelations(node.id)
                    .then(function(response) {
                        return response.json();
                    })
                    .then(function(result) {
                        var viz = self.viz();
                        var elements = result.related_resources.concat(result.resource_relationships)
                            .map(dataToElement)
                            .filter(function(element) {
                                var elements = viz.getElementById(element.data.id);
                                if (element.source) elements = elements.concat(
                                    viz.getElementById(element.source + element.target),
                                    viz.getElementById(element.target + element.source)
                                );
                                return elements.length === 0;
                            });
                        viz.add(elements);
                        self.elements(viz.elements());
                        viz.layout(layout).run();
                        viz.fit(null, fitPadding);
                    });
            };
            var getStyle = function() {
                self.legendEntries([]);
                var nodeSize = 86;
                var lineColor = '#606060';
                var styles = [{
                    "selector": "node",
                    "style": {
                        "content": "data(displayname)",
                        "font-size": "18px",
                        "width": nodeSize,
                        "height": nodeSize,
                        "text-valign": "center",
                        "text-halign": "center",
                        "border-color": lineColor,
                        "border-width": 1
                    }
                }, {
                    "selector": "node.focus",
                    "style": {
                        "font-weight": "bold"
                    }
                }, {
                    "selector": "node:selected",
                    "style": {
                        "border-width": 5
                    }
                }, {
                    "selector": "edge",
                    "style": {
                        "line-color": lineColor
                    }
                }, {
                    "selector": "edge:selected",
                    "style": {
                        "width": 6,
                        "line-color": lineColor
                    }
                }];
                for (var resourceId in resourceTypeLookup) {
                    var color = resourceTypeLookup[resourceId].fillColor || '#CCCCCC';
                    var style = {
                        "selector": "node." + resourceTypeLookup[resourceId].className,
                        "style": {
                            "background-color": color
                        }
                    };
                    styles.push(style);
                    self.legendEntries.push(resourceTypeLookup[resourceId]);
                }
                return styles;
            };
            var updateCytoscapeConfig = function(elements) {
                self.cytoscapeConfig({
                    selectionType: 'single',
                    elements: elements,
                    layout: layout,
                    style: getStyle()
                });
            };
            var updateFocusResource = function() {
                var resourceId = self.focusResourceId();
                if (resourceId) {
                    self.viz(null);
                    getResourceRelations(resourceId)
                        .then(function(response) {
                            return response.json();
                        })
                        .then(function(result) {
                            var i = 0;
                            for (var resourceId in result.node_config_lookup) {
                                result.node_config_lookup[resourceId].className = 'resource-type-' + i;
                                i++;
                            }
                            resourceTypeLookup = result.node_config_lookup;
                            result.resource_instance.focus = true;
                            result.resource_instance['total_relations'] = {
                                value: result.resource_relationships.length
                            };
                            var elements = [dataToElement(result.resource_instance)]
                                .concat(
                                    result.related_resources.concat(result.resource_relationships)
                                        .map(dataToElement)
                                );
                            self.selection(elements[0].data);
                            updateCytoscapeConfig(elements);
                            self.elements(self.viz().elements());
                        });
                }
            };

            this.focusResourceId.subscribe(updateFocusResource);
            this.viz.subscribe(function(viz) {
                if (!viz) {
                    self.cytoscapeConfig(null);
                    self.selection(null);
                }
                else {
                    viz.on('select', 'node, edge', function(e) {
                        // prevents multiple selection
                        viz.elements().not(e.target).unselect();

                        self.selection(e.target.data());
                    });
                    viz.on('unselect', 'node, edge', function() {
                        self.selection(null);
                    });
                }
            });

            this.activeTab.subscribe(function() {
                var viz = self.viz();
                if (viz) viz.resize();
            });

            this.selection.subscribe(function(selection) {
                var mode = self.selectionMode();
                var viz = self.viz();
                if (selection) switch (mode) {
                case 'expand':
                    if (selection.source) viz.elements().unselect();
                    else self.expandNode(selection);
                    break;
                case 'delete':
                    var element = viz.getElementById(selection.id);
                    var informationElement = self.informationElement();
                    var informationElementId = informationElement ? informationElement.id : null;
                    if (!selection.source) viz.edges().forEach(function(edge) {
                        if (edge.source().id() === selection.id ||
                            edge.target().id() === selection.id) {
                            if (edge.id() === informationElementId) self.informationElement(null);
                            viz.remove(edge);
                            self.elements.remove(edge);
                        }
                    });
                    if (selection.id === informationElementId) self.informationElement(null);
                    viz.remove(element);
                    self.elements.remove(element);
                    viz.fit(null, fitPadding);
                    break;
                case 'focus':
                    if (selection.source) viz.elements().unselect();
                    else {
                        self.focusResourceId(selection.id);
                        self.informationElement(selection);
                    }
                    break;
                default:
                    self.informationElement(selection);
                    break;
                }
            });

            self.informationElement.subscribe(function(data) {
                var viz = self.viz();
                if (data) {
                    if (viz) {
                        var element = viz.getElementById(data.id);
                        if (!element.selected()) {
                            self.selectionMode('information');
                            element.select();
                        }
                    }
                    self.activeTab('information');
                }
            });

            this.selectionMode.subscribe(function() {
                var viz = self.viz();
                viz.elements().unselect();
            });

            updateFocusResource();
        },
        template: { require: 'text!templates/views/components/related-resources-graph.htm' }
    });
});
<|endoftext|>


<commit_before>var Raintime = {};
Raintime.ComponentManager = (function () {

	function preRender (id) {
		console.log('preRender ' + id);
	}

	function postRender (id) {
		console.log('postRender ' + id);
	}

	function init (id) {
		console.log('init component ' + id);
	}

	return {
		preRender 	: preRender,
		postRender	: postRender
	}
})();<commit_msg>skel work<commit_after>var Raintime = (function () {

	function Component (id) {
		this.id = id;
		this.controller;
		this.parent = null;
		this.childs = [];
	}

	Component.prototype = {
		addParent : function (o) {
			this.parent = o;
		},
		addChild : function (o) {
			this.childs.push(o);
		},

	}

	var _id = 0;
	function createComponent(id) {
		var id = id ? id : 'id' + (++_id);
		return new Component(id);
	}

	function ComponentController () {

		this.preRender = function (id) {
			console.log('preRender ' + id);
		}

		this.postRender = function (id) {
			console.log('postRender ' + id);
		};

		this.init = function (id) {
			console.log('init component ' + id);
		};
	}

	function ComponentRegistry () {
		var components = {};

		this.register = function (id, controllerpath) {
			console.log('register component ' + id);
			if (components[id]) {
				return;
			}
			return (function () {
				var comp = createComponent(id);
				components[id] = comp;
				require([controllerpath], function (obj) {
					comp.controller = obj;
					console.log('registered component ' + id);
					if (obj.init) {
						obj.init();
					}
				});
				return comp;
			})();
		}

		this.deregister = function () {
			delete components[id];
		}
	}

	return {
		createComponent : createComponent,
		ComponentRegistry : new ComponentRegistry(),
		ComponentController : new ComponentController(),
		//Logger : new Logger(),
	}
})();

if (typeof exports != 'undefined') {
	var c = Raintime.createComponent();
	c.addParent('foo');
	console.log(c);
}<|endoftext|>


<commit_before>import React from 'react'
import { PropTypes } from 'react'

// REDUX
import { connect } from 'react-redux'

import ContributorEdit from 'views/pages/explore/dialect/Contributor/edit'
import validator from './validator'
import internationalization from './internationalization'
const { object, string } = PropTypes

export class RecorderEdit extends React.Component {
  static propTypes = {
    className: string,
    // REDUX: reducers/state
    routeParams: object.isRequired,
  }
  static defaultProps = {
    className: 'FormRecorder',
  }

  render() {
    const { routeParams } = this.props
    const { theme, dialect_path } = routeParams
    const createUrl = `/${theme}${dialect_path}/create/recorder`
    const editUrl = `/${theme}${dialect_path}/edit/recorder`
    return (
      <ContributorEdit
        createUrl={createUrl}
        editUrl={editUrl}
        className={this.props.className}
        validator={validator}
        copy={internationalization}
      />
    )
  }
}

// REDUX: reducers/state
const mapStateToProps = (state) => {
  const { navigation } = state

  const { route } = navigation

  return {
    routeParams: route.routeParams,
  }
}
export default connect(
  mapStateToProps,
  null
)(RecorderEdit)
<commit_msg>ContributorEdit: Drop unused prop<commit_after>import React from 'react'
import { PropTypes } from 'react'

// REDUX
import { connect } from 'react-redux'

import ContributorEdit from 'views/pages/explore/dialect/Contributor/edit'
import validator from './validator'
import internationalization from './internationalization'
const { object, string } = PropTypes

export class RecorderEdit extends React.Component {
  static propTypes = {
    className: string,
    // REDUX: reducers/state
    routeParams: object.isRequired,
  }
  static defaultProps = {
    className: 'FormRecorder',
  }

  render() {
    const { routeParams } = this.props
    const { theme, dialect_path } = routeParams
    const createUrl = `/${theme}${dialect_path}/create/recorder`
    return (
      <ContributorEdit
        createUrl={createUrl}
        className={this.props.className}
        validator={validator}
        copy={internationalization}
      />
    )
  }
}

// REDUX: reducers/state
const mapStateToProps = (state) => {
  const { navigation } = state

  const { route } = navigation

  return {
    routeParams: route.routeParams,
  }
}
export default connect(
  mapStateToProps,
  null
)(RecorderEdit)
<|endoftext|>


<commit_before>'use strict'
/**
 * Created by acastillo on 7/1/16.
 */
define([
    'file-saver',
    'src/util/api',
    'src/util/ui',
    'https://www.lactame.com/lib/openchemlib-extended/1.11.0/openchemlib-extended.js',
    'https://www.lactame.com/lib/chemcalc/3.0.6/chemcalc.js',
    'https://www.lactame.com/lib/eln-plugin/0.0.2/eln-plugin.js',
    'https://www.lactame.com/github/cheminfo-js/visualizer-helper/7f9c4d2c296389ed263a43826bafeba1164d13de/rest-on-couch/Roc.js'
], function (fileSaver, API, UI, OCLE, CC, elnPlugin, Roc) {

    var defaultOptions = {
        varName: 'sample',
        track: true
    };

    class Sample {
        constructor(couchDB, uuid, options) {
            this.options = Object.assign({}, defaultOptions, options);

            var roc = API.cache('roc');
            if (!roc) {
                roc = new Roc({
                    url: couchDB.url,
                    database: couchDB.database,
                    processor: elnPlugin,
                    kind: couchDB.kind
                });
                API.cache('roc', roc);
            }
            this.roc = roc;

            this.uuid = uuid;
            if (!this.uuid) {
                UI.showNotification("Cannot create an editable sample without an uuid", 'error');
                return;
            }
            this._loadInstanceInVisualizer();
        }

        _loadInstanceInVisualizer() {
            this.roc.document(this.uuid, {
                varName: this.options.varName
            }).then(sample => {
                this.sample = sample;
                var sampleVar = API.getVar(this.options.varName);
                API.setVariable('sampleCode', sampleVar, ['$id', 0]);
                API.setVariable('batchCode', sampleVar, ['$id', 1]);
                API.setVariable('creationDate', sampleVar, ['$creationDate']);
                API.setVariable('modificationDate', sampleVar, ['$modificationDate']);
                API.setVariable('content', sampleVar, ['$content']);
                API.setVariable('molfile', sampleVar, ['$content', 'general', 'molfile']);
                API.setVariable('mf', sampleVar, ['$content', 'general', 'mf']);
                API.setVariable('mw', sampleVar, ['$content', 'general', 'mw']);
                API.setVariable('description', sampleVar, ['$content', 'general', 'description']);
                API.setVariable('iupac', sampleVar, ['$content', 'general', 'iupac']);
                API.setVariable('bp', sampleVar, ['$content', 'physical', 'bp']);
                API.setVariable('nd', sampleVar, ['$content', 'physical', 'nd']);
                API.setVariable('mp', sampleVar, ['$content', 'physical', 'mp']);
                API.setVariable('density', sampleVar, ['$content', 'physical', 'density']);
                API.setVariable('nmr', sampleVar, ['$content', 'spectra', 'nmr']);
                API.setVariable('ir', sampleVar, ['$content', 'spectra', 'ir']);
                API.setVariable('mass', sampleVar, ['$content', 'spectra', 'mass']);
                this.updateAttachments(sample);

                this.updateChemcalc();
                initializeNMRAssignment();

                sample.onChange((event) => {
                    if (typeof IframeBridge !== 'undefined') {
                        IframeBridge.postMessage('tab.status', {
                            saved: false
                        });
                    }

                    console.log("change event received", event.jpath.join('.'), event);

                    switch (event.jpath.join('.')) {
                        case 'general.molfile':

                            break;
                        case 'general.mf':
                            this.updateChemcalc();
                            break;
                    }
                });

                if (typeof OCLE != 'undefined' && this.options.track) {
                    var expandableMolecule = new ExpandableMolecule(sample);
                    API.cache('expandableMolecule', expandableMolecule);
                }
            });
        }

        updateChemcalc() {
            this.chemcalc=undefined;
            if (this.sample.general && this.sample.general.mf) {
                try {
                    this.chemcalc=CC.analyzeMF(this.sample.general.mf);
                }
            }
        }

        updateAttachments(entry) {
            return this.roc.getAttachmentList(this.uuid).then(function (list) {
                API.createData('sampleAttachments', list);
            })
        }

        handleActionSD(action) {
            switch (action.name) {
                case 'reset1d':
                case 'reset2d':
                    if (this.event !== 'action') return;

                    var type;
                    if (action.name === 'reset1d') type = '1'
                    else if (action.name === 'reset2d') type = '2'
                    else return;

                    var legend = API.cache('legend');
                    if (!legend) {
                        legend = {
                            1: {},
                            2: {}
                        }
                        API.cache('legend', legend);
                    }

                    legend[type] = {};

                    type = type + 'd';
                    API.createData('black', null);
                    API.createData('annot' + type, null);
                    API.createData('legend' + type, {});
                    API.createData('acs', null);

                    break;
                case 'executePeakPicking':
                    //API.doAction("reset1d");
                    // the action may be generated by clicking on a line or clicking on the button to
                    // recalculate the peak picking.
                    var editedNmr;
                    if (action.value.dimension) { // Fired from click on row. We can not take variable because it may not exist yet
                        editedNmr = action.value;
                        if (editedNmr.dimension > 1) {
                            API.createData('black2d', editedNmr.jcamp.data);
                            API.switchToLayer('2D');
                            return;
                        } else {
                            API.switchToLayer('Default layer');
                            API.createData('black1d', editedNmr.jcamp.data);
                        }
                    } else { // we click on the button, show an alert if we want to redo peak picking
                        editedNmr = API.getData('editedNmr');
                        if (editedNmr.dimension > 1) {
                            if (typeof UI != "undefined")
                                UI.showNotification('Peak picking can only be applied on 1D spectra', 'warning');
                            return;
                        }
                    }
                    if (action.value.integral) {//Fired from button
                        doAssignment();
                    } else {
                        if (!editedNmr.range || !editedNmr.range.length) {
                            doAssignment();
                        } else {
                            API.setVariable("editedRange", API.getVariable('editedNmr'), ["range"]);
                        }
                    }
                    API.createData("nmrParams", {
                        "nucleus": editedNmr.nucleus[0],
                        "observe": Math.floor(editedNmr.frequency / 10) * 10
                    });
                    break;
                default:
                    return false;
            }
            return true;
        }

         doAssignment() {
            var jcamp = editedNmr.getChild(['jcamp', 'data']);

            jcamp.then(function(jcamp) {
                jcamp = String(jcamp.get());
                var ppOptions = JSON.parse(JSON.stringify(API.getData("options1H")));
                var integral = ppOptions.integral;
                //console.log(ppOptions);
                if(!ppOptions.noiseFactor){
                    ppOptions = {"noiseFactor":0.8,"clean":true,"compile":true,"optimize":false,"integralFn":"sum", "type":"1H"};
                }

                var spectrum = SD.NMR.fromJcamp(jcamp);
                //spectrum.fillWith(4.7,4.9,0);
                //spectrum.fillWith(-0.1,0.1,0);
                var intFN = 0;
                if(ppOptions.integralFn=="peaks"){
                    intFN=1;
                }
                var peakPicking = spectrum.nmrPeakDetection({"nH":integral,
                    realTop:true,
                    thresholdFactor:ppOptions.noiseFactor,
                    clean:ppOptions.clean,
                    compile:ppOptions.compile,
                    optimize:ppOptions.optimize,
                    integralFn:intFN,
                    idPrefix:spectrum.getNucleus()+"",
                    gsdOptions:{minMaxRatio:0.001, smoothY:false, broadWidth:0},
                    format:"new"
                });
                editedNmr.setChildSync(['range'], peakPicking);
                API.setVariable("editedRange",API.getVariable('editedNmr'),["range"]);
            });

        }

        handleAction(action) {
            if (!action) return;

            if (handleActionSD(action)) return;

            switch (action.name) {
                case 'refresh':
                    this.roc.get(this.uuid);
                    break;
                case 'save':
                    this.roc.update(this.sample).then(function () {
                        if (typeof IframeBridge != 'undefined') {
                            IframeBridge.postMessage('tab.status', {
                                saved: true
                            });
                        }
                    });
                    break;

                case 'toggleJSMEEdition':
                    API.cache("expandableMolecule").toggleJSMEEdition();
                    break;
                case 'clearMolfile':
                    var molfile=API.getData('editableMolfile');
                    molfile.setValue('');
                    break;
                case 'swapHydrogens':
                    API.cache("expandableMolecule").setExpandedHydrogens();
                    break;
                case 'toggleNMR1hAdvancedOptions':
                    API.cache('nmr1hAdvancedOptions', ! API.cache('nmr1hAdvancedOptions'));
                case 'createOptions':
                    var advancedOptions1H = API.cache("nmr1hAdvancedOptions");
                    if (advancedOptions1H) {
                        API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").full);
                    } else {
                        API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").short);
                    }
                    break;
                case 'downloadSVG':
                    var blob = new Blob([this.action.value+""], {type: "application/jcamp-dx;charset=utf-8"});
                    fileSaver(blob, 'spectra.svg');
                    break;

                case 'deleteAttachment':
                    var attachment = action.value.name;
                    this.roc.deleteAttachment(sample, attachment).then(this.updateAttachments);
                    break;
                case 'deleteSpectra':
                    this.roc.unattach(sample, action.value).then(this.updateAttachments);
                    break;
                case 'attachNMR':
                case 'attachIR':
                case 'attachMass':
                    var type = action.name.replace("attach", "").toLowerCase();
                    var droppedDatas = data;
                    droppedDatas = droppedDatas.file || droppedDatas.str;
                    var prom = Promise.resolve();
                    for (let i = 0; i < droppedDatas.length; i++) {
                        prom = prom.then(() => {
                            var data = DataObject.resurrect(droppedDatas[i]);
                            return this.roc.attach(type, sample, data);
                        });
                    }

                    prom.then(() => {
                        this.updateAttachments(sample);
                    }).catch(() => {
                        this.updateAttachments(sample);
                    });
                    break;
                default:
                    break
            }

            initializeNMRAssignment() {
                console.log(this.chemcalc);

                API.createData('nmr1hOptions', {
                    "noiseFactor": 0.8,
                    "clean": true,
                    "compile": true,
                    "optimize": false,
                    "integralFn": "sum",
                    "integral": 30,
                    "type": "1H"
                });

                API.createData('nmr1hOndeTemplates', {
                    "full": {
                        "type": "object",
                        "properties": {
                            "integral": {
                                "type": "number",
                                "title": "value to fit the spectrum integral",
                                "label": "Integral"
                            },
                            "noiseFactor": {
                                "type": "number",
                                "title": "Mutiplier of the auto-detected noise level",
                                "label": "noiseFactor"
                            },
                            "clean": {
                                "type": "boolean",
                                "title": "Delete signals with integration less than 0.5",
                                "label": "clean"
                            },
                            "compile": {
                                "type": "boolean",
                                "title": "Compile the multiplets",
                                "label": "compile"
                            },
                            "optimize": {
                                "type": "boolean",
                                "title": "Optimize the peaks to fit the spectrum",
                                "label": "optimize"
                            },
                            "integralFn": {
                                "type": "string",
                                "title": "Type of integration",
                                "label": "Integral type",
                                "enum": [
                                    "sum",
                                    "peaks"
                                ]
                            },
                            "type": {
                                "type": "string",
                                "title": "Nucleus",
                                "label": "Nucleus",
                                "editable": false
                            }
                        }
                    },
                    "short": {
                        "type": "object",
                        "properties": {
                            "integral": {
                                "type": "number",
                                "title": "value to fit the spectrum integral",
                                "label": "Integral"
                            }
                        }
                    }
                }).then(function(nmr1hOndeTemplates) {
                    API.createData('nmr1hOndeTemplate', nmr1hOndeTemplates.short);
                });
            }
        }
    }

    class ExpandableMolecule {
        constructor(sampleIn) {
            this.sample = sampleIn;
            this.molfile = this.sample.$content.general.molfile + '';
            var molecule = OCLE.Molecule.fromMolfile(this.molfile);
            this.idCode = molecule.getIDCode();
            this.expandedHydrogens = false;
            this.jsmeEditionMode = false;
            API.createData('editableMolfile', this.molfile).then(
                (editableMolfile) => {
                    editableMolfile.onChange( (event) => {
                        // us this really a modification ? or a loop event ...
                        // need to compare former oclID with new oclID
                        var idCode = OCLE.Molecule.fromMolfile(event.target + '').getIDCode();
                        if (idCode != this.idCode) {
                            this.idCode = idCode;
                            this.molfile = event.target + '';
                            this.sample.setChildSync('$content.general.molfile', this.molfile);
                        } else {
                            console.log('no update');
                        }

                        // by default we would like the depict mode
                        this.updateMolfiles();
                        this.updateMF();
                    });
                    this.updateMolfiles();
                    this.toggleJSMEEdition(false);
                }
            );
        }

        toggleJSMEEdition(force, noDepictUpdate) {
            if (force !== undefined && force === this.jsmeEditionMode) return;
            if (force === undefined) {
                this.jsmeEditionMode = !this.jsmeEditionMode;
            } else {
                this.jsmeEditionMode = force;
            }
            var prefs = {
                "prefs": [
                    "oldlook",
                    "nozoom"
                ],
                "labelsize": "14",
                "bondwidth": "1",
                "defaultaction": "105",
                "highlightColor": "3",
                "outputResult": [
                    "yes"
                ]
            };

            if (this.jsmeEditionMode) {
                API.getData("editableMolfile").triggerChange();
                this.expandedHydrogens = false;
            } else {
                prefs.prefs.push('depict');
                if (!noDepictUpdate) {
                    this.expandedHydrogens = false;
                    API.createData("viewMolfile", this.viewMolfile);
                }

            }
            API.doAction('setJSMEPreferences', prefs)
        }

        setExpandedHydrogens(force) {
            if (force === undefined) {
                this.expandedHydrogens = !this.expandedHydrogens;
            } else {
                this.expandedHydrogens = force;
            }
            if (this.expandedHydrogens) {
                API.createData("viewMolfileExpandedH", this.viewMolfileExpandedH);
                this.toggleJSMEEdition(false, true);
            } else {
                API.createData("viewMolfile", this.viewMolfile);
            }
        }

        updateMolfiles() {
            // prevent the loop by checking actelionID
            var molecule = OCLE.Molecule.fromMolfile(this.molfile);
            this.viewMolfile = molecule.toVisualizerMolfile();

            molecule.addImplicitHydrogens();
            this.viewMolfileExpandedH = molecule.toVisualizerMolfile();
            this.mf = molecule.getMolecularFormula().formula;
            this.mw = molecule.getMolecularFormula().relativeWeight;
            this.nH = molecule.getNumberOfAtoms('H');
        }

        updateMF() {
            if (typeof UI != 'undefined')
                UI.showNotification('Updated mf and mw', 'info');
            this.sample.$content.general.molfile = this.molfile;
            this.sample.$content.general.mf = this.mf;
            this.sample.$content.general.mw = this.mw;
        }
    }

    return Sample;
});

<commit_msg>Add chemcalc<commit_after>'use strict'
/**
 * Created by acastillo on 7/1/16.
 */
define([
    'file-saver',
    'src/util/api',
    'src/util/ui',
    'https://www.lactame.com/lib/openchemlib-extended/1.11.0/openchemlib-extended.js',
    'https://www.lactame.com/lib/chemcalc/3.0.6/chemcalc.js',
    'https://www.lactame.com/lib/eln-plugin/0.0.2/eln-plugin.js',
    'https://www.lactame.com/github/cheminfo-js/visualizer-helper/7f9c4d2c296389ed263a43826bafeba1164d13de/rest-on-couch/Roc.js'
], function (fileSaver, API, UI, OCLE, CC, elnPlugin, Roc) {

    var defaultOptions = {
        varName: 'sample',
        track: true
    };

    class Sample {
        constructor(couchDB, uuid, options) {
            this.options = Object.assign({}, defaultOptions, options);

            var roc = API.cache('roc');
            if (!roc) {
                roc = new Roc({
                    url: couchDB.url,
                    database: couchDB.database,
                    processor: elnPlugin,
                    kind: couchDB.kind
                });
                API.cache('roc', roc);
            }
            this.roc = roc;

            this.uuid = uuid;
            if (!this.uuid) {
                UI.showNotification("Cannot create an editable sample without an uuid", 'error');
                return;
            }
            this._loadInstanceInVisualizer();
        }

        _loadInstanceInVisualizer() {
            this.roc.document(this.uuid, {
                varName: this.options.varName
            }).then(sample => {
                this.sample = sample;
                var sampleVar = API.getVar(this.options.varName);
                API.setVariable('sampleCode', sampleVar, ['$id', 0]);
                API.setVariable('batchCode', sampleVar, ['$id', 1]);
                API.setVariable('creationDate', sampleVar, ['$creationDate']);
                API.setVariable('modificationDate', sampleVar, ['$modificationDate']);
                API.setVariable('content', sampleVar, ['$content']);
                API.setVariable('molfile', sampleVar, ['$content', 'general', 'molfile']);
                API.setVariable('mf', sampleVar, ['$content', 'general', 'mf']);
                API.setVariable('mw', sampleVar, ['$content', 'general', 'mw']);
                API.setVariable('description', sampleVar, ['$content', 'general', 'description']);
                API.setVariable('iupac', sampleVar, ['$content', 'general', 'iupac']);
                API.setVariable('bp', sampleVar, ['$content', 'physical', 'bp']);
                API.setVariable('nd', sampleVar, ['$content', 'physical', 'nd']);
                API.setVariable('mp', sampleVar, ['$content', 'physical', 'mp']);
                API.setVariable('density', sampleVar, ['$content', 'physical', 'density']);
                API.setVariable('nmr', sampleVar, ['$content', 'spectra', 'nmr']);
                API.setVariable('ir', sampleVar, ['$content', 'spectra', 'ir']);
                API.setVariable('mass', sampleVar, ['$content', 'spectra', 'mass']);
                this.updateAttachments(sample);

                this.updateChemcalc();
                initializeNMRAssignment();

                sample.onChange((event) => {
                    if (typeof IframeBridge !== 'undefined') {
                        IframeBridge.postMessage('tab.status', {
                            saved: false
                        });
                    }

                    console.log("change event received", event.jpath.join('.'), event);

                    switch (event.jpath.join('.')) {
                        case 'general.molfile':

                            break;
                        case 'general.mf':
                            this.updateChemcalc();
                            break;
                    }
                });

                if (typeof OCLE != 'undefined' && this.options.track) {
                    var expandableMolecule = new ExpandableMolecule(sample);
                    API.cache('expandableMolecule', expandableMolecule);
                }
            });
        }

        updateChemcalc() {
            this.chemcalc=undefined;
            if (this.sample.general && this.sample.general.mf) {
                try {
                    this.chemcalc=CC.analyzeMF(this.sample.general.mf);
                } catch () {
                    UI.showNotification('Could not calculate molecular formula: '+e);
                    console.log(e);
                }
            }
        }

        updateAttachments(entry) {
            return this.roc.getAttachmentList(this.uuid).then(function (list) {
                API.createData('sampleAttachments', list);
            })
        }

        handleActionSD(action) {
            switch (action.name) {
                case 'reset1d':
                case 'reset2d':
                    if (this.event !== 'action') return;

                    var type;
                    if (action.name === 'reset1d') type = '1'
                    else if (action.name === 'reset2d') type = '2'
                    else return;

                    var legend = API.cache('legend');
                    if (!legend) {
                        legend = {
                            1: {},
                            2: {}
                        }
                        API.cache('legend', legend);
                    }

                    legend[type] = {};

                    type = type + 'd';
                    API.createData('black', null);
                    API.createData('annot' + type, null);
                    API.createData('legend' + type, {});
                    API.createData('acs', null);

                    break;
                case 'executePeakPicking':
                    //API.doAction("reset1d");
                    // the action may be generated by clicking on a line or clicking on the button to
                    // recalculate the peak picking.
                    var editedNmr;
                    if (action.value.dimension) { // Fired from click on row. We can not take variable because it may not exist yet
                        editedNmr = action.value;
                        if (editedNmr.dimension > 1) {
                            API.createData('black2d', editedNmr.jcamp.data);
                            API.switchToLayer('2D');
                            return;
                        } else {
                            API.switchToLayer('Default layer');
                            API.createData('black1d', editedNmr.jcamp.data);
                        }
                    } else { // we click on the button, show an alert if we want to redo peak picking
                        editedNmr = API.getData('editedNmr');
                        if (editedNmr.dimension > 1) {
                            if (typeof UI != "undefined")
                                UI.showNotification('Peak picking can only be applied on 1D spectra', 'warning');
                            return;
                        }
                    }
                    if (action.value.integral) {//Fired from button
                        doAssignment();
                    } else {
                        if (!editedNmr.range || !editedNmr.range.length) {
                            doAssignment();
                        } else {
                            API.setVariable("editedRange", API.getVariable('editedNmr'), ["range"]);
                        }
                    }
                    API.createData("nmrParams", {
                        "nucleus": editedNmr.nucleus[0],
                        "observe": Math.floor(editedNmr.frequency / 10) * 10
                    });
                    break;
                default:
                    return false;
            }
            return true;
        }

         doAssignment() {
            var jcamp = editedNmr.getChild(['jcamp', 'data']);

            jcamp.then(function(jcamp) {
                jcamp = String(jcamp.get());
                var ppOptions = JSON.parse(JSON.stringify(API.getData("options1H")));
                var integral = ppOptions.integral;
                //console.log(ppOptions);
                if(!ppOptions.noiseFactor){
                    ppOptions = {"noiseFactor":0.8,"clean":true,"compile":true,"optimize":false,"integralFn":"sum", "type":"1H"};
                }

                var spectrum = SD.NMR.fromJcamp(jcamp);
                //spectrum.fillWith(4.7,4.9,0);
                //spectrum.fillWith(-0.1,0.1,0);
                var intFN = 0;
                if(ppOptions.integralFn=="peaks"){
                    intFN=1;
                }
                var peakPicking = spectrum.nmrPeakDetection({"nH":integral,
                    realTop:true,
                    thresholdFactor:ppOptions.noiseFactor,
                    clean:ppOptions.clean,
                    compile:ppOptions.compile,
                    optimize:ppOptions.optimize,
                    integralFn:intFN,
                    idPrefix:spectrum.getNucleus()+"",
                    gsdOptions:{minMaxRatio:0.001, smoothY:false, broadWidth:0},
                    format:"new"
                });
                editedNmr.setChildSync(['range'], peakPicking);
                API.setVariable("editedRange",API.getVariable('editedNmr'),["range"]);
            });

        }

        handleAction(action) {
            if (!action) return;

            if (handleActionSD(action)) return;

            switch (action.name) {
                case 'refresh':
                    this.roc.get(this.uuid);
                    break;
                case 'save':
                    this.roc.update(this.sample).then(function () {
                        if (typeof IframeBridge != 'undefined') {
                            IframeBridge.postMessage('tab.status', {
                                saved: true
                            });
                        }
                    });
                    break;

                case 'toggleJSMEEdition':
                    API.cache("expandableMolecule").toggleJSMEEdition();
                    break;
                case 'clearMolfile':
                    var molfile=API.getData('editableMolfile');
                    molfile.setValue('');
                    break;
                case 'swapHydrogens':
                    API.cache("expandableMolecule").setExpandedHydrogens();
                    break;
                case 'toggleNMR1hAdvancedOptions':
                    API.cache('nmr1hAdvancedOptions', ! API.cache('nmr1hAdvancedOptions'));
                case 'createOptions':
                    var advancedOptions1H = API.cache("nmr1hAdvancedOptions");
                    if (advancedOptions1H) {
                        API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").full);
                    } else {
                        API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").short);
                    }
                    break;
                case 'downloadSVG':
                    var blob = new Blob([this.action.value+""], {type: "application/jcamp-dx;charset=utf-8"});
                    fileSaver(blob, 'spectra.svg');
                    break;

                case 'deleteAttachment':
                    var attachment = action.value.name;
                    this.roc.deleteAttachment(sample, attachment).then(this.updateAttachments);
                    break;
                case 'deleteSpectra':
                    this.roc.unattach(sample, action.value).then(this.updateAttachments);
                    break;
                case 'attachNMR':
                case 'attachIR':
                case 'attachMass':
                    var type = action.name.replace("attach", "").toLowerCase();
                    var droppedDatas = data;
                    droppedDatas = droppedDatas.file || droppedDatas.str;
                    var prom = Promise.resolve();
                    for (let i = 0; i < droppedDatas.length; i++) {
                        prom = prom.then(() => {
                            var data = DataObject.resurrect(droppedDatas[i]);
                            return this.roc.attach(type, sample, data);
                        });
                    }

                    prom.then(() => {
                        this.updateAttachments(sample);
                    }).catch(() => {
                        this.updateAttachments(sample);
                    });
                    break;
                default:
                    break
            }

            initializeNMRAssignment() {
                console.log(this.chemcalc);

                API.createData('nmr1hOptions', {
                    "noiseFactor": 0.8,
                    "clean": true,
                    "compile": true,
                    "optimize": false,
                    "integralFn": "sum",
                    "integral": 30,
                    "type": "1H"
                });

                API.createData('nmr1hOndeTemplates', {
                    "full": {
                        "type": "object",
                        "properties": {
                            "integral": {
                                "type": "number",
                                "title": "value to fit the spectrum integral",
                                "label": "Integral"
                            },
                            "noiseFactor": {
                                "type": "number",
                                "title": "Mutiplier of the auto-detected noise level",
                                "label": "noiseFactor"
                            },
                            "clean": {
                                "type": "boolean",
                                "title": "Delete signals with integration less than 0.5",
                                "label": "clean"
                            },
                            "compile": {
                                "type": "boolean",
                                "title": "Compile the multiplets",
                                "label": "compile"
                            },
                            "optimize": {
                                "type": "boolean",
                                "title": "Optimize the peaks to fit the spectrum",
                                "label": "optimize"
                            },
                            "integralFn": {
                                "type": "string",
                                "title": "Type of integration",
                                "label": "Integral type",
                                "enum": [
                                    "sum",
                                    "peaks"
                                ]
                            },
                            "type": {
                                "type": "string",
                                "title": "Nucleus",
                                "label": "Nucleus",
                                "editable": false
                            }
                        }
                    },
                    "short": {
                        "type": "object",
                        "properties": {
                            "integral": {
                                "type": "number",
                                "title": "value to fit the spectrum integral",
                                "label": "Integral"
                            }
                        }
                    }
                }).then(function(nmr1hOndeTemplates) {
                    API.createData('nmr1hOndeTemplate', nmr1hOndeTemplates.short);
                });
            }
        }
    }

    class ExpandableMolecule {
        constructor(sampleIn) {
            this.sample = sampleIn;
            this.molfile = this.sample.$content.general.molfile + '';
            var molecule = OCLE.Molecule.fromMolfile(this.molfile);
            this.idCode = molecule.getIDCode();
            this.expandedHydrogens = false;
            this.jsmeEditionMode = false;
            API.createData('editableMolfile', this.molfile).then(
                (editableMolfile) => {
                    editableMolfile.onChange( (event) => {
                        // us this really a modification ? or a loop event ...
                        // need to compare former oclID with new oclID
                        var idCode = OCLE.Molecule.fromMolfile(event.target + '').getIDCode();
                        if (idCode != this.idCode) {
                            this.idCode = idCode;
                            this.molfile = event.target + '';
                            this.sample.setChildSync('$content.general.molfile', this.molfile);
                        } else {
                            console.log('no update');
                        }

                        // by default we would like the depict mode
                        this.updateMolfiles();
                        this.updateMF();
                    });
                    this.updateMolfiles();
                    this.toggleJSMEEdition(false);
                }
            );
        }

        toggleJSMEEdition(force, noDepictUpdate) {
            if (force !== undefined && force === this.jsmeEditionMode) return;
            if (force === undefined) {
                this.jsmeEditionMode = !this.jsmeEditionMode;
            } else {
                this.jsmeEditionMode = force;
            }
            var prefs = {
                "prefs": [
                    "oldlook",
                    "nozoom"
                ],
                "labelsize": "14",
                "bondwidth": "1",
                "defaultaction": "105",
                "highlightColor": "3",
                "outputResult": [
                    "yes"
                ]
            };

            if (this.jsmeEditionMode) {
                API.getData("editableMolfile").triggerChange();
                this.expandedHydrogens = false;
            } else {
                prefs.prefs.push('depict');
                if (!noDepictUpdate) {
                    this.expandedHydrogens = false;
                    API.createData("viewMolfile", this.viewMolfile);
                }

            }
            API.doAction('setJSMEPreferences', prefs)
        }

        setExpandedHydrogens(force) {
            if (force === undefined) {
                this.expandedHydrogens = !this.expandedHydrogens;
            } else {
                this.expandedHydrogens = force;
            }
            if (this.expandedHydrogens) {
                API.createData("viewMolfileExpandedH", this.viewMolfileExpandedH);
                this.toggleJSMEEdition(false, true);
            } else {
                API.createData("viewMolfile", this.viewMolfile);
            }
        }

        updateMolfiles() {
            // prevent the loop by checking actelionID
            var molecule = OCLE.Molecule.fromMolfile(this.molfile);
            this.viewMolfile = molecule.toVisualizerMolfile();

            molecule.addImplicitHydrogens();
            this.viewMolfileExpandedH = molecule.toVisualizerMolfile();
            this.mf = molecule.getMolecularFormula().formula;
            this.mw = molecule.getMolecularFormula().relativeWeight;
            this.nH = molecule.getNumberOfAtoms('H');
        }

        updateMF() {
            if (typeof UI != 'undefined')
                UI.showNotification('Updated mf and mw', 'info');
            this.sample.$content.general.molfile = this.molfile;
            this.sample.$content.general.mf = this.mf;
            this.sample.$content.general.mw = this.mw;
        }
    }

    return Sample;
});

<|endoftext|>


<commit_before>/*eslint-env browser */
/*global require: false, module: false */

'use strict';

require('../css/km.css');
var _ = require('./underscore_ext');
var React = require('react');
var { PropTypes } = React;
var Modal = require('react-bootstrap/lib/Modal');
var { ListGroup, ListGroupItem, OverlayTrigger, Tooltip } = require('react-bootstrap/lib/');
var Axis = require('./Axis');
var {deepPureRenderMixin} = require('./react-utils');
var {linear, linearTicks} = require('./scale');
// XXX Warn on duplicate patients, and list patient ids?

// Basic sizes. Should make these responsive. How to make the svg responsive?
var margin = {top: 20, right: 50, bottom: 30, left: 50};
const HOVER = 'hover';

// XXX point at 100%? [xdomain[0] - 1, 1]
function line(xScale, yScale, values) {
	var coords = values.map(({t, s}) => [xScale(t), yScale(s)]);
	return ['M0,0', ...coords.map(([t, s]) => `H${t}V${s}`)].join(' ');
}

function censorLines(xScale, yScale, censors, className) {
	/*eslint-disable comma-spacing */
	return censors.map(({t, s}, i) =>
		<line
			key={i}
			className={className}
			x1={0} x2={0} y1={-5} y2={5}
			transform={`translate(${xScale(t)},${yScale(s)})`} />
	);
	/*eslint-enable comma-spacing */
}

function calcDims (viewDims, sizeRatios) {
	return _.mapObject(sizeRatios, (section) => {
		return _.mapObject(section, (ratio, side) => viewDims[side] * ratio);
	});
}

function checkIfActive(currentLabel, activeLabel) {
	// check whether this line group should be set to Active
	if (activeLabel)
		return (activeLabel === currentLabel);
	else
		return false;
}

var LineGroup = React.createClass({
	getInitialState: function() {
		return { isActive: false }
	},

	componentWillReceiveProps: function(newProps) {
		let { g, activeLabel } = newProps,
			[ color, label, curve ] = g,
			oldIsActive = this.state.isActive,
			activeStatus = checkIfActive(label, activeLabel);

		if (oldIsActive != activeStatus)
			this.setState({ isActive: activeStatus });
	},

	shouldComponentUpdate: function(newProps, newState) {
		//testing for any changes to g, and state's isActive parameter should be sufficient
		let gChanged = !_.isEqual(newProps.g, this.props.g),
			isActiveChanged = !_.isEqual(newState.isActive, this.state.isActive);

		return (gChanged || isActiveChanged);
	},

	render: function() {
		let { xScale, yScale, g, setActiveLabel } = this.props;
		let [ color, label, curve ] = g;
		var censors = curve.filter(pt => !pt.e);
		let activeLabelClassName = this.state.isActive ? HOVER : '';

		return (
			<g key={label} className='subgroup' stroke={color}
				onMouseOver={(e) => setActiveLabel(e, label)}
				onMouseOut={(e) => setActiveLabel(e, '')}>
				<path className={`outline ${activeLabelClassName}`} d={line(xScale, yScale, curve)}/>
				<path className={`line ${activeLabelClassName}`} d={line(xScale, yScale, curve)}/>
				{censorLines(xScale, yScale, censors, `outline ${activeLabelClassName}`)}
				{censorLines(xScale, yScale, censors, `line' ${activeLabelClassName}`)}
			</g>
		);
	}
});

var bounds = x => [_.min(x), _.max(x)];

function svg({colors, labels, curves}, setActiveLabel, activeLabel, size) {
	var height = size.height - margin.top - margin.bottom,
		width = size.width,
		xdomain = bounds(_.pluck(_.flatten(curves), 't')),
		xrange = [0, width],
		ydomain = [0, 1],
		yrange = [height, 0],
		xScale = linear(xdomain, xrange),
		yScale = linear(ydomain, yrange);

	var groupSvg = _.zip(colors, labels, curves).map((g, index) => {
		return <LineGroup
				key={index}
				xScale={xScale}
				yScale={yScale}
				g={g}
				activeLabel={activeLabel}
				setActiveLabel={setActiveLabel} />;
	});

	/*eslint-disable comma-spacing */
	return (
		<svg width={width} height={size.height}>
			<g transform={`translate(${margin.left}, ${margin.top})`}>
				<Axis
					groupProps={{
						className: 'x axis',
						transform: `translate(0, ${height})`
					}}
					domain={xdomain}
					range={xrange}
					scale={xScale}
					tickfn={linearTicks}
					orientation='bottom'
				/>
				<Axis
					groupProps={{
						className: 'y axis'
					}}
					domain={ydomain}
					range={yrange}
					scale={yScale}
					tickfn={linearTicks}
					orientation='left'>

					<text
						transform='rotate(-90)'
						y='6'
						x={-height}
						dy='.71em'
						textAnchor='start'>
						Survival percentage
					</text>
				</Axis>
				{groupSvg}
			</g>
		</svg>
	);
	/*eslint-enable comma-spacing */
}

var formatPValue = v => v == null ? String.fromCharCode(8709) : v.toPrecision(4);

var PValue = React.createClass({
	render: function () {
		var {logRank, pValue} = this.props;
		const tooltip = (
			<Tooltip id='p-value' placement='top'>
				Some individuals survival data are used more than once in the KM plot. Affected patients are:
				TCGA-G4-6317-02,
				TCGA-A6-2671-01, TCGA-A6-2680-01, TCGA-A6-2684-01, TCGA-A6-2685-01, TCGA-A6-2683-01, TCGA-AA-3520-01,
				TCGA-AA-3525-01. For more information and how to remove such duplications: https://goo.gl/TSQt6z.
			</Tooltip>
		);

		return (
			<ListGroup fill>
				<ListGroupItem>
					<OverlayTrigger
						placement='right'
						overlay={tooltip}
						trigger={['hover', 'click']}>

!

					</OverlayTrigger>
					P-Value = {formatPValue(pValue)}
				</ListGroupItem>
				<ListGroupItem>
					Log-rank Test Stats = {formatPValue(logRank)}
				</ListGroupItem>
			</ListGroup>
		)
	}
});

function makeLegendKey([color, curves, label], setActiveLabel, activeLabel) {
	// show colored line and category of curve
	let isActive = checkIfActive(label, activeLabel);
	let activeLabelClassName = isActive ? HOVER : '';
	let legendLineStyle = {
		backgroundColor: color,
		border: (isActive ? 2 : 1).toString() +'px solid',
		display: 'inline-block',
		height: 6,
		width: 25,
		verticalAlign: 'middle'
	};

	return (
		<li
			key={label}
			className={`list-group-item outline ${activeLabelClassName}`}
			onMouseOver={(e) => setActiveLabel(e, label)}
			onMouseOut={(e) => setActiveLabel(e, '')}>
			 {label} (n={curves.length})

	);
}

var Legend = React.createClass({
	propTypes: {
		activeLabel: PropTypes.string,
		columns: PropTypes.number,
		groups: PropTypes.object,
		setActiveLabel: PropTypes.func
	},

	render: function () {
		let { groups, setActiveLabel, activeLabel } = this.props;
		let { colors, curves, labels } = groups;
		let sets = _.zip(colors, curves, labels)
					.map((set, index) => makeLegendKey(set, setActiveLabel, activeLabel));

		return (
			<ListGroup className="legend">{sets}</ListGroup>
		);
	}
});

function makeGraph(groups, setActiveLabel, activeLabel, size) {
	return (

			{svg(groups, setActiveLabel, activeLabel, size)}

	);
}

function makeDefinitions(groups, setActiveLabel, activeLabel, size) {
	// get new size based on size ratio for definitions column

	return (

			<PValue pValue={groups.pValue} logRank={groups.KM_stats}/>
			<Legend groups={groups}
					setActiveLabel={setActiveLabel}
					activeLabel={activeLabel} />

	);
}

var KmPlot = React.createClass({
	mixins: [deepPureRenderMixin],
	propTypes: {
		eventClose: PropTypes.string,
		dims: PropTypes.object
	},
	size: {
		ratios: {
			graph: {
				width: 0.75,
				height: 1.0
			},
			definitions: {
				width: 0.25,
				height: 1.0
			}
		}
	},

	getDefaultProps: () => ({
		eventClose: 'km-close',
		dims: {
			height: 450,
			width: 860
		}
	}),

	getInitialState: function() {
		return { activeLabel: '' }
	},

	hide: function () {
		let {callback, eventClose} = this.props;
		callback([eventClose]);
	},

	setActiveLabel: function (e, label) {
		this.setState({ activeLabel: label });
	},

	render: function () {
		let { km: {title, label, groups}, dims } = this.props,
			{warning} = groups,
			fullLabel = warning ? `${label} (${warning})` : label,
			{ activeLabel } = this.state,
			sectionDims = calcDims(dims, this.size.ratios);
		// XXX Use bootstrap to lay this out, instead of tables + divs
		let Content = _.isEmpty(groups)
			?

Loading...

			:

				{makeGraph(groups, this.setActiveLabel, activeLabel, sectionDims.graph)}
				{makeDefinitions(groups, this.setActiveLabel, activeLabel, sectionDims.definitions)}

;

		return (
			<Modal show={true} bsSize='large' className='kmDialog' onHide={this.hide} ref="kmPlot">
				<Modal.Header closeButton className="container-fluid">

						<Modal.Title>Kaplan Meier</Modal.Title>

					{title}
				</Modal.Header>
				<Modal.Body className="container-fluid">
					{Content}
				</Modal.Body>
				<Modal.Footer className="container-fluid">
					<samp className='featureLabel'>{fullLabel}</samp>
				</Modal.Footer>
			</Modal>
		);
	}
});

module.exports = KmPlot;
<commit_msg>Error when km groups is null.<commit_after>/*eslint-env browser */
/*global require: false, module: false */

'use strict';

require('../css/km.css');
var _ = require('./underscore_ext');
var React = require('react');
var { PropTypes } = React;
var Modal = require('react-bootstrap/lib/Modal');
var { ListGroup, ListGroupItem, OverlayTrigger, Tooltip } = require('react-bootstrap/lib/');
var Axis = require('./Axis');
var {deepPureRenderMixin} = require('./react-utils');
var {linear, linearTicks} = require('./scale');
// XXX Warn on duplicate patients, and list patient ids?

// Basic sizes. Should make these responsive. How to make the svg responsive?
var margin = {top: 20, right: 50, bottom: 30, left: 50};
const HOVER = 'hover';

// XXX point at 100%? [xdomain[0] - 1, 1]
function line(xScale, yScale, values) {
	var coords = values.map(({t, s}) => [xScale(t), yScale(s)]);
	return ['M0,0', ...coords.map(([t, s]) => `H${t}V${s}`)].join(' ');
}

function censorLines(xScale, yScale, censors, className) {
	/*eslint-disable comma-spacing */
	return censors.map(({t, s}, i) =>
		<line
			key={i}
			className={className}
			x1={0} x2={0} y1={-5} y2={5}
			transform={`translate(${xScale(t)},${yScale(s)})`} />
	);
	/*eslint-enable comma-spacing */
}

function calcDims (viewDims, sizeRatios) {
	return _.mapObject(sizeRatios, (section) => {
		return _.mapObject(section, (ratio, side) => viewDims[side] * ratio);
	});
}

function checkIfActive(currentLabel, activeLabel) {
	// check whether this line group should be set to Active
	if (activeLabel)
		return (activeLabel === currentLabel);
	else
		return false;
}

var LineGroup = React.createClass({
	getInitialState: function() {
		return { isActive: false }
	},

	componentWillReceiveProps: function(newProps) {
		let { g, activeLabel } = newProps,
			[ color, label, curve ] = g,
			oldIsActive = this.state.isActive,
			activeStatus = checkIfActive(label, activeLabel);

		if (oldIsActive != activeStatus)
			this.setState({ isActive: activeStatus });
	},

	shouldComponentUpdate: function(newProps, newState) {
		//testing for any changes to g, and state's isActive parameter should be sufficient
		let gChanged = !_.isEqual(newProps.g, this.props.g),
			isActiveChanged = !_.isEqual(newState.isActive, this.state.isActive);

		return (gChanged || isActiveChanged);
	},

	render: function() {
		let { xScale, yScale, g, setActiveLabel } = this.props;
		let [ color, label, curve ] = g;
		var censors = curve.filter(pt => !pt.e);
		let activeLabelClassName = this.state.isActive ? HOVER : '';

		return (
			<g key={label} className='subgroup' stroke={color}
				onMouseOver={(e) => setActiveLabel(e, label)}
				onMouseOut={(e) => setActiveLabel(e, '')}>
				<path className={`outline ${activeLabelClassName}`} d={line(xScale, yScale, curve)}/>
				<path className={`line ${activeLabelClassName}`} d={line(xScale, yScale, curve)}/>
				{censorLines(xScale, yScale, censors, `outline ${activeLabelClassName}`)}
				{censorLines(xScale, yScale, censors, `line' ${activeLabelClassName}`)}
			</g>
		);
	}
});

var bounds = x => [_.min(x), _.max(x)];

function svg({colors, labels, curves}, setActiveLabel, activeLabel, size) {
	var height = size.height - margin.top - margin.bottom,
		width = size.width,
		xdomain = bounds(_.pluck(_.flatten(curves), 't')),
		xrange = [0, width],
		ydomain = [0, 1],
		yrange = [height, 0],
		xScale = linear(xdomain, xrange),
		yScale = linear(ydomain, yrange);

	var groupSvg = _.zip(colors, labels, curves).map((g, index) => {
		return <LineGroup
				key={index}
				xScale={xScale}
				yScale={yScale}
				g={g}
				activeLabel={activeLabel}
				setActiveLabel={setActiveLabel} />;
	});

	/*eslint-disable comma-spacing */
	return (
		<svg width={width} height={size.height}>
			<g transform={`translate(${margin.left}, ${margin.top})`}>
				<Axis
					groupProps={{
						className: 'x axis',
						transform: `translate(0, ${height})`
					}}
					domain={xdomain}
					range={xrange}
					scale={xScale}
					tickfn={linearTicks}
					orientation='bottom'
				/>
				<Axis
					groupProps={{
						className: 'y axis'
					}}
					domain={ydomain}
					range={yrange}
					scale={yScale}
					tickfn={linearTicks}
					orientation='left'>

					<text
						transform='rotate(-90)'
						y='6'
						x={-height}
						dy='.71em'
						textAnchor='start'>
						Survival percentage
					</text>
				</Axis>
				{groupSvg}
			</g>
		</svg>
	);
	/*eslint-enable comma-spacing */
}

var formatPValue = v => v == null ? String.fromCharCode(8709) : v.toPrecision(4);

var PValue = React.createClass({
	render: function () {
		var {logRank, pValue} = this.props;
		const tooltip = (
			<Tooltip id='p-value' placement='top'>
				Some individuals survival data are used more than once in the KM plot. Affected patients are:
				TCGA-G4-6317-02,
				TCGA-A6-2671-01, TCGA-A6-2680-01, TCGA-A6-2684-01, TCGA-A6-2685-01, TCGA-A6-2683-01, TCGA-AA-3520-01,
				TCGA-AA-3525-01. For more information and how to remove such duplications: https://goo.gl/TSQt6z.
			</Tooltip>
		);

		return (
			<ListGroup fill>
				<ListGroupItem>
					<OverlayTrigger
						placement='right'
						overlay={tooltip}
						trigger={['hover', 'click']}>

!

					</OverlayTrigger>
					P-Value = {formatPValue(pValue)}
				</ListGroupItem>
				<ListGroupItem>
					Log-rank Test Stats = {formatPValue(logRank)}
				</ListGroupItem>
			</ListGroup>
		)
	}
});

function makeLegendKey([color, curves, label], setActiveLabel, activeLabel) {
	// show colored line and category of curve
	let isActive = checkIfActive(label, activeLabel);
	let activeLabelClassName = isActive ? HOVER : '';
	let legendLineStyle = {
		backgroundColor: color,
		border: (isActive ? 2 : 1).toString() +'px solid',
		display: 'inline-block',
		height: 6,
		width: 25,
		verticalAlign: 'middle'
	};

	return (
		<li
			key={label}
			className={`list-group-item outline ${activeLabelClassName}`}
			onMouseOver={(e) => setActiveLabel(e, label)}
			onMouseOut={(e) => setActiveLabel(e, '')}>
			 {label} (n={curves.length})

	);
}

var Legend = React.createClass({
	propTypes: {
		activeLabel: PropTypes.string,
		columns: PropTypes.number,
		groups: PropTypes.object,
		setActiveLabel: PropTypes.func
	},

	render: function () {
		let { groups, setActiveLabel, activeLabel } = this.props;
		let { colors, curves, labels } = groups;
		let sets = _.zip(colors, curves, labels)
					.map((set, index) => makeLegendKey(set, setActiveLabel, activeLabel));

		return (
			<ListGroup className="legend">{sets}</ListGroup>
		);
	}
});

function makeGraph(groups, setActiveLabel, activeLabel, size) {
	return (

			{svg(groups, setActiveLabel, activeLabel, size)}

	);
}

function makeDefinitions(groups, setActiveLabel, activeLabel, size) {
	// get new size based on size ratio for definitions column

	return (

			<PValue pValue={groups.pValue} logRank={groups.KM_stats}/>
			<Legend groups={groups}
					setActiveLabel={setActiveLabel}
					activeLabel={activeLabel} />

	);
}

var KmPlot = React.createClass({
	mixins: [deepPureRenderMixin],
	propTypes: {
		eventClose: PropTypes.string,
		dims: PropTypes.object
	},
	size: {
		ratios: {
			graph: {
				width: 0.75,
				height: 1.0
			},
			definitions: {
				width: 0.25,
				height: 1.0
			}
		}
	},

	getDefaultProps: () => ({
		eventClose: 'km-close',
		dims: {
			height: 450,
			width: 860
		}
	}),

	getInitialState: function() {
		return { activeLabel: '' }
	},

	hide: function () {
		let {callback, eventClose} = this.props;
		callback([eventClose]);
	},

	setActiveLabel: function (e, label) {
		this.setState({ activeLabel: label });
	},

	render: function () {
		let { km: {title, label, groups}, dims } = this.props,
			warning = _.get(groups, 'warning'),
			fullLabel = warning ? `${label} (${warning})` : label,
			{ activeLabel } = this.state,
			sectionDims = calcDims(dims, this.size.ratios);
		// XXX Use bootstrap to lay this out, instead of tables + divs
		let Content = _.isEmpty(groups)
			?

Loading...

			:

				{makeGraph(groups, this.setActiveLabel, activeLabel, sectionDims.graph)}
				{makeDefinitions(groups, this.setActiveLabel, activeLabel, sectionDims.definitions)}

;

		return (
			<Modal show={true} bsSize='large' className='kmDialog' onHide={this.hide} ref="kmPlot">
				<Modal.Header closeButton className="container-fluid">

						<Modal.Title>Kaplan Meier</Modal.Title>

					{title}
				</Modal.Header>
				<Modal.Body className="container-fluid">
					{Content}
				</Modal.Body>
				<Modal.Footer className="container-fluid">
					<samp className='featureLabel'>{fullLabel}</samp>
				</Modal.Footer>
			</Modal>
		);
	}
});

module.exports = KmPlot;
<|endoftext|>


<commit_before>let mod = new ActionObj('FromContainer');
module.exports = mod;

const targetInitFunc = function(creep) {
    const need = creep.carryCapacity - creep.carry.energy;
    const role = creep.memory.role;
    const room = creep.room;
    if(role === C.UPGRADER) {
        if(room.controller.container && room.controller.container.store[RESOURCE_ENERGY]>need) {
            return room.controller.container;
        } else {
            return false;
        }
    }
    //Find source container
    let suitableContainer = false;;
    for(let source of room.sources) {
        const container = source.container || false;
        if(container) {
            if(!suitableContainer || container.store[RESOURCE_ENERGY] > suitableContainer.store[RESOURCE_ENERGY]) suitableContainer = container;
        }
    }
    if(suitableContainer && suitableContainer.store[RESOURCE_ENERGY]>0) return suitableContainer;

    //Find mineral container
    if(role === C.HAULER || role === C.REMOTE_HAULER) {
        const mineral = room.mineral;
        if(mineral && mineral.container && _.sum(mineral.container.store)>=need) {
            return mineral.container;
        }
    }

    return false;
};

mod.nextTarget = function() {
    return Util.Mark.handleMark(this.creep, targetInitFunc, this.actionName, validateFunc);
};

const validateFunc = function(creep, target) {
    return target.room && target.room.name===creep.room.name && _.sum(target.store) > 0;
};

mod.word = '⬅Container';

mod.loop = function(creep) {
    return this.loop0(creep, (creep, target) => {
        let result = OK;
        if(creep.memory.role===C.HAULER || creep.memory.role===C.REMOTE_HAULER) {
            //Only haulers are allowed to get resources other than energy
            for(const resourceType in target.store) {
                result = creep.withdraw(target, resourceType);
            }
        } else {
            result = creep.withdraw(target, RESOURCE_ENERGY);
        }
        if(result === ERR_NOT_IN_RANGE) {
            creep.moveTo(target, {range: 1, maxRooms: 1, visualizePathStyle: {stroke: '#ffaa00'}});
        } else if(result === OK) {
            Util.Mark.unmarkTarget(creep, this.actionName);
        }
    });
};
<commit_msg>hauler prefer mineral container; only go and withdraw from container which contains enough resources<commit_after>let mod = new ActionObj('FromContainer');
module.exports = mod;

const targetInitFunc = function(creep) {
    const need = creep.carryCapacity - _.sum(creep.carry);
    const role = creep.memory.role;
    const room = creep.room;
    if(role === C.UPGRADER) {
        if(room.controller.container && room.controller.container.store[RESOURCE_ENERGY]>need) {
            return room.controller.container;
        } else {
            return false;
        }
    }

    //Find mineral container
    if(role === C.HAULER || role === C.REMOTE_HAULER) {
        const mineral = room.mineral;
        if(mineral && mineral.container && _.sum(mineral.container.store)>=need) {
            return mineral.container;
        }
    }

    //Find source container
    let suitableContainer = false;;
    for(let source of room.sources) {
        const container = source.container || false;
        if(container) {
            if(!suitableContainer || container.store[RESOURCE_ENERGY] > suitableContainer.store[RESOURCE_ENERGY]) suitableContainer = container;
        }
    }
    if(suitableContainer && suitableContainer.store[RESOURCE_ENERGY]>need) return suitableContainer;

    return false;
};

mod.nextTarget = function() {
    return Util.Mark.handleMark(this.creep, targetInitFunc, this.actionName, validateFunc);
};

const validateFunc = function(creep, target) {
    const need = creep.carryCapacity - _.sum(creep.carry);
    return target.room && target.room.name===creep.room.name && _.sum(target.store) > need;
};

mod.word = '⬅Container';

mod.loop = function(creep) {
    return this.loop0(creep, (creep, target) => {
        let result = OK;
        if(creep.memory.role===C.HAULER || creep.memory.role===C.REMOTE_HAULER) {
            //Only haulers are allowed to get resources other than energy
            for(const resourceType in target.store) {
                result = creep.withdraw(target, resourceType);
            }
        } else {
            result = creep.withdraw(target, RESOURCE_ENERGY);
        }
        if(result === ERR_NOT_IN_RANGE) {
            creep.moveTo(target, {range: 1, maxRooms: 1, visualizePathStyle: {stroke: '#ffaa00'}});
        } else if(result === OK) {
            Util.Mark.unmarkTarget(creep, this.actionName);
        }
    });
};
<|endoftext|>