Source: seeq.js

/*
 * seeq
 * https://github.com/gamtiq/seeq
 *
 * Copyright (c) 2014 Denis Sikuler
 * Licensed under the MIT license.
 */


/**
 * Detect whether a name is registered or present on some resource, or make search for string on specified resources.
 * 
 * @module seeq
 */


"use strict";

var mixing = require("mixing"),
    resourceLib = require("./resource"),
    resourceUtil = require("./resource/util");


function getCheckNameCallback(resource, position, callback) {
    return function(err, result) {
        callback(err, result, resource, position);
    };
}

/**
 * Check existence of name or search for given string on specified resources.
 * 
 * Result of checking/searching will be passed into callback as object.
 * Each field of the object is name of resource that was checked/searched.
 * Value of result's field is object with the following fields (name - type - description):
   <ul>
   <li><code>name</code> - <code>String</code> - resource name
   <li><code>description</code> - <code>String</code> - resource description
   <li><code>url</code> - <code>String</code> - URL of resource
   <li><code>query</code> - <code>String</code> - name/string that was checked/searched
   <li><code>result</code> - <code>Array</code> - result that was received from resource; 
           each item in the array is object that represents data about found element
   <li><code>error</code> - <code>Object | String</code> - error that was got while checking resource;
           this field is present only when there was an error
   </ul>
 * 
 * <code>null</code> will be passed into callback when the name is not given or resources with specified names are not found.
 * 
 * @param {String} name
 *      The name that should be checked/searched.
 * @param {Function} callback
 *      Function that should be called to process operation's result.
 * @param {Object} [settings]
 *      Operation settings. The following settings are supported (name - type - description):
        <ul>
        <li><code>progressCallback</code> - <code>Function</code> - function that should be called after getting result
                from each resource; object with the following fields will be passed into callback:
                <ul>
                <li><code>name</code> - <code>String</code> - name that was checked/searched
                <li><code>resource</code> - <code>String</code> - resource that was checked
                <li><code>result</code> - <code>Object</code> - result of checking/searching (see above)
                <li><code>number</code> - <code>Integer</code> - index number of checking/searching
                <li><code>total</code> - <code>Integer</code> - total number of checks/searches
                <li><code>error</code> - <code>Object | String</code> - error that was got while checking/searching resource;
                       this field is present only when there was an error
                </ul>
        <li><code>resource</code> - <code>Array | String</code> - specifies filter for available resources by name;
                list of names of resources or name of resource (case-insensitive) that should be checked/searched
        <li><code>resourceTag</code> - <code>Array | String</code> - specifies filter for available resources by tag;
                list of tags or tag (case-insensitive) that should be used to select resources;
                resources that satisfy to specified tags (depending on <code>checkAllTags</code> setting)
                will be checked/searched; see {@link module:resource.checkResourceTags checkResourceTags} for details
        <li><code>checkAllTags</code> - <code>Boolean</code> - whether all tags specified in <code>resourceTag</code>
                should be used to select resources; see {@link module:resource.checkResourceTags checkResourceTags} for details
        <li><code>search</code> - <code>Boolean</code> - whether search should be made instead of check;
                it is used only when <code>search</code> setting for a resource is not specified (see below)
        <li><code>settings</code> - <code>Object</code> - settings for resources usage;
                fields are resource identifiers, values are objects representing settings for the corresponding resources;
                value of <code>_general</code> field can be used to specify settings that should be applied to all resources
        </ul>
        Filter by name (<code>resource</code>) and filter by tag (<code>resourceTag</code>)
        can be used separately or together.
        If no filter is specified, all resources will be checked/searched.
 * @alias module:seeq.searchName
 */
function searchName(name, callback, settings) {
    /*jshint laxbreak:true*/
    
    // Gather results from resources
    function resultCallback(err, result, resource, position) {
        /*jshint boss:true*/
        var sResourceName = resource.name,
            data, item, nI, nK, resultMap;
        nC--;
        item = resultList[position] = {
            name: sResourceName,
            description: resource.description,
            url: resource.url,
            query: name,
            result: result
        };
        if (err) {
            item.error = err;
        }
        if (settings.progressCallback) {
            data = {
                name: name,
                resource: sResourceName,
                result: item,
                number: nTotal - nC,
                total: nTotal
            };
            if (err) {
                data.error = err;
            }
            settings.progressCallback(data);
        }
        if (nC === 0) {
            // Form result
            resultMap = {};
            for (nI = 0, nK = resultList.length; nI < nK; nI++) {
                if (resource = resultList[nI]) {
                    resultMap[resource.name] = resource;
                }
            }
            callback(resultMap);
        }
    }
    
    var resultList = [],
        api, generalSettings, nC, nI, nTotal, realSettings, resource, resourceList, resourceSettings;
    if (! settings) {
        settings = {};
    }
    resourceSettings = settings.settings || {};
    generalSettings = resourceSettings._general;
    resourceList = resourceLib.getList({
                                        selectName: settings.resource, 
                                        selectTag: settings.resourceTag,
                                        checkAllTags: settings.checkAllTags,
                                        includeApi: true
                                        });
    if (name && (nC = resourceList.length)) {
        // Request data from resources
        for (nI = 0, nTotal = nC; nI < nTotal; nI++) {
            resource = resourceList[nI];
            realSettings = generalSettings 
                            ? mixing({}, [resourceSettings[resource.id], generalSettings]) 
                            : (resourceSettings[resource.id] || {});
            if (! ("search" in realSettings) && ("search" in settings)) {
                realSettings.search = settings.search;
            }
            api = resource.api;
            api[resourceUtil.isRealSearchSet(realSettings) && typeof api.search === "function" ? "search" : "detect"]
                (name, 
                 getCheckNameCallback(resource, nI, resultCallback), 
                 realSettings);
        }
    }
    else {
        callback(null);
    }
}


/**
 * Check existence of each name from the list on specified resources
 * or search for each string  on specified resources.
 * 
 * Result of checking/searching will be passed into callback as object.
 * Each field of the object is a name that was checked/searched.
 * Value of result's field is object that is returned by {@link module:seeq.searchName searchName} function.
 * 
 * <code>null</code> will be passed into callback when no name is specified to check/search.
 * 
 * @param {Array | String} names
 *      The list of names or a name that should be checked/searched.
 * @param {Function} callback
 *      Function that should be called to process operation's result.
 * @param {Object} [settings]
 *      Operation settings. See {@link module:seeq.searchName searchName} for details.
 * @alias module:seeq.search
 */
function search(names, callback, settings) {
    /*jshint boss:true*/
    
    // Notify about operation progress
    function searchNameProgress(data) {
        data.number += data.total * nI;
        data.total *= nK;
        progressCallback(data);
    }
    
    // Gather results for each name
    function resultCallback(result) {
        resultMap[ names[nI] ] = result;
        nI++;
        if (nI < nK) {
            // Get results for the next name
            searchName(names[nI], resultCallback, settings);
        }
        else {
            // Return collected data
            callback(resultMap);
        }
    }
    
    var progressCallback = settings && settings.progressCallback,
        resultMap = {},
        nI, nK;
    
    if (names && typeof names === "string") {
        names = [names];
    }
    if (names && (nK = names.length)) {
        if (progressCallback) {
            settings = mixing({progressCallback: searchNameProgress}, settings, {except: "progressCallback"});
        }
        // Get results for the first name
        searchName(names[nI = 0], resultCallback, settings);
    }
    else {
        callback(null);
    }
}


// Exports

exports.search = search;
exports.searchName = searchName;

/**
 * Reference to {@link module:resource resource} module.
 */
exports.resource = resourceLib;
/**
 * Reference to {@link module:format format} module.
 */
exports.format = require("./format");
Copyright (c) 2014 Denis Sikuler
Documentation generated by JSDoc 3.2.2 on Sun Jul 13 2014 23:52:09 GMT+0400 (MSK) using the DocStrap template.