<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Dan "Ducky" Little
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

import React, {Component, PropTypes } from 'react';

import { connect } from 'react-redux';

import { removeQuery, createQuery, changeTool, renderedResultsForQuery} from '../actions/map';

import { startService, finishService } from '../actions/service';

import * as util from '../util';

import * as uuid from 'uuid';

import * as mapActions from '../actions/map';

import { getLayerFromPath } from '../actions/mapSource';

import { setUiHint } from '../actions/ui';


import Mark from 'markup-js';

import DrawTool from './drawTool';

import TextInput from './serviceInputs/text';
import SelectInput from './serviceInputs/select';
import LengthInput from './serviceInputs/length';

import MeasureTool from './measure';

class ServiceManager extends Component {

    constructor() {
        super();
        this.services = {};

        this.finishedQueries = {};

        this.startQuery = this.startQuery.bind(this); 
        this.drawTool = this.drawTool.bind(this); 
        this.renderQuery = this.renderQuery.bind(this); 
        this.renderQueryResults = this.renderQueryResults.bind(this); 
        this.onServiceFieldChange = this.onServiceFieldChange.bind(this);

        this.state = {
            lastService: null,
            lastFeature: ''
        };

        this.fieldValues = {};
    }

    registerService(name, service) {

        this.services[name] = service;
    }

    /* Normalizes the selectionFeatures from the map
     * for use with a service.
     *
     */
    normalizeSelection(selectionFeatures) {
        // OpenLayers handles MultiPoint geometries in an awkward way,
        // each feature is a 'MultiPoint' type but only contains one feature,
        //  this normalizes that in order to be submitted properly to query services.
        if(selectionFeatures.length > 0) {
            if(selectionFeatures[0].geometry.type === 'MultiPoint') {
                const all_coords = [];
                for(let feature of selectionFeatures) {
                    if(feature.geometry.type === 'MultiPoint') {
                        all_coords.push(feature.geometry.coordinates[0]);
                    }
                }
                return {
                    type: 'Feature',
                    properties: {},
                    geometry: {
                        type: 'MultiPoint',
                        coordinates: all_coords
                    }
                };
            }
        }
        return selectionFeatures[0];
    }

    /** Call the service with the relevant information
     *  and have it start a query.
     *
     */
    startQuery(service) {
        if(this.props.services[service]) {
            let service_def = this.props.services[service];
            let selection = this.normalizeSelection(this.props.store.getState().map.selectionFeatures);
            let fields = [];

            for(let name in this.fieldValues[service]) {
                fields.push({name: name, value: this.fieldValues[service][name]});
            }

            // check to see if the selection should stay 
            //  'alive' in the background.
            if(service_def.keepAlive !== true) {
                // shutdown the drawing on the layer.
                this.drawTool(null);
            }

            this.closeForm();
            this.props.services[service].query(selection, fields);
        } else {
            console.info('Failed to start query, service: ' + service + ' not found.');
        }

    }


    /** Renders the results for an individual query.
     *
     *  @param queryId the query's ID.
     *  @param query   The details of the query.
     *
     *  @returns a Hash appropriate for dnagerouslySetInnerHTML
     */
    renderQueryResults(queryId, query) {
        var html_contents = ''; 

        if(query.progress === 'finished' && this.props.services[query.service]) {
            let service = this.props.services[query.service];
            if(service.renderQueryResults) {
                service.renderQueryResults(queryId, query);
            }
            if(service.resultsAsHtml) {
                html_contents = service.resultsAsHtml(queryId, query);
            }
        }

        return {__html: html_contents};
    }

    removeQuery(queryId) {
        this.props.store.dispatch(removeQuery(queryId));
    }


    /** Render queries as they are coming in.
     *
     *  @param queryId
     *
     */
    renderQuery(queryId) {
        let query = this.props.queries[queryId];
        let service_title = this.props.services[query.service].resultsTitle;

        // this is a little ungangly but it will help those who
        //  forget to specify a results title.<commit_msg>add spinny icon<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Dan "Ducky" Little
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

import React, {Component, PropTypes } from 'react';

import { connect } from 'react-redux';

import { removeQuery, createQuery, changeTool, renderedResultsForQuery} from '../actions/map';

import { startService, finishService } from '../actions/service';

import * as util from '../util';

import * as uuid from 'uuid';

import * as mapActions from '../actions/map';

import { getLayerFromPath } from '../actions/mapSource';

import { setUiHint } from '../actions/ui';


import Mark from 'markup-js';

import DrawTool from './drawTool';

import TextInput from './serviceInputs/text';
import SelectInput from './serviceInputs/select';
import LengthInput from './serviceInputs/length';

import MeasureTool from './measure';

class ServiceManager extends Component {

    constructor() {
        super();
        this.services = {};

        this.finishedQueries = {};

        this.startQuery = this.startQuery.bind(this); 
        this.drawTool = this.drawTool.bind(this); 
        this.renderQuery = this.renderQuery.bind(this); 
        this.renderQueryResults = this.renderQueryResults.bind(this); 
        this.onServiceFieldChange = this.onServiceFieldChange.bind(this);

        this.state = {
            lastService: null,
            lastFeature: ''
        };

        this.fieldValues = {};
    }

    registerService(name, service) {

        this.services[name] = service;
    }

    /* Normalizes the selectionFeatures from the map
     * for use with a service.
     *
     */
    normalizeSelection(selectionFeatures) {
        // OpenLayers handles MultiPoint geometries in an awkward way,
        // each feature is a 'MultiPoint' type but only contains one feature,
        //  this normalizes that in order to be submitted properly to query services.
        if(selectionFeatures.length > 0) {
            if(selectionFeatures[0].geometry.type === 'MultiPoint') {
                const all_coords = [];
                for(let feature of selectionFeatures) {
                    if(feature.geometry.type === 'MultiPoint') {
                        all_coords.push(feature.geometry.coordinates[0]);
                    }
                }
                return {
                    type: 'Feature',
                    properties: {},
                    geometry: {
                        type: 'MultiPoint',
                        coordinates: all_coords
                    }
                };
            }
        }
        return selectionFeatures[0];
    }

    /** Call the service with the relevant information
     *  and have it start a query.
     *
     */
    startQuery(service) {
        if(this.props.services[service]) {
            let service_def = this.props.services[service];
            let selection = this.normalizeSelection(this.props.store.getState().map.selectionFeatures);
            let fields = [];

            for(let name in this.fieldValues[service]) {
                fields.push({name: name, value: this.fieldValues[service][name]});
            }

            // check to see if the selection should stay 
            //  'alive' in the background.
            if(service_def.keepAlive !== true) {
                // shutdown the drawing on the layer.
                this.drawTool(null);
            }

            this.closeForm();
            this.props.services[service].query(selection, fields);
        } else {
            console.info('Failed to start query, service: ' + service + ' not found.');
        }

    }


    /** Renders the results for an individual query.
     *
     *  @param queryId the query's ID.
     *  @param query   The details of the query.
     *
     *  @returns a Hash appropriate for dnagerouslySetInnerHTML
     */
    renderQueryResults(queryId, query) {
        var html_contents = ''; 

        if(query.progress === 'finished' && this.props.services[query.service]) {
            let service = this.props.services[query.service];
            if(service.renderQueryResults) {
                service.renderQueryResults(queryId, query);
            }
            if(service.resultsAsHtml) {
                html_contents = service.resultsAsHtml(queryId, query);
            }
        } else {
            html_contents = "<i class='fa fa-spin fa-refresh'></i>";
        }

        return {__html: html_contents};
    }

    removeQuery(queryId) {
        this.props.store.dispatch(removeQuery(queryId));
    }


    /** Render queries as they are coming in.
     *
     *  @param queryId
     *
     */
    renderQuery(queryId) {
        let query = this.props.queries[queryId];
        let service_title = this.props.services[query.service].resultsTitle;

        // this is a little ungangly but it will help those who
        //  forget to specify a results title.
{'fraction_non_alphanumeric': 0.09812214515310438, 'fraction_numerical': 0.002030113347995263, 'mean_word_length': 2.191093117408907, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2349580', 'n_tokens_mistral': 3091, 'n_tokens_neox': 2954, 'n_words': 967}