<commit_before>/*
 *  Copyright (c) 2012, 2013 Jochen S. Klar <jklar@aip.de>,
 *                           Adrian M. Partl <apartl@aip.de>,
 *                           AIP E-Science (www.aip.de)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  See the NOTICE file distributed with this work for additional
 *  information regarding copyright ownership. You may obtain a copy
 *  of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

// daiquiri namespace
var daiquiri = daiquiri || {};
daiquiri.common = {};

/**
 * Starts the polling by calling the emit poll function for the first time.
 */
daiquiri.common.startPoll = function(timeout) {
    daiquiri.common.poll = daiquiri.common.emitPoll(timeout);
}

/**
 * Emits the 'poll' signal periodically, specified by timeout.
 */
daiquiri.common.emitPoll = function(timeout) {
    daiquiri.common.poll = setTimeout('daiquiri.common.emitPoll('+ timeout +');', timeout);
    $(window).trigger('poll');
}

/**
 * Displays the form errors next to the corresponding fields
 */
daiquiri.common.showFormErrors = function(form, errors) {
    // remove old errors
    $('.daiquiri-form-error').remove();

    // loop over new errors and append after corresponding fields
    $.each(errors, function(field, errors) {
        var e;
        var classes = 'daiquiri-form-error unstyled text-error';
        if (field == 'form' || /^.*csrf$/.test(field)) {
            e = $(form);
        } else {
            e = $('#' + field);
            if (e.parents('fieldset').hasClass('daiquiri-form-horizontal-group')) {
                classes += ' help-inline';
            }
        }

        var html = '
';
        $.each(errors, function (key, value) {
            html += '
' + value + '
';
        });
        html += '
';
        e.after(html);
    });
}

/**
 * Updated the csrf token of a given form
 */
daiquiri.common.updateCsrf = function(form, csrf) {
    if (csrf != undefined) {
        $('.daiquiri-csrf', $(form)).attr('value', csrf);
    } else {
        console.log('Error: No new csrf was provided!');
    }
}

/**
 * Displays errors with ajax calls.
 */
daiquiri.common.ajaxError = function(jqXHR, textStatus, errorThrown) {
    clearTimeout(daiquiri.common.poll);
    daiquiri.common.modal = new daiquiri.Modal({
        'label': 'Ajax Error',
        'body': '
An error occured while connectiong to the server.

The corresponding HTTP status is "' + jqXHR.statusText + '" (' + jqXHR.status + ').
',
        'primary': 'Reload page',
        'success': function () {
            $('#daiquiri-modal-primary').click(function () {
                var location = window.location.href.split('#')[0]
                window.location.replace(location);
            })
        }
    });
    setTimeout('daiquiri.common.modal.show();', 1000);
};

/**
 * Displays other ajax related errors (when json.status != 'ok').
 */
daiquiri.common.jsonError = function(json) {
    //alert('Error with ajax request. (Status: ' + json.status + ').');
    console.log(json);
};
<commit_msg>ajax error fixed<commit_after>/*
 *  Copyright (c) 2012, 2013 Jochen S. Klar <jklar@aip.de>,
 *                           Adrian M. Partl <apartl@aip.de>,
 *                           AIP E-Science (www.aip.de)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  See the NOTICE file distributed with this work for additional
 *  information regarding copyright ownership. You may obtain a copy
 *  of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

// daiquiri namespace
var daiquiri = daiquiri || {};
daiquiri.common = {};

/**
 * Starts the polling by calling the emit poll function for the first time.
 */
daiquiri.common.startPoll = function(timeout) {
    daiquiri.common.poll = daiquiri.common.emitPoll(timeout);
}

/**
 * Emits the 'poll' signal periodically, specified by timeout.
 */
daiquiri.common.emitPoll = function(timeout) {
    daiquiri.common.poll = setTimeout('daiquiri.common.emitPoll('+ timeout +');', timeout);
    $(window).trigger('poll');
}

/**
 * Displays the form errors next to the corresponding fields
 */
daiquiri.common.showFormErrors = function(form, errors) {
    // remove old errors
    $('.daiquiri-form-error').remove();

    // loop over new errors and append after corresponding fields
    $.each(errors, function(field, errors) {
        var e;
        var classes = 'daiquiri-form-error unstyled text-error';
        if (field == 'form' || /^.*csrf$/.test(field)) {
            e = $(form);
        } else {
            e = $('#' + field);
            if (e.parents('fieldset').hasClass('daiquiri-form-horizontal-group')) {
                classes += ' help-inline';
            }
        }

        var html = '
';
        $.each(errors, function (key, value) {
            html += '
' + value + '
';
        });
        html += '
';
        e.after(html);
    });
}

/**
 * Updated the csrf token of a given form
 */
daiquiri.common.updateCsrf = function(form, csrf) {
    if (csrf != undefined) {
        $('.daiquiri-csrf', $(form)).attr('value', csrf);
    } else {
        console.log('Error: No new csrf was provided!');
    }
}

/**
 * Displays errors with ajax calls.
 */
daiquiri.common.ajaxError = function(jqXHR, textStatus, errorThrown) {
    if (typeof daiquiri.common.poll == 'undefined') {
        console.log('Ajax error: ' + jqXHR.statusText + '" (' + jqXHR.status + ')');
    } else {
        clearTimeout(daiquiri.common.poll);

        if (jqXHR.status == 403) {
            var label = 'Session expired';
            var body = '
Your session is expired. Please log in again.
';
            var primary = 'Login';
        } else {
            var label = 'Ajax Error';
            var body = '
An error occured while connecting to the server.

The corresponding HTTP status is "' + jqXHR.statusText + '" (' + jqXHR.status + ').
';
            var primary = 'Reload page';
        }

        var modal = new daiquiri.Modal({
            'label': label,
            'body': body,
            'primary': primary,
            'success': function () {
                $('#daiquiri-modal-primary').click(function () {
                    window.location.replace(window.location.pathname);
                })
            }
        });
        modal.show();
    }
};

/**
 * Displays other ajax related errors (when json.status != 'ok').
 */
daiquiri.common.jsonError = function(json) {
    //alert('Error with ajax request. (Status: ' + json.status + ').');
    console.log(json);
};
<|endoftext|>


<commit_before>AutoForm.hooks({
	editContent: {
		onSuccess: function(updateDoc, result) {
			var newsletterValue = _.uniq(Contents.find({}, {
		    sort: {newsletter: 1}, fields: {newsletter: true}
		  }).fetch().map(function(x) {
		    return x.newsletter;
		  }), true);
			console.log(newsletterValue);

			if (newsletterValue[0] === true) {
				Session.set('newsletter', true);
			} else {
				Session.set('newsletter', false);
		  }

			Router.go('home');
			FlashMessages.sendSuccess('Content updated');
		},
			onSuccess: function(updateDoc, result) {
				var overlayValue = _.uniq(Contents.find({}, {
					sort: {overlay: 1}, fields: {overlay: true}
				}).fetch().map(function(x) {
					return x.overlay;
					}), true);
					console.log(overlayValue);

				if (overlayValue[0] === true) {
						Session.set('overlay', true);
					} else {
						Session.set('overlay', false);
					}

				Router.go('home');
				FlashMessages.sendSuccess('Content updated');
			}
		}
  });
<commit_msg>storing value of overlayTimeout<commit_after>AutoForm.hooks({
	editContent: {
		onSuccess: function(updateDoc, result) {
			var newsletterValue = _.uniq(Contents.find({}, {
		    sort: {newsletter: 1}, fields: {newsletter: true}
		  }).fetch().map(function(x) {
		    return x.newsletter;
		  }), true);
			console.log(newsletterValue);

			if (newsletterValue[0] === true) {
				Session.set('newsletter', true);
			} else {
				Session.set('newsletter', false);
		  }

			Router.go('home');
			FlashMessages.sendSuccess('Content updated');
		},
			onSuccess: function(updateDoc, result) {
				var overlayValue = _.uniq(Contents.find({}, {
					sort: {overlay: 1}, fields: {overlay: true}
				}).fetch().map(function(x) {
					return x.overlay;
					}), true);
					console.log(overlayValue);

				if (overlayValue[0] === true) {
						Session.set('overlay', true);
					} else {
						Session.set('overlay', false);
					}

				Router.go('home');
				FlashMessages.sendSuccess('Content updated');
			},
			onSuccess: function(updateDoc, result) {
				var overlayTimeoutValue = _.uniq(Contents.find({}, {
					sort: {overlayTimeout: 1}, fields: {overlayTimeout: true}
				}).fetch().map(function(x) {
					return x.overlayTimeout;
					}), true);
					console.log(overlayTimeoutValue);

				if (overlayTimeoutValue[0] === true) {
						// Session.set('overlay', true);
					} else {
						// Session.set('overlay', false);
					}

				Router.go('home');
				FlashMessages.sendSuccess('Content updated');
			}
		}
  });
<|endoftext|>


<commit_before>var fs = require('fs'),
    gju = require('geojson-utils'),
    key = require('./lib/key.js'),
    levelup = require('levelup'),
    wellknown = require('wellknown');

// adjusts skipvals based on geometry, prioritizing particular areas/markets

if (process.stdin.isTTY) {
    var quickMode = true; // should we bother matching against every geometry or just quit after one hit?

    if (process.argv.length < 4) {
        return console.log('file arguments are required\n`node prioritize.js [leveldb] [geojson1 geojson2 .. ]`');
    }

    // process command line params, load geojson files
    var geojson = [];
    process.argv
        .forEach(function(elem, i) {
            if (i <= 2) {
                // skip require params -- choosing not to use .filter() to make async logic simpler below
                return true;
            }

            // if using overlapping geojson files, this flag might be useful. otherwise, no.
            if (elem === '--slow') {
                quickMode = false;
            }
            else {
                fs.readFile(elem, function(err, data) {
                    if (err) console.log('# Error loading GeoJSON file ' + elem);
                    var boundary = JSON.parse(data);
                    if((boundary===null) || (!boundary.features)) {
                        console.log('# failed to load valid GeoJSON from ' + elem);
                    }
                    else {
                        geojson.push(boundary);
                        console.log('- loaded GeoJSON file ' + elem);
                    }

                    // if all params have been loaded, begin main processing
                    if(i === process.argv.length-1) ProcessLevelDB();
                });
            }
        });
}

function ProcessLevelDB(){
    console.log('- opening leveldb database ' + process.argv[2]);
    levelup(process.argv[2], function(err, db) {
        if (err) throw(err);

        var maxOverlaps = 0;
        console.log('- checking for geometry overlap')
        db.createReadStream()
            .on('data', function(data) {
                data.value = JSON.parse(data.value);

                // if this task is already fixed, skip it
                if (key.decompose(data.key).skipval === 0) return;

                // check if point is in any geojson geometries
                var overlaps = 0;
                geojson.forEach(function(poly) {
                    if (!data.value.st_astext) {
                        console.log('# missing geometry (st_astext) for key ' + data.key);
                        return false;
                    }

                    if( gju.pointInPolygon(wellknown.parse(data.value.st_astext), poly.features[0].geometry)) {
                        overlaps++;
                        if (quickMode) return false;
                    }
                });

                // track maximum number of overlaps
                maxOverlaps = Math.max(maxOverlaps, overlaps);

                data.value.overlaps = overlaps;
                db.put(data.key, JSON.stringify(data.value), function(err) {
                    if (err) console.log('# error saving key ' + data.key + '#' + overlaps);
                });
            })
            .on('end', function(){

                // iterate through all keys, adding (maxOverlaps - overlap) to each skipval
                console.log('- reordering tasks')
                var adjustmentsMade = 0;

                db.createReadStream()
                    .on('data', function(data) {
                        data.value = JSON.parse(data.value);

                        var keyComponents = key.decompose(data.key);
                        var newKey = key.compose((keyComponents.skipval + (maxOverlaps - parseInt(data.value.overlaps))), keyComponents.hash);

                        if (parseInt(data.value.overlaps) > 0) {
                            adjustmentsMade++;
                        }

                        delete data.value.overlaps;
                        db.put(newKey, JSON.stringify(data.value), function(err) {
                            if (err) console.log('# error saving key ' + newKey);
                        });

                    })
                    .on('end', function() {
                        console.log('- finished, reprioritized ' + adjustmentsMade + ' tasks')
                    });
            });

    });
}<commit_msg>delete old keys (bug); keep track of which geojson prioritized a given record (feature)<commit_after>var fs = require('fs'),
    gju = require('geojson-utils'),
    key = require('./lib/key.js'),
    levelup = require('levelup'),
    wellknown = require('wellknown');

// adjusts skipvals based on geometry, prioritizing particular areas/markets

if (process.stdin.isTTY) {
    var quickMode = true; // should we bother matching against every geometry or just quit after one hit?

    if (process.argv.length < 4) {
        return console.log('file arguments are required\n`node prioritize.js [task] [geojson1 geojson2 ... ]`');
    }

    // process command line params, load geojson files
    var geojson = {};
    process.argv
        .forEach(function(elem, i) {
            if (i <= 2) {
                // skip require params -- choosing not to use .filter() to make async logic simpler below
                return true;
            }

            // if using overlapping geojson files, this flag might be useful. otherwise, no.
            if (elem === '--slow') {
                quickMode = false;
            }
            else {
                var basename = elem.replace(/\.geojson/, '').replace(/^.*\//, '');

                fs.readFile(elem, function(err, data) {
                    if (err) console.log('# Error loading GeoJSON file ' + elem);
                    var boundary = JSON.parse(data);
                    if((boundary===null) || (!boundary.features)) {
                        console.log('# failed to load valid GeoJSON from ' + elem);
                    }
                    else {
                        geojson[basename] = boundary;
                        console.log('- loaded GeoJSON file ' + elem);
                    }

                    // if all params have been loaded, begin main processing
                    if(i === process.argv.length-1) ProcessLevelDB();
                });
            }
        });
}

function ProcessLevelDB(){
    console.log('- opening leveldb database ' + process.argv[2]);
    levelup('./ldb/' + process.argv[2] + '.ldb', function(err, db) {
        if (err) throw(err);

        var maxOverlaps = 0;
        console.log('- checking for geometry overlap')
        db.createReadStream()
            .on('data', function(data) {
                data.value = JSON.parse(data.value);

                // if this task is already fixed, skip it
                if (key.decompose(data.key).skipval === 0) return;

                // check if point is in any geojson geometries
                var overlapCount = 0;
                Object.keys(geojson).forEach(function(k) {
                    if (!data.value.st_astext) {
                        console.log('# missing geometry (st_astext) for key ' + data.key);
                        return false;
                    }

                    if( gju.pointInPolygon(wellknown.parse(data.value.st_astext), geojson[k].features[0].geometry)) {
                        if (!data.value.priority) data.value.priority = [];
                        data.value.priority.push(k);
                        overlapCount++;
                        if (quickMode) return false;
                    }
                });

                // track maximum number of overlaps
                maxOverlaps = Math.max(maxOverlaps, overlapCount);

                data.value.overlapCount = overlapCount;
                db.put(data.key, JSON.stringify(data.value), function(err) {
                    if (err) console.log('# error saving key ' + data.key + '#' + overlapCount);
                });
            })
            .on('end', function(){

                // iterate through all keys, adding (maxOverlaps - overlap) to each skipval
                console.log('- reordering tasks')
                var adjustmentsMade = 0;

                var reordered = 0;
                db.createReadStream()
                    .on('data', function(data) {
                        data.value = JSON.parse(data.value);

                        var keyComponents = key.decompose(data.key);
                        var newKey = key.compose((keyComponents.skipval + (maxOverlaps - parseInt(data.value.overlapCount))), keyComponents.hash);

                        if (parseInt(data.value.overlapCount) > 0) adjustmentsMade++;

                        delete data.value.overlapCount;
                        db.del(data.key, function(err){
                            if (err) console.log('# error deleting key ' + newKey);
                            db.put(newKey, JSON.stringify(data.value), function(err) {
                                if (err) console.log('# error saving key ' + newKey);
                                reordered++;
                            });
                        });

                    })
                    .on('end', function() {
                        console.log('- finished, reprioritized ' + adjustmentsMade + '/' + reordered + ' tasks');
                    });
            });

    });
}<|endoftext|>


<commit_before>var config = require('config');
var FeedbackModal = require('feedback-modal');
var FilterView = require('filter-view');
var HelpMeChoose = require('help-me-choose-view');
var LeafletTransitiveLayer = require('Leaflet.TransitiveLayer');
var LocationsView = require('locations-view');
var log = require('./client/log')('planner-page');
var showMapView = require('map-view');
var OptionsView = require('options-view');
var PlannerNav = require('planner-nav');
var querystring = require('querystring');
var scrollbarSize = require('scrollbar-size');
var scrolling = require('scrolling');
var session = require('session');
var textModal = require('text-modal');
//var transitive = require('transitive');
var ua = require('user-agent');
var view = require('view');
var showWelcomeWizard = require('welcome-flow');
var showPlannerWalkthrough = require('planner-walkthrough');
var geocode = require('geocode');

var FROM = config.geocode().start_address;
var TO = config.geocode().end_address;
var isMobile = window.innerWidth <= 480;
var center = config.geocode().center.split(',').map(parseFloat);

var View = view(require('./template.html'), function(view, model) {
  view.scrollable = view.find('.scrollable');
  view.panelFooter = view.find('.footer');

  if (scrollbarSize > 0) {
    if (ua.os.name === 'Windows' || ua.browser.name !== 'Chrome')
      view.scrollable.style.marginRight = -scrollbarSize + 'px';

    // Scrollbars are fun and implemented the same on every OS/Browser...right
    if (ua.os.name === 'Windows' && ua.browser.name === 'Chrome')
      view.scrollable.style.paddingRight = scrollbarSize + 'px';
  }
});

/**
 * Expose `render`
 */

module.exports = function(ctx, next) {
  log('render');

  var plan = ctx.plan;
  var query = querystring.parse(window.location.search);

  // Set up the views
  var views = {
    'filter-view': new FilterView(plan),
    'locations-view': new LocationsView(plan),
    'options-view': new OptionsView(plan),
    'planner-nav': new PlannerNav(session)
  };

  ctx.view = new View(views);
  ctx.view.on('rendered', function() {
    // Set plan to loading
    plan.loading(true);

    for (var key in views) {
      views[key].emit('rendered', views[key]);
    }

    // Show the map
    var map = showMapView(ctx.view.find('.MapView'));

    console.log("map ->", map);

    // Create the transitive layer
    //var transitiveLayer = new LeafletTransitiveLayer(transitive);

    // Set the transitive layer
    //map.addLayer(transitiveLayer);

    // Update map on plan change
    updateMapOnPlanChange(plan, map);

    //map.on('click', function (e) {
    //      var from = plan.from_ll();
    //      var to = plan.to_ll();
    //      if (!plan.coordinateIsValid(from)) {
    //        plan.journey({
    //      places: [
    //        {
    //          place_id: 'from',
    //          place_lat: e.latlng.lat,
    //          place_lon: e.latlng.lng,
    //          place_name: 'From'
    //        },
    //        {
    //          place_id: 'to',
    //          place_lat: (plan.to_ll() ? plan.to_ll().lat : 0),
    //          place_lon: (plan.to_ll() ? plan.to_ll().lng : 0),
    //          place_name: 'To'
    //        }
    //      ]
    //    });
    //    plan.setAddress('from', e.latlng.lng + ',' + e.latlng.lat, function (err, res) {
    //        plan.updateRoutes();
    //    });
    //      } else if (!plan.coordinateIsValid(to)) {
    //    plan.journey({
    //      places: [
    //        {
    //          place_id: 'from',
    //          place_lat: plan.from_ll().lat,
    //          place_lon: plan.from_ll().lng,
    //          place_name: 'From'
    //        },
    //        {
    //          place_id: 'to',
    //          place_lat: e.latlng.lat,
    //          place_lon: e.latlng.lng,
    //          place_name: 'To'
    //        }
    //      ]
    //    });
    //    plan.setAddress('to', e.latlng.lng + ',' + e.latlng.lat, function (err, res) {
    //        plan.updateRoutes();
    //    });
    //      }
    //});

    // Clear plan & cookies for now, plan will re-save automatically on save
      var from = plan.from_ll();
      var to = plan.to_ll();
      //plan.clearStore();

    // If it's a shared URL or welcome is complete skip the welcome screen
    console.log("query ->", query);
    if ((query.from && query.to)) {
      showQuery(query);
    } else {
      console.log("plan.coordinateIsValid(from)", plan.coordinateIsValid(from));
      console.log("plan.coordinateIsValid(to)", plan.coordinateIsValid(to));

      if (plan.coordinateIsValid(from) && plan.coordinateIsValid(to)) {
          plan.setAddresses(
            from.lng + ',' + from.lat, // from
            to.lng + ',' + to.lat, // to
            function (err, res) {
              plan.updateRoutes();
              console.log("aqui la data del plan 4 ->", plan.dataplan);
            }
          );
          plan.updateRoutes();
          console.log("aqui la data del plan 3 ->", plan.dataplan);
      } else {
          console.log(from);
          console.log(to);
          plan.loading(false);
      }
    }
  });

  plan.on('updating options', function() {
    ctx.view.panelFooter.classList.add('hidden');
  });

  plan.on('updating options complete', function(res) {
    if (res && !res.err) ctx.view.panelFooter.classList.remove('hidden');
  });

  next();
};

/**
 * Reverse Commute
 */

View.prototype.reverseCommute = function(e) {
  e.preventDefault();
  var plan = session.plan();
  plan.set({
    from: plan.to(),
    from_id: plan.to_id(),
    from_ll: plan.to_ll(),
    to: plan.from(),
    to_id: plan.from_id(),
    to_ll: plan.from_ll()
  });

  plan.updateRoutes();

  console.log("aqui la data del plan 5 ->", plan.dataplan);
};

/**
 * Scroll
 */

View.prototype.scroll = function(e) {
  e.preventDefault();
  this.scrollable.scrollTop += (this.scrollable.scrollHeight / 5);
};

/**
 * On submit
 */

View.prototype.onsubmit = function(e) {
  e.preventDefault();
};

/**
 * Help Me Choose
 */

View.prototype.helpMeChoose = function(e) {
  HelpMeChoose(session.plan().options()).show();
};

/**
 * Show feedback modal
 */
View.prototype.feedback = function(e) {
  e.preventDefault();
  FeedbackModal().show();
};

/**
 * Hide Side Panel
 */

View.prototype.hideSidePanel = function (e) {
  var sidePanel = $('.SidePanel');
  var fullscreen = $('.fullscreen');
  var width = sidePanel.width();
  var map = showMapView.getMap();

  sidePanel.css({
    'transition': 'transform 2s',
    '-webkit-transition': '-webkit-transform 2s',
    'transform': 'translate3d(' + width + 'px, 0, 0)'
  });

  fullscreen.css({
    'transition': 'padding 2s',
    'padding': '0'
  });

  setTimeout(function () {
    map.invalidateSize();
  }, 2100)
};

/**
 * Show Side Panel
 */

View.prototype.showSidePanel = function (e) {
  var sidePanel = $('.SidePanel');
  var fullscreen = $('.fullscreen');
  var width = sidePanel.width();
  var map = showMapView.getMap();

  sidePanel.css({
    'transition': 'transform 2s',
    '-webkit-transition': '-webkit-transform 2s',
    'transform': 'translate3d(0, 0, 0)'
  });

  fullscreen.css({
    'transition': 'padding 2s',
    'padding-right': '320px'
  });

  setTimeout(function () {
    var plan = session.plan();
    map.invalidateSize();

    plan = session.plan();
    plan.updateRoutes();
    //transitive.updateData(plan.journey());
  }, 2100)
};

/**
 * Show Journey
 */

function showQuery(query) {
  var plan = session.plan();
  // If no querystring, see if we have them in the plan already
  var from = query.from || plan.from() || FROM;
  var to = query.to || plan.to() || TO;
  var sameAddresses = from === plan.from() && to === plan.to();

  // Set plan from querystring
  if (query.modes) plan.setModes(query.modes);
  if (query.start_time !== undefined) plan.start_time(parseInt(query.start_time, 10));
  if (query.end_time !== undefined) plan.end_time(parseInt(query.end_time, 10));
  if (query.days !== undefined) plan.days(query.days);

  // If has valid coordinates, load
  if (plan.validCoordinates() && sameAddresses) {
    plan.journey({
      places: plan.generatePlaces()
    });
    plan.updateRoutes();

    console.log("aqui la data del plan 1 ->", plan.dataplan);
  } else {
      if (!plan.validCoordinates()) {
	  plan.loading(false);
	  return;
      } else {
    // Set addresses and update the routes
    plan.setAddresses(from, to, function(err) {
      if (err) {
        log.error('%e', err);
      } else {
        plan.journey({
          places: plan.generatePlaces()
        });
        plan.updateRoutes();

        console.log("aqui la data del plan 2 ->", plan.dataplan);
      }
    });
}
  }
}

/**
 * Update Map on plan change
 */

function updateMapOnPlanChange(plan, map) {
  // Register plan update events
    /*
    for (i in map._layers) {
        if (map._layers[i].options.format == undefined) {
            try {
                map.removeLayer(map._layers[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }
        }
    }
    */

    //map.removeLayer(polyline);
/*

  for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }

  }
  */

  plan.on('change journey', function(journey) {

  var polyline_creadas = showMapView.getpolyline_creadas();
    //console.log("poliline credas ->", polyline_creadas);
    //console.log("llamamos sin evento ->", showMapView.polyline_creadas);

    for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }

  }

    showMapView.polyline_creadas = [];
    if (journey && !isMobile) {
      try {

        log('updating data');

        var datajourney = journey;
        if (!(plan.dataplan === undefined)) {
            var itineraries = plan.dataplan.itineraries;
            showMapView.marker_map([plan.dataplan.from.lat,plan.dataplan.from.lon],[plan.dataplan.to.lat,plan.dataplan.to.lon], map);
            for (i = 0; i < itineraries.length; i++) {
                for (ii=0; ii < itineraries[i].legs.length; ii++) {
                  console.log("itineraries[i].legs[ii]", itineraries[i].legs[ii]);
                  var circle = [itineraries[i].legs[ii].to.lat, itineraries[i].legs[ii].to.lon, itineraries[i].legs[ii].to.name];
                  console.log("circle", circle);
                  showMapView.marker_map_point(circle, map);
                  showMapView.drawRouteAmigo(itineraries[i].legs[ii].legGeometry.points, itineraries[i].legs[ii].mode);
                }
            }
          console.log("entre if ")
        }else{
            var sesion_plan = JSON.parse(localStorage.getItem('dataplan'));
            if(!(sesion_plan === null)) {
                var itineraries = sesion_plan.itineraries;

                showMapView.marker_map([sesion_plan.from.lat,sesion_plan.from.lon],[sesion_plan.to.lat,sesion_plan.to.lon], map);

                for (i = 0; i < itineraries.length; i++) {
                    for (ii=0; ii < itineraries[i].legs.length; ii++) {
                      showMapView.drawRouteAmigo(itineraries[i].legs[ii].legGeometry.points, itineraries[i].legs[ii].mode);
                    }
                }
            }

        }
      } catch (e) {
        console.log("entre cath")
	    map.setView([center[1], center[0]], config.geocode().zoom);
      }

    }
  });
}
<commit_msg>adding html layer color<commit_after>var config = require('config');
var FeedbackModal = require('feedback-modal');
var FilterView = require('filter-view');
var HelpMeChoose = require('help-me-choose-view');
var LeafletTransitiveLayer = require('Leaflet.TransitiveLayer');
var LocationsView = require('locations-view');
var log = require('./client/log')('planner-page');
var showMapView = require('map-view');
var OptionsView = require('options-view');
var PlannerNav = require('planner-nav');
var querystring = require('querystring');
var scrollbarSize = require('scrollbar-size');
var scrolling = require('scrolling');
var session = require('session');
var textModal = require('text-modal');
//var transitive = require('transitive');
var ua = require('user-agent');
var view = require('view');
var showWelcomeWizard = require('welcome-flow');
var showPlannerWalkthrough = require('planner-walkthrough');
var geocode = require('geocode');

var FROM = config.geocode().start_address;
var TO = config.geocode().end_address;
var isMobile = window.innerWidth <= 480;
var center = config.geocode().center.split(',').map(parseFloat);

var View = view(require('./template.html'), function(view, model) {
  view.scrollable = view.find('.scrollable');
  view.panelFooter = view.find('.footer');

  if (scrollbarSize > 0) {
    if (ua.os.name === 'Windows' || ua.browser.name !== 'Chrome')
      view.scrollable.style.marginRight = -scrollbarSize + 'px';

    // Scrollbars are fun and implemented the same on every OS/Browser...right
    if (ua.os.name === 'Windows' && ua.browser.name === 'Chrome')
      view.scrollable.style.paddingRight = scrollbarSize + 'px';
  }
});

/**
 * Expose `render`
 */

module.exports = function(ctx, next) {
  log('render');

  var plan = ctx.plan;
  var query = querystring.parse(window.location.search);

  // Set up the views
  var views = {
    'filter-view': new FilterView(plan),
    'locations-view': new LocationsView(plan),
    'options-view': new OptionsView(plan),
    'planner-nav': new PlannerNav(session)
  };

  ctx.view = new View(views);
  ctx.view.on('rendered', function() {
    // Set plan to loading
    plan.loading(true);

    for (var key in views) {
      views[key].emit('rendered', views[key]);
    }

    // Show the map
    var map = showMapView(ctx.view.find('.MapView'));

    console.log("map ->", map);

    // Create the transitive layer
    //var transitiveLayer = new LeafletTransitiveLayer(transitive);

    // Set the transitive layer
    //map.addLayer(transitiveLayer);

    // Update map on plan change
    updateMapOnPlanChange(plan, map);

    //map.on('click', function (e) {
    //      var from = plan.from_ll();
    //      var to = plan.to_ll();
    //      if (!plan.coordinateIsValid(from)) {
    //        plan.journey({
    //      places: [
    //        {
    //          place_id: 'from',
    //          place_lat: e.latlng.lat,
    //          place_lon: e.latlng.lng,
    //          place_name: 'From'
    //        },
    //        {
    //          place_id: 'to',
    //          place_lat: (plan.to_ll() ? plan.to_ll().lat : 0),
    //          place_lon: (plan.to_ll() ? plan.to_ll().lng : 0),
    //          place_name: 'To'
    //        }
    //      ]
    //    });
    //    plan.setAddress('from', e.latlng.lng + ',' + e.latlng.lat, function (err, res) {
    //        plan.updateRoutes();
    //    });
    //      } else if (!plan.coordinateIsValid(to)) {
    //    plan.journey({
    //      places: [
    //        {
    //          place_id: 'from',
    //          place_lat: plan.from_ll().lat,
    //          place_lon: plan.from_ll().lng,
    //          place_name: 'From'
    //        },
    //        {
    //          place_id: 'to',
    //          place_lat: e.latlng.lat,
    //          place_lon: e.latlng.lng,
    //          place_name: 'To'
    //        }
    //      ]
    //    });
    //    plan.setAddress('to', e.latlng.lng + ',' + e.latlng.lat, function (err, res) {
    //        plan.updateRoutes();
    //    });
    //      }
    //});

    // Clear plan & cookies for now, plan will re-save automatically on save
      var from = plan.from_ll();
      var to = plan.to_ll();
      //plan.clearStore();

    // If it's a shared URL or welcome is complete skip the welcome screen
    console.log("query ->", query);
    if ((query.from && query.to)) {
      showQuery(query);
    } else {
      console.log("plan.coordinateIsValid(from)", plan.coordinateIsValid(from));
      console.log("plan.coordinateIsValid(to)", plan.coordinateIsValid(to));

      if (plan.coordinateIsValid(from) && plan.coordinateIsValid(to)) {
          plan.setAddresses(
            from.lng + ',' + from.lat, // from
            to.lng + ',' + to.lat, // to
            function (err, res) {
              plan.updateRoutes();
              console.log("aqui la data del plan 4 ->", plan.dataplan);
            }
          );
          plan.updateRoutes();
          console.log("aqui la data del plan 3 ->", plan.dataplan);
      } else {
          console.log(from);
          console.log(to);
          plan.loading(false);
      }
    }
  });

  plan.on('updating options', function() {
    ctx.view.panelFooter.classList.add('hidden');
  });

  plan.on('updating options complete', function(res) {
    if (res && !res.err) ctx.view.panelFooter.classList.remove('hidden');
  });

  next();
};

/**
 * Reverse Commute
 */

View.prototype.reverseCommute = function(e) {
  e.preventDefault();
  var plan = session.plan();
  plan.set({
    from: plan.to(),
    from_id: plan.to_id(),
    from_ll: plan.to_ll(),
    to: plan.from(),
    to_id: plan.from_id(),
    to_ll: plan.from_ll()
  });

  plan.updateRoutes();

  console.log("aqui la data del plan 5 ->", plan.dataplan);
};

/**
 * Scroll
 */

View.prototype.scroll = function(e) {
  e.preventDefault();
  this.scrollable.scrollTop += (this.scrollable.scrollHeight / 5);
};

/**
 * On submit
 */

View.prototype.onsubmit = function(e) {
  e.preventDefault();
};

/**
 * Help Me Choose
 */

View.prototype.helpMeChoose = function(e) {
  HelpMeChoose(session.plan().options()).show();
};

/**
 * Show feedback modal
 */
View.prototype.feedback = function(e) {
  e.preventDefault();
  FeedbackModal().show();
};

/**
 * Hide Side Panel
 */

View.prototype.hideSidePanel = function (e) {
  var sidePanel = $('.SidePanel');
  var fullscreen = $('.fullscreen');
  var width = sidePanel.width();
  var map = showMapView.getMap();

  sidePanel.css({
    'transition': 'transform 2s',
    '-webkit-transition': '-webkit-transform 2s',
    'transform': 'translate3d(' + width + 'px, 0, 0)'
  });

  fullscreen.css({
    'transition': 'padding 2s',
    'padding': '0'
  });

  setTimeout(function () {
    map.invalidateSize();
  }, 2100)
};

/**
 * Show Side Panel
 */

View.prototype.showSidePanel = function (e) {
  var sidePanel = $('.SidePanel');
  var fullscreen = $('.fullscreen');
  var width = sidePanel.width();
  var map = showMapView.getMap();

  sidePanel.css({
    'transition': 'transform 2s',
    '-webkit-transition': '-webkit-transform 2s',
    'transform': 'translate3d(0, 0, 0)'
  });

  fullscreen.css({
    'transition': 'padding 2s',
    'padding-right': '320px'
  });

  setTimeout(function () {
    var plan = session.plan();
    map.invalidateSize();

    plan = session.plan();
    plan.updateRoutes();
    //transitive.updateData(plan.journey());
  }, 2100)
};

/**
 * Show Journey
 */

function showQuery(query) {
  var plan = session.plan();
  // If no querystring, see if we have them in the plan already
  var from = query.from || plan.from() || FROM;
  var to = query.to || plan.to() || TO;
  var sameAddresses = from === plan.from() && to === plan.to();

  // Set plan from querystring
  if (query.modes) plan.setModes(query.modes);
  if (query.start_time !== undefined) plan.start_time(parseInt(query.start_time, 10));
  if (query.end_time !== undefined) plan.end_time(parseInt(query.end_time, 10));
  if (query.days !== undefined) plan.days(query.days);

  // If has valid coordinates, load
  if (plan.validCoordinates() && sameAddresses) {
    plan.journey({
      places: plan.generatePlaces()
    });
    plan.updateRoutes();

    console.log("aqui la data del plan 1 ->", plan.dataplan);
  } else {
      if (!plan.validCoordinates()) {
	  plan.loading(false);
	  return;
      } else {
    // Set addresses and update the routes
    plan.setAddresses(from, to, function(err) {
      if (err) {
        log.error('%e', err);
      } else {
        plan.journey({
          places: plan.generatePlaces()
        });
        plan.updateRoutes();

        console.log("aqui la data del plan 2 ->", plan.dataplan);
      }
    });
}
  }
}

/**
 * Update Map on plan change
 */

function updateMapOnPlanChange(plan, map) {
  // Register plan update events
    /*
    for (i in map._layers) {
        if (map._layers[i].options.format == undefined) {
            try {
                map.removeLayer(map._layers[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }
        }
    }
    */

    //map.removeLayer(polyline);
/*

  for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }

  }
  */

  plan.on('change journey', function(journey) {

  var polyline_creadas = showMapView.getpolyline_creadas();
    //console.log("poliline credas ->", polyline_creadas);
    //console.log("llamamos sin evento ->", showMapView.polyline_creadas);

    for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }

  }

    showMapView.polyline_creadas = [];
    if (journey && !isMobile) {
      try {

        log('updating data');

        var datajourney = journey;
        if (!(plan.dataplan === undefined)) {
            var itineraries = plan.dataplan.itineraries;
            showMapView.marker_map([plan.dataplan.from.lat,plan.dataplan.from.lon],[plan.dataplan.to.lat,plan.dataplan.to.lon], map);
            for (i = 0; i < itineraries.length; i++) {
                for (ii=0; ii < itineraries[i].legs.length; ii++) {
                  console.log("itineraries[i].legs[ii]", itineraries[i].legs[ii]);
                  var circle = [itineraries[i].legs[ii].to.lat, itineraries[i].legs[ii].to.lon, itineraries[i].legs[ii].to.name];
                  console.log("circle", circle);
                  showMapView.marker_map_point(circle, map);

                  for (i = 0; i < itineraries[i].legs[ii].steps.length; i++) {
                       var circle2 = [itineraries[i].legs[ii].steps[i].lat, itineraries[i].legs[ii].steps[i].lon, ''];
                       showMapView.marker_map_point(circle2, map);
                  }
                  showMapView.drawRouteAmigo(itineraries[i].legs[ii].legGeometry.points, itineraries[i].legs[ii].mode);
                }
            }
          console.log("entre if ")
        }else{
            var sesion_plan = JSON.parse(localStorage.getItem('dataplan'));
            if(!(sesion_plan === null)) {
                var itineraries = sesion_plan.itineraries;

                showMapView.marker_map([sesion_plan.from.lat,sesion_plan.from.lon],[sesion_plan.to.lat,sesion_plan.to.lon], map);

                for (i = 0; i < itineraries.length; i++) {
                    for (ii=0; ii < itineraries[i].legs.length; ii++) {
                      showMapView.drawRouteAmigo(itineraries[i].legs[ii].legGeometry.points, itineraries[i].legs[ii].mode);
                    }
                }
            }

        }
      } catch (e) {
        console.log("entre cath")
	    map.setView([center[1], center[0]], config.geocode().zoom);
      }

    }
  });
}
<|endoftext|>


<commit_before><commit_msg>some simple methods<commit_after>var ModelManager = module.exports = function() {
  this.models = []
}

ModelManager.prototype.addModel = function(model) {
  this.models.push(model)
  return model
}

ModelManager.prototype.removeModel = function(model) {
  this.models = this.models.filter(function(_model) {
    return _model.name != model.name
  })
}

ModelManager.prototype.__defineGetter__('all', function() {
  return this.models
})<|endoftext|>


<commit_before>/*
 * Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of iotagent-manager
 *
 * iotagent-manager is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * iotagent-manager is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with iotagent-manager.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 */

const protocols = require('./protocolData');
const request = require('request');
const logger = require('logops');
const errors = require('../errors');
const _ = require('underscore');
const async = require('async');
const domain = require('../utils/domain');
const fillService = domain.fillService;
var context = {
    op: 'IoTAManager.Redirector'
};

function guessCollection(body) {
    if (body.services) {
        return 'services';
    } else if (body.devices) {
        return 'devices';
    }
    return null;
}

function extractProtocols(body) {
    const collectionName = guessCollection(body);
    let protocols;

    logger.debug(context, 'Extracting protocols from body for collection [%s]', collectionName);

    function extractProtocol(previous, item) {
        if (item.protocol) {
            if (Array.isArray(item.protocol)) {
                return _.union(previous, item.protocol);
            }
            previous.push(item.protocol);

            return _.uniq(previous);
        }
        return previous;
    }

    if (collectionName) {
        protocols = body[collectionName].reduce(extractProtocol, []);

        logger.debug(context, 'Protocols found: %j', protocols);

        return protocols;
    }
    return null;
}

function queryParamExtractor(req, res, next) {
    if (req.query.protocol) {
        logger.debug(context, 'Protocol found in the query parameters [%s]', req.query.protocol);
        req.protocolId = [req.query.protocol];
    } else if (req.method !== 'GET') {
        req.splitAndRedirect = true;
        req.protocolId = extractProtocols(req.body);
    }

    next();
}

function getProtocols(req, res, next) {
    function addProtocolAsync(previous, item, callback) {
        protocols.get(item, function (error, protocol) {
            if (error) {
                callback(error);
            } else {
                previous[item] = protocol;
                callback(null, previous);
            }
        });
    }

    function addProtocolSync(previous, item) {
        previous[item.protocol] = item;
        return previous;
    }

    function extractId(protocol) {
        return protocol.protocol;
    }

    if (req.protocolId) {
        logger.debug(context, 'Finding objects for the following protocols: %j', req.protocolId);

        if (req.protocolId.length === 0) {
            next(new errors.ProtocolNotFound('', ''));
        }

        async.reduce(req.protocolId, {}, addProtocolAsync, function endReduction(error, result) {
            req.protocolObj = result;
            next(error);
        });
    } else {
        logger.debug(context, 'Finding objects for all the protocols');

        protocols.list(function (error, protocols) {
            if (error) {
                next(error);
            } else {
                req.protocolId = protocols.map(extractId);
                req.protocolObj = protocols.reduce(addProtocolSync, {});
                logger.debug(context, 'Finding objects for this protocol: %j', req.protocolId);
                next();
            }
        });
    }
}

function splitByProtocol(req) {
    const collectionName = guessCollection(req.body);
    const collections = {};
    let clonedObject;

    if (!collectionName) {
        return collections;
    }

    for (let i = 0; i < req.body[collectionName].length; i++) {
        if (Array.isArray(req.body[collectionName][i].protocol)) {
            for (let j = 0; j < req.body[collectionName][i].protocol.length; j++) {
                clonedObject = _.clone(req.body[collectionName][i]);

                clonedObject.protocol = req.body[collectionName][i].protocol[j];
                clonedObject.resource = req.protocolObj[clonedObject.protocol].resource;

                if (collections[req.body[collectionName][i].protocol[j]]) {
                    collections[req.body[collectionName][i].protocol[j]][collectionName].push(clonedObject);
                } else {
                    collections[req.body[collectionName][i].protocol[j]] = {};
                    collections[req.body[collectionName][i].protocol[j]][collectionName] = [clonedObject];
                }
            }
        } else {
            clonedObject = _.clone(req.body[collectionName][i]);

            clonedObject.protocol = req.body[collectionName][i].protocol;
            clonedObject.resource = req.protocolObj[clonedObject.protocol].resource;

            if (!collections[req.body[collectionName][i].protocol]) {
                collections[req.body[collectionName][i].protocol] = {};
            }

            if (!collections[req.body[collectionName][i].protocol][collectionName]) {
                collections[req.body[collectionName][i].protocol][collectionName] = [];
            }

            collections[req.body[collectionName][i].protocol][collectionName].push(
                _.clone(req.body[collectionName][i])
            );
        }
    }

    return collections;
}

/**
 * Create the redirected request based on the protocol information and the original request. For backwards compatibility
 * the IoT Agent Manager removes the "/iot" prefix from the protocol address if found.
 *
 * @param {Object} req           Original request object to be forwarded.
 * @param {String} protocol      ID of the protocol where the request will be forwarded
 * @param {Object} body          JSON body of the original request.
 * @return {Object}             Request object prepared to be sent.
 */
function createRequest(req, protocol, body) {
    const options = {
        qs: _.clone(req.query),
        method: req.method,
        headers: req.headers
    };
    const protocolObj = req.protocolObj[protocol];
    let protocolAddress = protocolObj.iotagent;

    logger.debug(context, 'creating request using protocol:\n\n%j\n', protocolObj);

    // Save original apikey before be overwrite by apikey from body (probably modified)
    if (req.query.apikey) {
        options.qs.apikeyReq = req.query.apikey;
    }
    if (protocolObj.resource) {
        options.qs.resource = protocolObj.resource;
    }
    if (protocolObj.protocol) {
        options.qs.protocol = protocolObj.protocol;
    }
    if (protocolAddress.substr(-1) === '/') {
        protocolAddress = protocolAddress.slice(0, -1);
    }

    if (protocolAddress.substr(-4) === '/iot') {
        protocolAddress = protocolAddress.slice(0, -4);
    }

    options.uri = protocolAddress + req.path;

    if (body && body.services) {
        body.services = body.services.map(function cleanProtocol(item) {
            delete item.protocol;
            return item;
        });
        // Translate body.services

        if (req.method === 'PUT') {
            body = body.services[0];
        }
    }

    if (req.method === 'PUT' || req.method === 'POST') {
        options.body = JSON.stringify(body);
    }

    delete options.headers['content-length'];
    options.headers.connection = 'close';

    context = fillService(context, {
        service: options.headers['fiware-service'],
        subservice: options.headers['fiware-servicepath']
    });
    logger.debug(context, 'Forwarding request:\n\n%j\n', options);

    return options;
}

function createRequests(req, res, next) {
    function mapToBody(split, protocol) {
        return createRequest(req, protocol, split[protocol]);
    }

    if (req.splitAndRedirect) {
        const split = splitByProtocol(req);

        logger.debug(context, 'Creating request for multiple elements');

        req.requests = req.protocolId.map(mapToBody.bind(null, split));
    } else {
        logger.debug(context, 'Creating request for redirecting single requests');
        req.requests = [];
        for (let i = 0; i < req.protocolId.length; i++) {
            req.requests.push(createRequest(req, req.protocolId[i], req.body));
        }
    }

    next();
}

function processRequests(req, res, next) {
    function extractStatusCode(result) {
        if (result && result.length === 2 && result[0].statusCode) {
            return result[0].statusCode;
        }
        return 0;
    }

    function sendRequest(options, callback) {
        logger.debug(context, 'Sending redirection with following options: %j', options);
        // Use original apikey, not apikey from body
        if (options.qs.apikeyReq) {
            options.qs.apikey = options.qs.apikeyReq;
        }
        request(options, function (error, response, body) {
            if (error) {
                logger.error(
                    context,
                    'REDIRECTION-001: Error found redirecting requests to [%s]: %j',
                    options.uri,
                    error
                );

                callback(new errors.TargetServerError(error));
            } else if (response.statusCode >= 500) {
                logger.error(
                    context,
                    'REDIRECTION-002: Wrong status code detected [%s] and body response [%s] redirecting request to [%s]',
                    response.statusCode,
                    response.body,
                    options.uri
                );
                callback(
                    new errors.TargetServerError(
                        'Wrong status code detected [' +
                            response.statusCode +
                            '] and body response [' +
                            response.body +
                            '] redirecting request to ' +
                            options.uri
                    )
                );
            } else if (body && body.length > 0) {
                let parsedBody;
                let parseError;

                try {
                    parsedBody = JSON.parse(body);
                    if (response.statusCode === 409) {
                        parseError = new errors.DuplicateError(parsedBody);
                    }
                    logger.debug(context, 'Response body from the redirected request parsed: \n\n%j\n', parsedBody);
                } catch (e) {
                    logger.error(
                        context,
                        'REDIRECTION-003: Error parsing response body from the redirected request: %s to [%s]',
                        e,
                        options.uri
                    );
                    parseError = new errors.TargetResponseError(e);
                }

                callback(parseError, [response, parsedBody]);
            } else {
                callback(null, [response, null]);
            }
        });
    }

    function combineResults(results) {
        let totalCount = 0;
        let finalResult = [];
        let collectionName;
        const resultObj = {};

        if (results[0] && results[0][1]) {
            if (results[0][1].devices || results[0][1].device_id) {
                collectionName = 'devices';
            } else if (results[0][1].services) {
                collectionName = 'services';
            } else {
                return null;
            }
        } else {
            return null;
        }

        for (let i = 0; i < results.length; i++) {
            logger.debug(context, 'results[%s][1] %j ', i, results[i][1]);

            if (results[i][1].count) {
                totalCount += results[i][1].count;
            } else {
                // Check if really there are some results in response
                if (results[i][1][collectionName]) {
                    if (results[i][1][collectionName].length > 0) {
                        totalCount += results[i][1][collectionName].length;
                    }
                } else if (results[i][1].length > 0) {
                    totalCount += results[i][1].length;
                }
                // Detect single device response but not Repsol empty device response
                if ('attributes' in results[i][1]) {
                    totalCount++;
                }
            }

            if (results[i][1][collectionName]) {
                finalResult = finalResult.concat(results[i][1][collectionName]);
            } else {
                finalResult = finalResult.concat(results[i][1]);
            }
        }

        resultObj.count = totalCount;
        resultObj[collectionName] = finalResult;

        return resultObj;
    }

    function requestHandler(error, results) {
        let combinedResult;

        if (error) {
            logger.error(context, 'The redirection ended up in error: ', error);
            next(error);
        } else {
            logger.debug(context, 'results %j', results);
            const statusCodes = _.uniq(results.map(extractStatusCode));

            if (statusCodes.length === 1) {
                if (req.method === 'POST' || req.method === 'DELETE' || req.method === 'PUT') {
                    res.status(statusCodes[0]).send();
                } else if (results.length >= 1) {
                    combinedResult = combineResults(results);

                    if (combinedResult) {
                        res.status(statusCodes[0]).json(combinedResult);
                    } else {
                        next(new errors.TargetServerError('No valid replies from any IoTAgent'));
                    }
                } else {
                    res.status(statusCodes[0]).json({});
                }
            } else {
                const errorMsg =
                    'Wrong status code obtained in some of the responses [' +
                    JSON.stringify(statusCodes) +
                    '] redirecting request';

                logger.error(context, errorMsg);

                next(new errors.TargetServerError(errorMsg));
            }
        }
    }

    async.map(req.requests, sendRequest, requestHandler);
}

function loadContextRoutes(router) {
    const middlewareList = [queryParamExtractor, getProtocols, createRequests, processRequests];

    router.post('/iot/services', middlewareList);
    router.post('/iot/devices', middlewareList);
    router.put('/iot/services', middlewareList);
    router.delete('/iot/services', middlewareList);
    router.get('/iot/devices', middlewareList);
    router.get('/iot/devices/:id', middlewareList);
    router.put('/iot/devices/:id', middlewareList);
    router.delete('/iot/devices/:id', middlewareList);
}

exports.loadContextRoutes = loadContextRoutes;

// Ccustom handleError for IOTAM CPP backward compability

/* eslint-disable-next-line no-unused-vars */
function handleError(error, req, res, next) {
    let code = 500;

    logger.debug(context, 'Error [%s] handling request: %s', error.name, error.message);

    if (error.code && String(error.code).match(/^[2345]\d\d$/)) {
        code = error.code;
    }

    const response = {
        name: error.name,
        message: error.message
    };
    // Expect IOTAM CPP format: errors[{ endpoint, code, details { name, mesage} }]
    if (error.errors) {
        response.errors = error.errors;
    }
    // Expect BodyPaser error from Express
    if (error.name === 'SyntaxError') {
        code = 400;
    }
    res.status(code).json(response);
}

exports.handleError = handleError;
<commit_msg>fix format<commit_after>/*
 * Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of iotagent-manager
 *
 * iotagent-manager is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * iotagent-manager is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with iotagent-manager.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 */

const protocols = require('./protocolData');
const request = require('request');
const logger = require('logops');
const errors = require('../errors');
const _ = require('underscore');
const async = require('async');
const domain = require('../utils/domain');
const fillService = domain.fillService;
var context = {
    op: 'IoTAManager.Redirector'
};

function guessCollection(body) {
    if (body.services) {
        return 'services';
    } else if (body.devices) {
        return 'devices';
    }
    return null;
}

function extractProtocols(body) {
    const collectionName = guessCollection(body);
    let protocols;

    logger.debug(context, 'Extracting protocols from body for collection [%s]', collectionName);

    function extractProtocol(previous, item) {
        if (item.protocol) {
            if (Array.isArray(item.protocol)) {
                return _.union(previous, item.protocol);
            }
            previous.push(item.protocol);

            return _.uniq(previous);
        }
        return previous;
    }

    if (collectionName) {
        protocols = body[collectionName].reduce(extractProtocol, []);

        logger.debug(context, 'Protocols found: %j', protocols);

        return protocols;
    }
    return null;
}

function queryParamExtractor(req, res, next) {
    if (req.query.protocol) {
        logger.debug(context, 'Protocol found in the query parameters [%s]', req.query.protocol);
        req.protocolId = [req.query.protocol];
    } else if (req.method !== 'GET') {
        req.splitAndRedirect = true;
        req.protocolId = extractProtocols(req.body);
    }

    next();
}

function getProtocols(req, res, next) {
    function addProtocolAsync(previous, item, callback) {
        protocols.get(item, function (error, protocol) {
            if (error) {
                callback(error);
            } else {
                previous[item] = protocol;
                callback(null, previous);
            }
        });
    }

    function addProtocolSync(previous, item) {
        previous[item.protocol] = item;
        return previous;
    }

    function extractId(protocol) {
        return protocol.protocol;
    }

    if (req.protocolId) {
        logger.debug(context, 'Finding objects for the following protocols: %j', req.protocolId);

        if (req.protocolId.length === 0) {
            next(new errors.ProtocolNotFound('', ''));
        }

        async.reduce(req.protocolId, {}, addProtocolAsync, function endReduction(error, result) {
            req.protocolObj = result;
            next(error);
        });
    } else {
        logger.debug(context, 'Finding objects for all the protocols');

        protocols.list(function (error, protocols) {
            if (error) {
                next(error);
            } else {
                req.protocolId = protocols.map(extractId);
                req.protocolObj = protocols.reduce(addProtocolSync, {});
                logger.debug(context, 'Finding objects for this protocol: %j', req.protocolId);
                next();
            }
        });
    }
}

function splitByProtocol(req) {
    const collectionName = guessCollection(req.body);
    const collections = {};
    let clonedObject;

    if (!collectionName) {
        return collections;
    }

    for (let i = 0; i < req.body[collectionName].length; i++) {
        if (Array.isArray(req.body[collectionName][i].protocol)) {
            for (let j = 0; j < req.body[collectionName][i].protocol.length; j++) {
                clonedObject = _.clone(req.body[collectionName][i]);

                clonedObject.protocol = req.body[collectionName][i].protocol[j];
                clonedObject.resource = req.protocolObj[clonedObject.protocol].resource;

                if (collections[req.body[collectionName][i].protocol[j]]) {
                    collections[req.body[collectionName][i].protocol[j]][collectionName].push(clonedObject);
                } else {
                    collections[req.body[collectionName][i].protocol[j]] = {};
                    collections[req.body[collectionName][i].protocol[j]][collectionName] = [clonedObject];
                }
            }
        } else {
            clonedObject = _.clone(req.body[collectionName][i]);

            clonedObject.protocol = req.body[collectionName][i].protocol;
            clonedObject.resource = req.protocolObj[clonedObject.protocol].resource;

            if (!collections[req.body[collectionName][i].protocol]) {
                collections[req.body[collectionName][i].protocol] = {};
            }

            if (!collections[req.body[collectionName][i].protocol][collectionName]) {
                collections[req.body[collectionName][i].protocol][collectionName] = [];
            }

            collections[req.body[collectionName][i].protocol][collectionName].push(
                _.clone(req.body[collectionName][i])
            );
        }
    }

    return collections;
}

/**
 * Create the redirected request based on the protocol information and the original request. For backwards compatibility
 * the IoT Agent Manager removes the "/iot" prefix from the protocol address if found.
 *
 * @param {Object} req           Original request object to be forwarded.
 * @param {String} protocol      ID of the protocol where the request will be forwarded
 * @param {Object} body          JSON body of the original request.
 * @return {Object}             Request object prepared to be sent.
 */
function createRequest(req, protocol, body) {
    const options = {
        qs: _.clone(req.query),
        method: req.method,
        headers: req.headers
    };
    const protocolObj = req.protocolObj[protocol];
    let protocolAddress = protocolObj.iotagent;

    logger.debug(context, 'creating request using protocol:\n\n%j\n', protocolObj);

    // Save original apikey before be overwrite by apikey from body (probably modified)
    if (req.query.apikey) {
        options.qs.apikeyReq = req.query.apikey;
    }
    if (protocolObj.resource) {
        options.qs.resource = protocolObj.resource;
    }
    if (protocolObj.protocol) {
        options.qs.protocol = protocolObj.protocol;
    }
    if (protocolAddress.substr(-1) === '/') {
        protocolAddress = protocolAddress.slice(0, -1);
    }

    if (protocolAddress.substr(-4) === '/iot') {
        protocolAddress = protocolAddress.slice(0, -4);
    }

    options.uri = protocolAddress + req.path;

    if (body && body.services) {
        body.services = body.services.map(function cleanProtocol(item) {
            delete item.protocol;
            return item;
        });
        // Translate body.services

        if (req.method === 'PUT') {
            body = body.services[0];
        }
    }

    if (req.method === 'PUT' || req.method === 'POST') {
        options.body = JSON.stringify(body);
    }

    delete options.headers['content-length'];
    options.headers.connection = 'close';

    context = fillService(context, {
        service: options.headers['fiware-service'],
        subservice: options.headers['fiware-servicepath']
    });
    logger.debug(context, 'Forwarding request:\n\n%j\n', options);

    return options;
}

function createRequests(req, res, next) {
    function mapToBody(split, protocol) {
        return createRequest(req, protocol, split[protocol]);
    }

    if (req.splitAndRedirect) {
        const split = splitByProtocol(req);

        logger.debug(context, 'Creating request for multiple elements');

        req.requests = req.protocolId.map(mapToBody.bind(null, split));
    } else {
        logger.debug(context, 'Creating request for redirecting single requests');
        req.requests = [];
        for (let i = 0; i < req.protocolId.length; i++) {
            req.requests.push(createRequest(req, req.protocolId[i], req.body));
        }
    }

    next();
}

function processRequests(req, res, next) {
    function extractStatusCode(result) {
        if (result && result.length === 2 && result[0].statusCode) {
            return result[0].statusCode;
        }
        return 0;
    }

    function sendRequest(options, callback) {
        logger.debug(context, 'Sending redirection with following options: %j', options);
        // Use original apikey, not apikey from body
        if (options.qs.apikeyReq) {
            options.qs.apikey = options.qs.apikeyReq;
        }
        request(options, function (error, response, body) {
            if (error) {
                logger.error(
                    context,
                    'REDIRECTION-001: Error found redirecting requests to [%s]: %j',
                    options.uri,
                    error
                );

                callback(new errors.TargetServerError(error));
            } else if (response.statusCode >= 500) {
                logger.error(
                    context,
                    'REDIRECTION-002: Wrong status code detected [%s] and body response [%s] redirecting request to [%s]',
                    response.statusCode,
                    response.body,
                    options.uri
                );
                callback(
                    new errors.TargetServerError(
                        'Wrong status code detected [' +
                            response.statusCode +
                            '] and body response [' +
                            response.body +
                            '] redirecting request to [' +
                            options.uri +
                            ']'
                    )
                );
            } else if (body && body.length > 0) {
                let parsedBody;
                let parseError;

                try {
                    parsedBody = JSON.parse(body);
                    if (response.statusCode === 409) {
                        parseError = new errors.DuplicateError(parsedBody);
                    }
                    logger.debug(context, 'Response body from the redirected request parsed: \n\n%j\n', parsedBody);
                } catch (e) {
                    logger.error(
                        context,
                        'REDIRECTION-003: Error parsing response body from the redirected request: %s to [%s]',
                        e,
                        options.uri
                    );
                    parseError = new errors.TargetResponseError(e);
                }

                callback(parseError, [response, parsedBody]);
            } else {
                callback(null, [response, null]);
            }
        });
    }

    function combineResults(results) {
        let totalCount = 0;
        let finalResult = [];
        let collectionName;
        const resultObj = {};

        if (results[0] && results[0][1]) {
            if (results[0][1].devices || results[0][1].device_id) {
                collectionName = 'devices';
            } else if (results[0][1].services) {
                collectionName = 'services';
            } else {
                return null;
            }
        } else {
            return null;
        }

        for (let i = 0; i < results.length; i++) {
            logger.debug(context, 'results[%s][1] %j ', i, results[i][1]);

            if (results[i][1].count) {
                totalCount += results[i][1].count;
            } else {
                // Check if really there are some results in response
                if (results[i][1][collectionName]) {
                    if (results[i][1][collectionName].length > 0) {
                        totalCount += results[i][1][collectionName].length;
                    }
                } else if (results[i][1].length > 0) {
                    totalCount += results[i][1].length;
                }
                // Detect single device response but not Repsol empty device response
                if ('attributes' in results[i][1]) {
                    totalCount++;
                }
            }

            if (results[i][1][collectionName]) {
                finalResult = finalResult.concat(results[i][1][collectionName]);
            } else {
                finalResult = finalResult.concat(results[i][1]);
            }
        }

        resultObj.count = totalCount;
        resultObj[collectionName] = finalResult;

        return resultObj;
    }

    function requestHandler(error, results) {
        let combinedResult;

        if (error) {
            logger.error(context, 'The redirection ended up in error: ', error);
            next(error);
        } else {
            logger.debug(context, 'results %j', results);
            const statusCodes = _.uniq(results.map(extractStatusCode));

            if (statusCodes.length === 1) {
                if (req.method === 'POST' || req.method === 'DELETE' || req.method === 'PUT') {
                    res.status(statusCodes[0]).send();
                } else if (results.length >= 1) {
                    combinedResult = combineResults(results);

                    if (combinedResult) {
                        res.status(statusCodes[0]).json(combinedResult);
                    } else {
                        next(new errors.TargetServerError('No valid replies from any IoTAgent'));
                    }
                } else {
                    res.status(statusCodes[0]).json({});
                }
            } else {
                const errorMsg =
                    'Wrong status code obtained in some of the responses [' +
                    JSON.stringify(statusCodes) +
                    '] redirecting request';

                logger.error(context, errorMsg);

                next(new errors.TargetServerError(errorMsg));
            }
        }
    }

    async.map(req.requests, sendRequest, requestHandler);
}

function loadContextRoutes(router) {
    const middlewareList = [queryParamExtractor, getProtocols, createRequests, processRequests];

    router.post('/iot/services', middlewareList);
    router.post('/iot/devices', middlewareList);
    router.put('/iot/services', middlewareList);
    router.delete('/iot/services', middlewareList);
    router.get('/iot/devices', middlewareList);
    router.get('/iot/devices/:id', middlewareList);
    router.put('/iot/devices/:id', middlewareList);
    router.delete('/iot/devices/:id', middlewareList);
}

exports.loadContextRoutes = loadContextRoutes;

// Ccustom handleError for IOTAM CPP backward compability

/* eslint-disable-next-line no-unused-vars */
function handleError(error, req, res, next) {
    let code = 500;

    logger.debug(context, 'Error [%s] handling request: %s', error.name, error.message);

    if (error.code && String(error.code).match(/^[2345]\d\d$/)) {
        code = error.code;
    }

    const response = {
        name: error.name,
        message: error.message
    };
    // Expect IOTAM CPP format: errors[{ endpoint, code, details { name, mesage} }]
    if (error.errors) {
        response.errors = error.errors;
    }
    // Expect BodyPaser error from Express
    if (error.name === 'SyntaxError') {
        code = 400;
    }
    res.status(code).json(response);
}

exports.handleError = handleError;
<|endoftext|>


<commit_before>var cradle = require('cradle')
  , root = this
  , couchDbStorage
  , Storage;

if (typeof exports !== 'undefined') {
    couchDbStorage = exports;
} else {
    couchDbStorage = root.couchDbStorage = {};
}

couchDbStorage.VERSION = '0.0.1';

// Create new instance of storage.
couchDbStorage.createStorage = function(options, callback) {
    new Storage(options, callback);
};

/*******************************************
* Storage
*/
Storage = function(options, callback) {
    if (typeof options === 'function')
        callback = options;

    var defaults = {
        host: 'localhost',
        port: 5984,
        dbName: 'eventstore',
        eventsCollectionName: 'events',
        snapshotsCollectionName: 'snapshots'
    };

    this.options = mergeOptions(options, defaults);

    this.store = new(cradle.Connection)();
    this.client = this.store.database(this.options.dbName);
    this.client.exists(function(err, res) {
    	if (err) {
			callback(err);
		}
		else if (res === false) {
            this.client.create(function(err) {
                if (err) {
                    callback(err);
                }
                else {
                    this.client.save('_design/'+this.options.dbName, {
                        byStreamId: {
                            map: function (evt) {
                                if (evt.snapshotId == null) {
                                    emit(evt.streamId, evt);
                                }
                            }
                        },
                        allUndispatched: {
                            map: function (evt) {
                                if (evt.snapshotId == null && evt.dispatched === false) {
                                    emit(evt._id, evt);
                                }
                            }
                        },
                        snapshotsByStreamId: {
                            map: function (snapshot) {
                                if (snapshot.snapshotId != null) {
                                    emit(snapshot.streamId, snapshot);
                                }
                            }
                        },
                        all: {
                            map: function (evt) {
                                emit(evt._id, evt);
                            }
                        }
                    });
                    callback(null, this);
                }
            }.bind(this));
        }
        else {
            callback(null, this);
        }
    }.bind(this));
};

Storage.prototype = {

    // This function saves an event in the storage.
    addEvents: function(events, callback) {
        for(var i in events) {
            events[i]._id = events[i].commitId;
        }
        this.client.save(events, callback);
    },

    // This function saves a snapshot in the storage.
    addSnapshot: function(snapshot, callback) {
        snapshot._id = snapshot.snapshotId;
        this.client.save(snapshot, callback);
    },

    // This function returns the wished events.
    getEvents: function(streamId, minRev, maxRev, callback) {
        this.client.view(this.options.dbName+'/byStreamId', { 'key': streamId },
            function(err, res) {
                if(!err) {
                    var result = [];
                    for (var i in res) {
        				result.push(res[i].value);
        			}
                    if (result.length === 0) {
                        callback(null, []);
                    } else {
                        if (maxRev === -1) {
                            callback(null, result.slice(minRev));
                        }
                        else {
                            callback(null, result.slice(minRev, maxRev));
                        }
                    }
                }
                else {
                    callback(err);
    			}
            }.bind(this));
    },

    // This function returns all events.
    getAllEvents: function(callback) {
        this.client.view(this.options.dbName+'/all',
            function(err, res) {
                if(!err) {
                    var result = [];
                    for (var i in res) {
            			result.push(res[i].value);
        			}
                    if (result.length === 0) {
                        callback(null, []);
                    } else {
                        if (maxRev === -1) {
                            callback(null, result.slice(minRev));
                        }
                        else {
                            callback(null, result.slice(minRev, maxRev));
                        }
                    }
                }
                else {
    				callback(err);
    			}
            }.bind(this));
    },

    // This function returns the wished snapshot.
    // If revMax is -1 returns the latest snapshot.
    getSnapshot: function(streamId, maxRev, callback) {
        this.client.view(this.options.dbName+'/snapshotsByStreamId', { 'key': streamId },
            function(err, res) {
                if(!err) {
                    var result = [];
                	for (var i in res) {
        				result.push(res[i].value);
        			}
                    if (result.length === 0) {
                        callback(null);
                    } else {
                        if (maxRev === -1) {
                            callback(null, result[result.length-1]);
                        }
                        else {
                            callback(null, result[maxRev]);
                        }
                    }
                }
                else {
        			callback(err);
    			}
            }.bind(this));
    },

    // This function returns all undispatched events.
    getUndispatchedEvents: function(callback) {
        this.client.view(this.options.dbName+'/allUndispatched', function(err, res) {
        	if (err) {
    			callback(err);
    		}
    		else {
    			var result = [];
    			for (var i in res) {
    				result.push(res[i].value);
    			}
    			callback(null, result);
    		}
        });
    },

    // This function set an event to dispatched.
    setEventToDispatched: function(event, callback) {
        this.client.merge(evt.commitId, {'dispatched': true}, function(err, res) {
            if (err) {
                callback(err);
            }
        });
    },

    // This function returns a new id.
    getId: function(callback) {
        this.store.uuids(function(err, uuids) {
            if (err) {
        		callback(err);
    		}
    		else {
                if (typeof callback === 'function') {
                    callback(null, uuids.toString());
                }
            }
        });
    }
}

// helper
var mergeOptions = function(options, defaultOptions) {
    if (!options || typeof options === 'function') {
        return defaultOptions;
    }

    var merged = {};
    for (var attrname in defaultOptions) { merged[attrname] = defaultOptions[attrname]; }
    for (var attrname in options) { if (options[attrname]) merged[attrname] = options[attrname]; }
    return merged;
};
<commit_msg>clean up<commit_after>var cradle = require('cradle')
  , root = this
  , couchDbStorage
  , Storage;

if (typeof exports !== 'undefined') {
    couchDbStorage = exports;
} else {
    couchDbStorage = root.couchDbStorage = {};
}

couchDbStorage.VERSION = '0.0.1';

// Create new instance of storage.
couchDbStorage.createStorage = function(options, callback) {
    new Storage(options, callback);
};

/*******************************************
* Storage
*/
Storage = function(options, callback) {
    if (typeof options === 'function')
        callback = options;

    var defaults = {
        host: 'localhost',
        port: 5984,
        dbName: 'eventstore',
        eventsCollectionName: 'events',
        snapshotsCollectionName: 'snapshots'
    };

    this.options = mergeOptions(options, defaults);

    this.store = new(cradle.Connection)();
    this.client = this.store.database(this.options.dbName);
    this.client.exists(function(err, res) {
        if (err) {
			callback(err);
		}
		else if (res === false) {
            this.client.create(function(err) {
                if (err) {
                    callback(err);
                }
                else {
                    this.client.save('_design/'+this.options.dbName, {
                        byStreamId: {
                            map: function (evt) {
                                if (evt.snapshotId === null) {
                                    emit(evt.streamId, evt);
                                }
                            }
                        },
                        allUndispatched: {
                            map: function (evt) {
                                if (evt.snapshotId === null && evt.dispatched === false) {
                                    emit(evt._id, evt);
                                }
                            }
                        },
                        snapshotsByStreamId: {
                            map: function (snapshot) {
                                if (snapshot.snapshotId !== null) {
                                    emit(snapshot.streamId, snapshot);
                                }
                            }
                        },
                        all: {
                            map: function (evt) {
                                emit(evt._id, evt);
                            }
                        }
                    });
                    callback(null, this);
                }
            }.bind(this));
        }
        else {
            callback(null, this);
        }
    }.bind(this));
};

Storage.prototype = {

    // This function saves an event in the storage.
    addEvents: function(events, callback) {
        for(var i in events) {
            events[i]._id = events[i].commitId;
        }
        this.client.save(events, callback);
    },

    // This function saves a snapshot in the storage.
    addSnapshot: function(snapshot, callback) {
        snapshot._id = snapshot.snapshotId;
        this.client.save(snapshot, callback);
    },

    // This function returns the wished events.
    getEvents: function(streamId, minRev, maxRev, callback) {

        this.client.view(this.options.dbName+'/byStreamId', { 'key': streamId },
            function(err, res) {
                if(!err) {
                    var result = [];
                    for (var i in res) {
                        result.push(res[i].value);
                    }
                    if (result.length === 0) {
                        callback(null, []);
                    } else {
                        if (maxRev === -1) {
                            callback(null, result.slice(minRev));
                        }
                        else {
                            callback(null, result.slice(minRev, maxRev));
                        }
                    }
                }
                else {
                    callback(err);
                }
            }.bind(this));
    },

    // This function returns all events.
    getAllEvents: function(callback) {

        this.client.view(this.options.dbName+'/all',
            function(err, res) {
                if(!err) {
                    var result = [];
                    for (var i in res) {
                        result.push(res[i].value);
                    }
                    if (result.length === 0) {
                        callback(null, []);
                    } else {
                        if (maxRev === -1) {
                            callback(null, result.slice(minRev));
                        }
                        else {
                            callback(null, result.slice(minRev, maxRev));
                        }
                    }
                }
                else {
                    callback(err);
                }
            }.bind(this));
    },

    // This function returns the wished snapshot.
    // If revMax is -1 returns the latest snapshot.
    getSnapshot: function(streamId, maxRev, callback) {

        this.client.view(this.options.dbName+'/snapshotsByStreamId', { 'key': streamId },
            function(err, res) {
                if(!err) {
                    var result = [];
                    for (var i in res) {
                        result.push(res[i].value);
                    }
                    if (result.length === 0) {
                        callback(null);
                    } else {
                        if (maxRev === -1) {
                            callback(null, result[result.length-1]);
                        }
                        else {
                            callback(null, result[maxRev]);
                        }
                    }
                }
                else {
                    callback(err);
                }
            }.bind(this));
    },

    // This function returns all undispatched events.
    getUndispatchedEvents: function(callback) {

        this.client.view(this.options.dbName+'/allUndispatched', function(err, res) {
            if (err) {
                callback(err);
            }
            else {
                var result = [];
                for (var i in res) {
                    result.push(res[i].value);
                }
                callback(null, result);
	        }
        });
    },

    // This function set an event to dispatched.
    setEventToDispatched: function(event, callback) {

        this.client.merge(evt.commitId, {'dispatched': true}, function(err, res) {
            if (err) {
                callback(err);
            }
        });
    },

    // This function returns a new id.
    getId: function(callback) {

        this.store.uuids(function(err, uuids) {
            if (err) {
                callback(err);
            }
            else {
                if (typeof callback === 'function') {
                    callback(null, uuids.toString());
                }
            }
        });
    }
};

// helper
var mergeOptions = function(options, defaultOptions) {
    if (!options || typeof options === 'function') {
        return defaultOptions;
    }

    var merged = {};
    for (var attrname in defaultOptions) { merged[attrname] = defaultOptions[attrname]; }
    for (var attrname in options) { if (options[attrname]) merged[attrname] = options[attrname]; }
    return merged;
};
<|endoftext|>