<commit_before>var http = require('http'),
    firmata = require('firmata'),
    xbee_api = require('xbee-api'),
    serialPort = require('serialport'),
    XbeeApiStream = require('./XbeeApiStream.js');

const PORT = 8080;

xbeeAPI = new xbee_api.XBeeAPI({
    api_mode: 2
});

var serialOptions = {
    baudrate: 9600,
    parser: xbeeAPI.rawParser()
};

var deviceList = [];
var busyDevices = [];

var Serial = new serialPort.SerialPort(process.argv[2], serialOptions, true, function() {
    console.log('Opened serial port');
    Serial.flush();

    xbeeAPI.on('frame_object', function(frame) {
        if (frame.type === xbee_api.constants.FRAME_TYPE.NODE_IDENTIFICATION) {
            if (deviceList.filter(function(item) {
                    return item === frame.remote64;
                }).length === 0)
                deviceList.push(frame.remote64);
            console.log(frame);
        }
    });
    var server = http.createServer(httpRequestHandler);

    server.listen(PORT, function() {
        console.log("Server listening on: http://localhost:%s", PORT);
    });

});

function httpRequestHandler(request, response) {
    var url = request.url.split('/').slice(1);
    console.log(request.url);
    if (url.length > 0) {
        if (url[0] === 'device') {
            if (url.length > 1) {
                if (deviceList.filter(function(element) {
                        return element === url[1];
                    }).length > 0) {
                    if (busyDevices.filter(function(deviceID) {
                            return deviceID === url[1];
                        }).length > 0) {
                        response.end('ERROR: Device is busy. Please try again soon.');
                        return;
                    }
                    busyDevices.push(url[1]);
                    var xbeeStream = new XbeeApiStream(url[1], Serial, xbeeAPI);
                    var arduino = new firmata.Board(xbeeStream, function() {
                        setTimeout(function() {
                            if (!response.finished) {
                                response.end('ERROR: Device communication timed out. Try again.');
                                if (xbeeStream) xbeeStream.detachEventHandlers();
                                busyDevices.filter(function(deviceID) {
                                    return deviceID !== url[1];
                                });
                            }
                        }, 10000);
                        if (url[2] === 'pin') {
                            if (request.method === 'GET')
                                response.end(JSON.stringify(getPin(arduino, url[3])));
                            else if (request.method === 'POST') response.end(setPin(arduino, url[3], url[4]));
                        } else response.end(JSON.stringify(arduino.pins)); // send device ID, pins
                    });
                } else response.end('Error: No device found with that ID'); // send error in device ID request
            } else response.end(JSON.stringify(deviceList)); // send array of devices and IDs
        } else response.end('error in request, must request in the format /device/deviceID/pin/pinID'); // send error in request
    } else response.end('error in url'); // send error in url received
    if (xbeeStream) xbeeStream.detachEventHandlers();
    busyDevices.filter(function(deviceID) {
        return deviceID !== url[1];
    });
}

function setPin(arduino, pin, value) {
    if (pin && value) {
        if (value === 'HIGH') value = arduino.HIGH;
        else if (value === 'LOW') value = arduino.LOW;
        arduino.pinMode(pin, arduino.MODES.OUTPUT);
        arduino.digitalWrite(pin, value);
    }
}

function getPin(arduino, pin) {
    if (pin) {
        var _isAnalog = false;
        if (pin[0] === 'A') {
            _isAnalog = true;
            pin = pin.slice(1);
        }
        pin = parseInt(pin);
        if (_isAnalog) {
            var analogPins = arduino.pins.filter(getAnalogPins);
            if (pin < analogPins.length) return analogPins[pin];
        } else {
            var digitalPins = arduino.pins.filter(getDigitalPins);
            if (pin < digitalPins.length) return digitalPins[pin];
        }
    }
    return 'ERROR: No matching pin found';
}

function getDigitalPins(item) {
    return item.analogChannel === 127;
}

function getAnalogPins(item) {
    return item.analogChannel !== 127;
}
<commit_msg>Changed location of setTimeout to outside firmata constructor and in it, explicitly set arduino and xbeeStream references to null<commit_after>var http = require('http'),
    firmata = require('firmata'),
    xbee_api = require('xbee-api'),
    serialPort = require('serialport'),
    XbeeApiStream = require('./XbeeApiStream.js');

const PORT = 8080;

xbeeAPI = new xbee_api.XBeeAPI({
    api_mode: 2
});

var serialOptions = {
    baudrate: 9600,
    parser: xbeeAPI.rawParser()
};

var deviceList = [];
var busyDevices = [];

var Serial = new serialPort.SerialPort(process.argv[2], serialOptions, true, function() {
    console.log('Opened serial port');
    Serial.flush();

    xbeeAPI.on('frame_object', function(frame) {
        if (frame.type === xbee_api.constants.FRAME_TYPE.NODE_IDENTIFICATION) {
            if (deviceList.filter(function(item) {
                    return item === frame.remote64;
                }).length === 0)
                deviceList.push(frame.remote64);
            console.log(frame);
        }
    });
    var server = http.createServer(httpRequestHandler);

    server.listen(PORT, function() {
        console.log("Server listening on: http://localhost:%s", PORT);
    });

});

function httpRequestHandler(request, response) {
    var url = request.url.split('/').slice(1);
    console.log(request.url);
    if (url.length > 0) {
        if (url[0] === 'device') {
            if (url.length > 1) {
                if (deviceList.filter(function(element) {
                        return element === url[1];
                    }).length > 0) {
                    if (busyDevices.filter(function(deviceID) {
                            return deviceID === url[1];
                        }).length > 0) {
                        response.end('ERROR: Device is busy. Please try again soon.');
                        return;
                    }
                    busyDevices.push(url[1]);
                    var xbeeStream = new XbeeApiStream(url[1], Serial, xbeeAPI);
                    setTimeout(function() {
                        if (!response.finished) {
                            response.end('ERROR: Device communication timed out. Try again.');
                            if (xbeeStream) xbeeStream.detachEventHandlers();
                            busyDevices = busyDevices.filter(function(deviceID) {
                                return deviceID !== url[1];
                            });
                            if(arduino)	arduino = null;
                            if(xbeeStream) xbeeStream = null;
                        }
                    }, 20000);
                    var arduino = new firmata.Board(xbeeStream, function() {
                        if (url[2] === 'pin') {
                            if (request.method === 'GET')
                                response.end(JSON.stringify(getPin(arduino, url[3])));
                            else if (request.method === 'POST') response.end(setPin(arduino, url[3], url[4]));
                        } else response.end(JSON.stringify(arduino.pins)); // send device ID, pins
                        if (xbeeStream) xbeeStream.detachEventHandlers();
                        busyDevices = busyDevices.filter(function(deviceID) {
                            return deviceID !== url[1];
                        });
                    });
                } else response.end('Error: No device found with that ID'); // send error in device ID request
            } else response.end(JSON.stringify(deviceList)); // send array of devices and IDs
        } else response.end('error in request, must request in the format /device/deviceID/pin/pinID'); // send error in request
    } else response.end('error in url'); // send error in url received
}

function setPin(arduino, pin, value) {
    if (pin && value) {
        if (value === 'HIGH') value = arduino.HIGH;
        else if (value === 'LOW') value = arduino.LOW;
        arduino.pinMode(pin, arduino.MODES.OUTPUT);
        arduino.digitalWrite(pin, value);
    }
}

function getPin(arduino, pin) {
    if (pin) {
        var _isAnalog = false;
        if (pin[0] === 'A') {
            _isAnalog = true;
            pin = pin.slice(1);
        }
        pin = parseInt(pin);
        if (_isAnalog) {
            var analogPins = arduino.pins.filter(getAnalogPins);
            if (pin < analogPins.length) return analogPins[pin];
        } else {
            var digitalPins = arduino.pins.filter(getDigitalPins);
            if (pin < digitalPins.length) return digitalPins[pin];
        }
    }
    return 'ERROR: No matching pin found';
}

function getDigitalPins(item) {
    return item.analogChannel === 127;
}

function getAnalogPins(item) {
    return item.analogChannel !== 127;
}
<|endoftext|>


<commit_before>const fs = require("fs");
const path = require("path");
const OS = require("os");
const BlockchainUtils = require("@truffle/blockchain-utils");
const Provider = require("@truffle/provider");
const async = require("async");
const { Web3Shim } = require("@truffle/interface-adapter");

const Networks = {
  deployed: function(options, callback) {
    let files;
    try {
      files = fs.readdirSync(options.contracts_build_directory);
    } catch (error) {
      // We can't read the directory. Act like we found nothing.
      files = [];
    }

    const promises = [];

    files.forEach(function(file) {
      promises.push(
        new Promise(function(accept, reject) {
          fs.readFile(
            path.join(options.contracts_build_directory, file),
            "utf8",
            function(err, body) {
              if (err) return reject(err);

              try {
                body = JSON.parse(body);
              } catch (e) {
                return reject(e);
              }

              accept(body);
            }
          );
        })
      );
    });

    Promise.all(promises)
      .then(function(binaries) {
        const ids_to_names = {};
        const networks = {};

        // binaries.map(function(b) {return b.contract_name + ": " + JSON.stringify(b.networks, null, 2)}).forEach(function(b) {
        //   console.log(b);
        // });

        Object.keys(options.networks).forEach(networkName => {
          const network = options.networks[networkName];
          const networkId = network.network_id;

          if (networkId == null) return;

          ids_to_names[networkId] = networkName;
          networks[networkName] = {};
        });

        binaries.forEach(function(json) {
          Object.keys(json.networks).forEach(networkId => {
            const network_name = ids_to_names[networkId] || networkId;

            if (networks[network_name] == null) {
              networks[network_name] = {};
            }

            const address = json.networks[networkId].address;

            if (address == null) return;

            networks[network_name][json.contractName] = address;
          });
        });

        callback(null, networks);
      })
      .catch(callback);
  },

  display: function(config, callback) {
    this.deployed(config, function(err, networks) {
      if (err) return callback(err);

      let networkNames = Object.keys(networks).sort();

      const starNetworks = networkNames.filter(networkName => {
        return (
          config.networks[networkName] != null &&
          config.networks[networkName].network_id === "*"
        );
      });

      // Remove * networks from network names.
      networkNames = networkNames.filter(networkName => {
        return starNetworks.indexOf(networkName) < 0;
      });

      const unknownNetworks = networkNames.filter(networkName => {
        const configuredNetworks = Object.keys(config.networks);
        let found = false;
        for (let i = 0; i < configuredNetworks.length; i++) {
          const configuredNetworkName = configuredNetworks[i];
          if (networkName === configuredNetworkName) {
            found = true;
            break;
          }
        }

        return !found;
      });

      // Only display this warning if:
      //
      //   At least one network is configured with the wildcard ('*') network id
      //   There's a least one network deployed to
      //   And one of those networks deployed to is unknown (i.e., unconfigured).
      if (
        starNetworks.length > 0 &&
        networkNames.length > 0 &&
        unknownNetworks.length > 0
      ) {
        config.logger.log(
          OS.EOL +
            "The following networks are configured to match any network id ('*'):" +
            OS.EOL
        );

        starNetworks.forEach(networkName => {
          config.logger.log("    " + networkName);
        });

        config.logger.log(
          OS.EOL +
            "Closely inspect the deployed networks below, and use `truffle networks --clean` to remove any networks that don't match your configuration. You should not use the wildcard configuration ('*') for staging and production networks for which you intend to deploy your application."
        );
      }

      networkNames.forEach(function(networkName) {
        config.logger.log("");

        let output = Object.keys(networks[networkName])
          .sort()
          .map(contract_name => {
            const address = networks[networkName][contract_name];
            return contract_name + ": " + address;
          });

        if (output.length === 0) output = ["No contracts deployed."];

        let message = "Network: ";

        const is_id = config.networks[networkName] == null;

        if (is_id) {
          message += "UNKNOWN (id: " + networkName + ")";
        } else {
          message +=
            networkName +
            " (id: " +
            config.networks[networkName].network_id +
            ")";
        }

        config.logger.log(message);
        config.logger.log("  " + output.join("\n  "));
      });

      if (networkNames.length === 0) {
        config.logger.log(
          OS.EOL + "Contracts have not been deployed to any network."
        );
      }

      config.logger.log("");

      callback();
    });
  },

  clean: function(config, callback) {
    let files;
    try {
      files = fs.readdirSync(config.contracts_build_directory);
    } catch (error) {
      return callback(error);
    }

    const configured_networks = Object.keys(config.networks);
    const promises = [];

    files.forEach(function(file) {
      promises.push(
        new Promise(function(accept, reject) {
          const file_path = path.join(config.contracts_build_directory, file);
          fs.readFile(file_path, "utf8", function(err, body) {
            if (err) return reject(err);

            try {
              body = JSON.parse(body);
            } catch (e) {
              return reject(e);
            }

            Object.keys(body.networks).forEach(installed_network_id => {
              let found = false;
              for (let i = 0; i < configured_networks.length; i++) {
                const configured_network = configured_networks[i];

                // If an installed network id matches a configured id, then we can ignore this one.
                if (
                  installed_network_id ===
                  config.networks[configured_network].network_id
                ) {
                  found = true;
                  break;
                }
              }

              // If we didn't find a suitable configuration, delete this network.
              if (found === false) {
                delete body.networks[installed_network_id];
              }
            });

            // Our work is done here. Save the file.
            fs.writeFile(
              file_path,
              JSON.stringify(body, null, 2),
              "utf8",
              function(err) {
                if (err) return reject(err);
                accept(body);
              }
            );
          });
        })
      );
    });

    // TODO: Display what's removed?
    Promise.all(promises)
      .then(() => {
        callback();
      })
      .catch(callback);
  },

  // Try to connect to every named network except for "test" and "development"
  asURIs: function(options, networks, callback) {
    if (typeof networks === "function") {
      callback = networks;
      networks = Object.keys(options.networks);
    }

    const result = {
      uris: {},
      failed: []
    };

    async.each(
      networks,
      async function(network_name, finished) {
        const provider = Provider.create(options.networks[network_name]);
        BlockchainUtils.asURI(provider, function(err, uri) {
          if (err) {
            result.failed.push(network_name);
          } else {
            result.uris[network_name] = uri;
          }
          finished();
        });
      },
      error => {
        if (error) return callback(error);
        callback(null, result);
      }
    );
  },

  matchesNetwork: async function(network_id, network_options, callback) {
    const provider = Provider.create(network_options);

    const first = network_id + "";
    const second = network_options.network_id + "";

    if (first === second) return callback(null, true);

    const isFirstANumber = isNaN(parseInt(network_id)) === false;
    const isSecondANumber =
      isNaN(parseInt(network_options.network_id)) === false;

    // If both network ids are numbers, then they don't match, and we should quit.
    if (isFirstANumber && isSecondANumber) return callback(null, false);

    const web3 = new Web3Shim({
      provider,
      networkType: network_options.type
    });
    web3.eth.net
      .getId(current_network_id => {
        if (first === current_network_id) return callback(null, true);

        if (isFirstANumber === false) {
          BlockchainUtils.matches(first, provider, callback);
        } else {
          // Nothing else to compare.
          return callback(null, false);
        }
      })
      .catch(callback);
  }
};

module.exports = Networks;
<commit_msg>Change a few more variable names<commit_after>const fs = require("fs");
const path = require("path");
const OS = require("os");
const BlockchainUtils = require("@truffle/blockchain-utils");
const Provider = require("@truffle/provider");
const async = require("async");
const { Web3Shim } = require("@truffle/interface-adapter");

const Networks = {
  deployed: function(options, callback) {
    let files;
    try {
      files = fs.readdirSync(options.contracts_build_directory);
    } catch (error) {
      // We can't read the directory. Act like we found nothing.
      files = [];
    }

    const promises = [];

    files.forEach(function(file) {
      promises.push(
        new Promise(function(accept, reject) {
          fs.readFile(
            path.join(options.contracts_build_directory, file),
            "utf8",
            function(err, body) {
              if (err) return reject(err);

              try {
                body = JSON.parse(body);
              } catch (e) {
                return reject(e);
              }

              accept(body);
            }
          );
        })
      );
    });

    Promise.all(promises)
      .then(function(binaries) {
        const ids_to_names = {};
        const networks = {};

        // binaries.map(function(b) {return b.contract_name + ": " + JSON.stringify(b.networks, null, 2)}).forEach(function(b) {
        //   console.log(b);
        // });

        Object.keys(options.networks).forEach(networkName => {
          const network = options.networks[networkName];
          const networkId = network.network_id;

          if (networkId == null) return;

          ids_to_names[networkId] = networkName;
          networks[networkName] = {};
        });

        binaries.forEach(function(json) {
          Object.keys(json.networks).forEach(networkId => {
            const network_name = ids_to_names[networkId] || networkId;

            if (networks[network_name] == null) {
              networks[network_name] = {};
            }

            const address = json.networks[networkId].address;

            if (address == null) return;

            networks[network_name][json.contractName] = address;
          });
        });

        callback(null, networks);
      })
      .catch(callback);
  },

  display: function(config, callback) {
    this.deployed(config, function(err, networks) {
      if (err) return callback(err);

      let networkNames = Object.keys(networks).sort();

      const starNetworks = networkNames.filter(networkName => {
        return (
          config.networks[networkName] != null &&
          config.networks[networkName].network_id === "*"
        );
      });

      // Remove * networks from network names.
      networkNames = networkNames.filter(networkName => {
        return starNetworks.indexOf(networkName) < 0;
      });

      const unknownNetworks = networkNames.filter(networkName => {
        const configuredNetworks = Object.keys(config.networks);
        let found = false;
        for (let i = 0; i < configuredNetworks.length; i++) {
          const configuredNetworkName = configuredNetworks[i];
          if (networkName === configuredNetworkName) {
            found = true;
            break;
          }
        }

        return !found;
      });

      // Only display this warning if:
      //
      //   At least one network is configured with the wildcard ('*') network id
      //   There's a least one network deployed to
      //   And one of those networks deployed to is unknown (i.e., unconfigured).
      if (
        starNetworks.length > 0 &&
        networkNames.length > 0 &&
        unknownNetworks.length > 0
      ) {
        config.logger.log(
          OS.EOL +
            "The following networks are configured to match any network id ('*'):" +
            OS.EOL
        );

        starNetworks.forEach(networkName => {
          config.logger.log("    " + networkName);
        });

        config.logger.log(
          OS.EOL +
            "Closely inspect the deployed networks below, and use `truffle networks --clean` to remove any networks that don't match your configuration. You should not use the wildcard configuration ('*') for staging and production networks for which you intend to deploy your application."
        );
      }

      networkNames.forEach(function(networkName) {
        config.logger.log("");

        let output = Object.keys(networks[networkName])
          .sort()
          .map(contract_name => {
            const address = networks[networkName][contract_name];
            return contract_name + ": " + address;
          });

        if (output.length === 0) output = ["No contracts deployed."];

        let message = "Network: ";

        const is_id = config.networks[networkName] == null;

        if (is_id) {
          message += "UNKNOWN (id: " + networkName + ")";
        } else {
          message +=
            networkName +
            " (id: " +
            config.networks[networkName].network_id +
            ")";
        }

        config.logger.log(message);
        config.logger.log("  " + output.join("\n  "));
      });

      if (networkNames.length === 0) {
        config.logger.log(
          OS.EOL + "Contracts have not been deployed to any network."
        );
      }

      config.logger.log("");

      callback();
    });
  },

  clean: function(config, callback) {
    let files;
    try {
      files = fs.readdirSync(config.contracts_build_directory);
    } catch (error) {
      return callback(error);
    }

    const configuredNetworks = Object.keys(config.networks);
    const promises = [];

    files.forEach(function(file) {
      promises.push(
        new Promise(function(accept, reject) {
          const filePath = path.join(config.contracts_build_directory, file);
          fs.readFile(filePath, "utf8", function(err, body) {
            if (err) return reject(err);

            try {
              body = JSON.parse(body);
            } catch (e) {
              return reject(e);
            }

            Object.keys(body.networks).forEach(installedNetworkId => {
              let found = false;
              for (let i = 0; i < configuredNetworks.length; i++) {
                const configuredNetwork = configuredNetworks[i];

                // If an installed network id matches a configured id, then we can ignore this one.
                if (
                  installedNetworkId ===
                  config.networks[configuredNetwork].network_id
                ) {
                  found = true;
                  break;
                }
              }

              // If we didn't find a suitable configuration, delete this network.
              if (found === false) {
                delete body.networks[installedNetworkId];
              }
            });

            // Our work is done here. Save the file.
            fs.writeFile(
              filePath,
              JSON.stringify(body, null, 2),
              "utf8",
              function(err) {
                if (err) return reject(err);
                accept(body);
              }
            );
          });
        })
      );
    });

    // TODO: Display what's removed?
    Promise.all(promises)
      .then(() => {
        callback();
      })
      .catch(callback);
  },

  // Try to connect to every named network except for "test" and "development"
  asURIs: function(options, networks, callback) {
    if (typeof networks === "function") {
      callback = networks;
      networks = Object.keys(options.networks);
    }

    const result = {
      uris: {},
      failed: []
    };

    async.each(
      networks,
      async function(network_name, finished) {
        const provider = Provider.create(options.networks[network_name]);
        BlockchainUtils.asURI(provider, function(err, uri) {
          if (err) {
            result.failed.push(network_name);
          } else {
            result.uris[network_name] = uri;
          }
          finished();
        });
      },
      error => {
        if (error) return callback(error);
        callback(null, result);
      }
    );
  },

  matchesNetwork: async function(network_id, network_options, callback) {
    const provider = Provider.create(network_options);

    const first = network_id + "";
    const second = network_options.network_id + "";

    if (first === second) return callback(null, true);

    const isFirstANumber = isNaN(parseInt(network_id)) === false;
    const isSecondANumber =
      isNaN(parseInt(network_options.network_id)) === false;

    // If both network ids are numbers, then they don't match, and we should quit.
    if (isFirstANumber && isSecondANumber) return callback(null, false);

    const web3 = new Web3Shim({
      provider,
      networkType: network_options.type
    });
    web3.eth.net
      .getId(current_network_id => {
        if (first === current_network_id) return callback(null, true);

        if (isFirstANumber === false) {
          BlockchainUtils.matches(first, provider, callback);
        } else {
          // Nothing else to compare.
          return callback(null, false);
        }
      })
      .catch(callback);
  }
};

module.exports = Networks;
<|endoftext|>


<commit_before>/**
 * @file HTTP mocking
 * @since 0.2.2
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HTTP_METHODS*/ // HTTP Methods
/*global _gpfArrayForEachFalsy*/ // _gpfArrayForEach that returns first truthy value computed by the callback
/*global _gpfHost*/ // Host type
/*global _gpfHttpSetRequestImplIf*/ // Set the http request implementation if the host matches
/*#endif*/

/**
 * Mocked response callback
 *
 * @callback gpf.typedef.mockedResponseCallback
 *
 * @param {gpf.typedef.httpRequestSettings} HTTP request settings
 * @param {...String} captured Regular expression capturing group values
 * @return {Promise<gpf.typedef.httpRequestResponse>|undefined}
 * @since 0.2.2
 */

/**
 * Definition of a mocked request
 *
 * @typedef gpf.typedef.mockedRequest
 * @property {gpf.http.methods} method HTTP method to mock
 * @property {RegExp} url Regular expression matching the URL to mock
 * @property {gpf.typedef.mockedResponseCallback} response Function that generates response when mocking applies
 * @since 0.2.2
 */

/**
 * Mocked request identifier
 *
 * @typedef gpf.typedef.mockedRequestID
 * @since 0.2.2
 */

/**
 * Maps request method to an array of mocked requests
 *
 * @type {Object}
 * @since 0.2.2
 */
var _gpfHttpMockedRequests = {};

function _gpfHttMockPromisify (value) {
    if (undefined !== value) {
        return Promise.resolve(value);
    }
}

/**
 * Match the provided request with the mocked one
 *
 * @param {gpf.typedef.mockedRequest} mockedRequest Mocked request to match
 * @return {Promise<gpf.typedef.httpRequestResponse>|undefined} undefined if not matching
 * @this {gpf.typedef.httpRequestSettings}
 * @since 0.2.2
 */
function _gpfHttMockMatchRequest (mockedRequest) {
    /*jshint validthis:true*/
    var url = mockedRequest.url,
        match;
    url.lastIndex = 0;
    match = url.exec(this.url);
    if (match) {
        return _gpfHttMockPromisify(mockedRequest.response.apply(null, [this].concat([].slice.call(match, 1))));
    }
}

/**
 * Match the provided request to the list of mocked ones
 *
 * @param {gpf.typedef.mockedRequest[]} mockedRequests List of mocked requests for the given method
 * @param {gpf.typedef.httpRequestSettings} request Request to match
 * @return {Promise<gpf.typedef.httpRequestResponse>|undefined} undefined if no mocked request matches
 * @since 0.2.2
 */
function _gpfHttMockMatch (mockedRequests, request) {
    return _gpfArrayForEachFalsy(mockedRequests, _gpfHttMockMatchRequest.bind(request));
}

/**
 * Check if the provided request match any of the mocked one
 *
 * @param {gpf.typedef.httpRequestSettings} request Request to check
 * @return {Promise<gpf.typedef.httpRequestResponse>|undefined} undefined if no mocked request matches
 * @since 0.2.2
 */
function _gpfHttpMockCheck (request) {
    return _gpfHttMockMatch(_gpfHttpMockedRequests[request.method], request);
}

var _gpfHttpMockLastId = 0;

/**
 * Add a mocked request
 *
 * @param {gpf.typedef.mockedRequest} definition Mocked request definition
 * @return {gpf.typedef.mockedRequestID} Mocked request identifier, to be used with {@link gpf.http.mock.remove}
 * @see gpf.http
 * @since 0.2.2
 */
function _gpfHttpMockAdd (definition) {
    var method = definition.method,
        id;
    ++_gpfHttpMockLastId;
    id = method + "." + _gpfHttpMockLastId;
    _gpfHttpMockedRequests[method].unshift(Object.assign({
        method: method,
        id: id
    }, definition));
    return id;
}

/**
 * Removes a mocked request
 *
 * @param {gpf.typedef.mockedRequestID} id Mocked request identifier returned by {@link gpf.http.mock}
 * @since 0.2.2
 */
function _gpfHttpMockRemove (id) {
    var method = id.split(".")[0];
    _gpfHttpMockedRequests[method] = _gpfHttpMockedRequests[method].filter(function (mockedRequest) {
        return mockedRequest.id !== id;
    });
}

/**
 * Clears all mocked requests
 * @since 0.2.2
 */
function _gpfHttpMockReset () {
    Object.keys(_GPF_HTTP_METHODS).forEach(function (method) {
        _gpfHttpMockedRequests[method] = [];
    });
}

_gpfHttpMockReset();

/**
 * @gpf:sameas _gpfHttpMockAdd
 * @since 0.2.2
 */
gpf.http.mock = _gpfHttpMockAdd;

/**
 * @gpf:sameas _gpfHttpMockRemove
 * @since 0.2.2
 */
gpf.http.mock.remove = _gpfHttpMockRemove;

/**
 * @gpf:sameas _gpfHttpMockReset
 * @since 0.2.2
 */
gpf.http.mock.reset = _gpfHttpMockReset;

// Hook the mocking algorithm on top of host specific implementation

debugger;

var _gpfHttpMockRequestImpl;

function _gpfHttpMockImpl (request) {
    return _gpfHttpMockCheck(request) || _gpfHttpMockRequestImpl(request);
}

_gpfHttpMockRequestImpl = _gpfHttpSetRequestImplIf(_gpfHost, _gpfHttpMockImpl);
<commit_msg>New mocking hook (#252)<commit_after>/**
 * @file HTTP mocking
 * @since 0.2.2
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HTTP_METHODS*/ // HTTP Methods
/*global _gpfHost*/ // Host type
/*global _gpfHttpSetRequestImplIf*/ // Set the http request implementation if the host matches
/*#endif*/

/**
 * Mocked response callback
 *
 * @callback gpf.typedef.mockedResponseCallback
 *
 * @param {gpf.typedef.httpRequestSettings} HTTP request settings
 * @param {...String} captured Regular expression capturing group values
 * @return {Promise<gpf.typedef.httpRequestResponse>|undefined}
 * @since 0.2.2
 */

/**
 * Definition of a mocked request
 *
 * @typedef gpf.typedef.mockedRequest
 * @property {gpf.http.methods} method HTTP method to mock
 * @property {RegExp} url Regular expression matching the URL to mock
 * @property {gpf.typedef.mockedResponseCallback} response Function that generates response when mocking applies
 * @since 0.2.2
 */

/**
 * Mocked request identifier
 *
 * @typedef gpf.typedef.mockedRequestID
 * @since 0.2.2
 */

/**
 * Maps request method to an array of mocked requests
 *
 * @type {Object}
 * @since 0.2.2
 */
var _gpfHttpMockedRequests = {};

/**
 * Match the provided request with the mocked one
 *
 * @param {gpf.typedef.mockedRequest} mockedRequest Mocked request to match
 * @param {gpf.typedef.httpRequestSettings} request Request to match
 * @return {Promise<gpf.typedef.httpRequestResponse>|undefined} undefined if not matching
 * @since 0.2.2
 */
function _gpfHttMockMatchRequest (mockedRequest, request) {
    var url = mockedRequest.url,
        match;
    url.lastIndex = 0;
    match = url.exec(request.url);
    if (match) {
        return mockedRequest.response.apply(mockedRequest, [request].concat([].slice.call(match, 1)));
    }
}

/**
 * Match the provided request to the list of mocked ones
 *
 * @param {gpf.typedef.mockedRequest[]} mockedRequests List of mocked requests for the given method
 * @param {gpf.typedef.httpRequestSettings} request Request to match
 * @return {Promise<gpf.typedef.httpRequestResponse>|undefined} undefined if no mocked request matches
 * @since 0.2.2
 */
function _gpfHttMockMatch (mockedRequests, request) {
    var result;
    mockedRequests.every(function (mockedRequest) {
        result = _gpfHttMockMatchRequest(mockedRequest, request);
        return result === undefined;
    });
    return result;
}

/**
 * Check if the provided request match any of the mocked one
 *
 * @param {gpf.typedef.httpRequestSettings} request Request to check
 * @return {Promise<gpf.typedef.httpRequestResponse>|undefined} undefined if no mocked request matches
 * @since 0.2.2
 */
function _gpfHttpMockCheck (request) {
    return _gpfHttMockMatch(_gpfHttpMockedRequests[request.method], request);
}

var _gpfHttpMockLastId = 0;

/**
 * Add a mocked request
 *
 * @param {gpf.typedef.mockedRequest} definition Mocked request definition
 * @return {gpf.typedef.mockedRequestID} Mocked request identifier, to be used with {@link gpf.http.mock.remove}
 * @see gpf.http
 * @since 0.2.2
 */
function _gpfHttpMockAdd (definition) {
    var method = definition.method,
        id;
    ++_gpfHttpMockLastId;
    id = method + "." + _gpfHttpMockLastId;
    _gpfHttpMockedRequests[method].unshift(Object.assign({
        id: id
    }, definition));
    return id;
}

/**
 * Removes a mocked request
 *
 * @param {gpf.typedef.mockedRequestID} id Mocked request identifier returned by {@link gpf.http.mock}
 * @since 0.2.2
 */
function _gpfHttpMockRemove (id) {
    var method = id.split(".")[0];
    _gpfHttpMockedRequests[method] = _gpfHttpMockedRequests[method].filter(function (mockedRequest) {
        return mockedRequest.id !== id;
    });
}

/**
 * Clears all mocked requests
 * @since 0.2.2
 */
function _gpfHttpMockReset () {
    Object.keys(_GPF_HTTP_METHODS).forEach(function (method) {
        _gpfHttpMockedRequests[method] = [];
    });
}

_gpfHttpMockReset();

/**
 * @gpf:sameas _gpfHttpMockAdd
 * @since 0.2.2
 */
gpf.http.mock = _gpfHttpMockAdd;

/**
 * @gpf:sameas _gpfHttpMockRemove
 * @since 0.2.2
 */
gpf.http.mock.remove = _gpfHttpMockRemove;

/**
 * @gpf:sameas _gpfHttpMockReset
 * @since 0.2.2
 */
gpf.http.mock.reset = _gpfHttpMockReset;

// Hook the mocking algorithm on top of host specific implementation

var _gpfHttpMockRequestImpl;

function _gpfHttpMockImpl (request, resolve, reject) {
    var mockedResult = _gpfHttpMockCheck(request);
    if (undefined === mockedResult) {
        _gpfHttpMockRequestImpl(request, resolve, reject);
    } else {
        resolve(mockedResult);
    }
}

_gpfHttpMockRequestImpl = _gpfHttpSetRequestImplIf(_gpfHost, _gpfHttpMockImpl);
<|endoftext|>


<commit_before>/*
 * freepano - WebGL panorama viewer
 *
 * Copyright (c) 2015 FOXEL SA - http://foxel.ch
 * Please read <http://foxel.ch/license> for more information.
 *
 *
 * Author(s):
 *
 *      Luc Deschenaux <l.deschenaux@foxel.ch>
 *
 *
 * This file is part of the FOXEL project <http://foxel.ch>.
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Additional Terms:
 *
 *      You are required to preserve legal notices and author attributions in
 *      that material or in the Appropriate Legal Notices displayed by works
 *      containing it.
 *
 *      You are required to attribute the work as explained in the "Usage and
 *      Attribution" section of <http://foxel.ch/license>.
 */

function PointCloud(options) {
  if (!(this instanceof PointCloud)) {
    return new PointCloud(options);
  }
  $.extend(true,this,{},this.defaults,options);
  this.init();
}

$.extend(true,PointCloud.prototype,{

  defaults: {

    overlay: true,

    // paramaeters for converting panorama url to pointcloud json url
    urlReplace: {
      replaceThis: new RegExp(/\/pyramid\/.*/),
      replaceWithThis: '/pointcloud/',
      suffix: '-freepano.json'
    },

    // point cloud dot material
    dotMaterial: new THREE.PointCloudMaterial({
        map: THREE.ImageUtils.loadTexture('img/dot.png'),
        size: 0.15,
        color: 'yellow',
        sizeAttenuation: true,
        transparent: true,
        opacity: 0.8,
        alphaTest: 0.1,
        depthTest: false,
        depthWrite: false
    }), // pointCloud.defaults.dotMaterial

   // generate particle positions array from json
    parseJSON: function parseJSON(json) {

      var pointCloud=this;
      var panorama=pointCloud.panorama;

      var positions = new Float32Array(json.points.length * 3);

      var v=new THREE.Vector3();
      var Xaxis=new THREE.Vector3(1,0,0);
      var Yaxis=new THREE.Vector3(0,1,0);

      console.log('parsing cloud... ('+json.points.length+' points)');
      var i=0;

      // for each point defined in the json
      json.points.forEach(function(point,index) {
        // initialize vector at z = sphere radius
        v.x=0;
        v.y=0;
        v.z=1;

        // apply rotations
        v.applyAxisAngle(Xaxis,point[1]);
        v.applyAxisAngle(Yaxis,point[0]);

        // store position
        positions[i]=-v.x*point[2];
        positions[i+1]=v.y*point[2];
        positions[i+2]=v.z*point[2];
        i+=3;

      });
      console.log('parsing cloud... done');

      return positions;

    }, // pointCloud.defaults.parseJSON

    // sort point cloud particles by depth
    sortParticles: true,

    // raycaster options
    raycaster: {
      threshold: 0.5
    }

  }, // pointCloud.prototype.defaults

  init: function pointCloud_init(){
    var pointCloud=this;

    if (pointCloud.overlay) {
      pointCloud.scene=new THREE.Scene();
    }

    // init raycaster
    if (!(pointCloud.raycaster instanceof THREE.Raycaster)) {
      if (pointCloud.raycaster && pointCloud.raycaster.instance) {
        delete pointCloud.raycaster.instance;
      }
      pointCloud.raycaster.instance=new THREE.Raycaster(pointCloud.raycaster.options);
      pointCloud.raycaster.instance.params.PointCloud.threshold=pointCloud.raycaster.threshold||0.01;
    }

    // load url if any
    if (pointCloud.url) {
      pointCloud.fromURL(pointCloud.url);

    // load json if any
    } else if (pointCloud.json) {
      pointCloud.fromJSON(pointCloud.json);
    }

  }, // pointCloud_init

  // load point cloud json from url
  fromURL: function pointCloud_fromURL(url) {

    var pointCloud=this;
    pointCloud.url=url;

    $.ajax({

      url: pointCloud.url,

      error: function() {
        // trigger pointcloud 'loaderror' event
        pointCloud.dispatch('loaderror',Array.prototype.slice.call(arguments));
      }, // error

      success: function(json){

        // no data available ?
        if (!json.points) {
          // trigger pointcloud 'loaderror' event
          pointCloud.dispatch('loaderror',Array.prototype.slice.call(arguments));
          return;
        }

        // parse point cloud json
        pointCloud.fromJSON(json);

        // trigger pointcloud 'load' event
        pointCloud.dispatch('load');

      } // success

    });  // ajax

  }, // pointCloud_fromURL

  // load point cloud from json
  fromJSON: function pointCloud_fromJSON(json){

    var pointCloud=this;

    // keep json reference
    pointCloud.json=json;

    // instantiate point cloud geometry
    pointCloud.geometry=new THREE.BufferGeometry();

    // extract particles positions from JSON
    var positions=pointCloud.parseJSON(json);

    // add particles to geometry
    pointCloud.geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));

    // instantiate object3D
    pointCloud.object3D=new THREE.PointCloud(pointCloud.geometry,pointCloud.dotMaterial);
    pointCloud.object3D.sortParticles=pointCloud.sortParticles;

  }, // pointCloud_fromJSON

  // pointcloud 'load' event handler
  onload: function pointCloud_onload(e) {

    var pointCloud=this;
    var panorama=pointCloud.panorama;

    // add pointcloud to scene
    var scene=(pointCloud.overlay)?pointCloud.scene:panorama.scene;
    scene.add(pointCloud.object3D);

    panorama.drawScene();

  }, // pointCloud_onload

  // pointcloud 'loaderror' event handler
  onloaderror: function pointCloud_onloaderror(e) {
    throw e;
  }, // onloaderror

  // render pointcloud overlay on "panorama render" event
  on_panorama_render: function pointCloud_on_panorama_render(){

    var panorama=this;
    var pointCloud=panorama.pointCloud.instance;

    if (pointCloud.overlay) {
      panorama.renderer.clearDepth();
      panorama.renderer.render(pointCloud.scene,panorama.camera.instance);
    }

  }, // on_panorama_render

  // trigger pointcloud 'mouseover' event on particle mouseover
  on_panorama_mousemove: function pointCloud_on_panorama_mousemove(e){

    var panorama=this;
    var pointCloud=panorama.pointCloud;

    if (
      !pointCloud ||
      !pointCloud.instance ||
      pointCloud.active===false ||
      !pointCloud.instance.object3D ||
      !pointCloud.instance.object3D.visible
    ) {
      return;
    }

    // compute mouse normalized coordinates
    var canvas=panorama.renderer.domElement;
    var offset=$(canvas).offset();
    var mouse={
      x: ((e.clientX-offset.left) / canvas.width) * 2 - 1,
      y: -((e.clientY-offset.top) / canvas.height) * 2 + 1
    }

    // setup raycaster
    var raycaster=pointCloud.instance.raycaster;
    raycaster.instance.setFromCamera(mouse,panorama.camera.instance);

    // get intersection list
    var intersections=raycaster.instance.intersectObject(pointCloud.instance.object3D);

    // trigger pointcloud mouseover event
    if (intersections.length) {
      pointCloud.instance.dispatch({
          type: 'mouseover',
          target: intersections,
          originalEvent: e
      });
    }

  }, // pointCloud_on_panorama_render

  // snap to nearest intersecting particle
  onmouseover: function on_pointcloud_mouseover(e){

    var pointCloud=this;
    var panorama=pointCloud.panorama;
    var particle_list=e.target;

    panorama.getMouseCoords(e.originalEvent);
    var hover=pointCloud.nearestParticle(panorama.mouseCoords,particle_list);

    var material;
    var cursor=pointCloud.cursor;

    if (!cursor) {
      cursor=pointCloud.cursor={
        material: new THREE.SpriteMaterial({
          map: THREE.ImageUtils.loadTexture('img/dot_hover.png'),
          depthTest: false,
          depthWrite: false

        }),
        geometry: new THREE.Geometry()
      }
      cursor.sprite=new THREE.Sprite(cursor.material);
      pointCloud.scene.add(cursor.sprite);
    }

    cursor.sprite.position.copy(new THREE.Vector3().copy(pointCloud.getParticlePosition(hover.index)).normalize().multiplyScalar(10));
    var scale=0.1/p.getZoom();
    cursor.sprite.scale.set(scale,scale,scale);
    pointCloud.showParticleInfo(hover.index);

    pointCloud.panorama.drawScene();

  }, // pointCloud_onmouseover

  // return particle with least square distance from coords in radians
  nearestParticle: function pointCloud_nearestParticle(coords,particle_list) {
    var pointCloud=this;
    var panorama=pointCloud.panorama;
    var candidate=0;
    var d2min=999;
    var point_list=pointCloud.json.points;

    $.each(particle_list,function(i){

      var point=point_list[this.index];

      // compute absolute angle difference
      var dthe=Math.abs(point[0]-panorama.mouseCoords.theta);
      var dphi=Math.abs(point[1]+panorama.mouseCoords.phi);

      // adjust delta when crossing boundaries
      // (assume distance is less than half image)
      if (dthe>Math.PI) dthe=Math.PI*2-dthe;
      if (dphi>Math.PI/2) dphi=Math.PI-dphi;

      // select least square distance
      var dsquare=dthe*dthe+dphi*dphi;
      if (dsquare<d2min) {
        d2min=dsquare;
        candidate=i;

      // select nearest point on z axis when equidistant from cursor
      } else if (dsquare==d2min) {
        if (point_list[candidate].point[2]>point[2]) {
          candidate=i;
        }
      }

    });

    return particle_list[candidate];

  }, // pointCloud_nearestParticle

  // return particle world coordinates
  getParticlePosition: function pointCloud_getParticlePosition(index) {
    var pointCloud=this;
    var point=pointCloud.json.points[index];

    // initialize vector
    var v=new THREE.Vector3(0,0,1);

    // apply rotations
    v.applyAxisAngle(Xaxis,point[1]);
    v.applyAxisAngle(Yaxis,point[0]);

    // return positions
    return {
      x: -v.x*point[2],
      y: v.y*point[2],
      z: v.z*point[2]
    }
  }, // pointCloud_getParticlePosition

  showParticleInfo: function pointCloud_showParticleInfo(index) {
    var pointCloud=this;
    var point=pointCloud.json.points[index];
    var panorama=pointCloud.panorama;

    var div = $('#particleInfo');
    if (!div.length) {
        div = $('
').appendTo(panorama.container).css({
            position: 'absolute',
            top: 0,
            left: 0,
            width: 128,
            backgroundColor: "rgba(0,0,0,.4)",
            color: 'white'
        });
    }

    var html = '
';
    html += 'Particle info
';
    html += 'theta: ' + point[0].toPrecision(6) + '
';
    html += 'phi: ' + point[1].toPrecision(6) + '
';
    html += 'distance: ' + point[2].toPrecision(6) + '
';
    html += 'index: ' + point[3] + '
';
    div.html(html);

  }, // pointCloud_showParticleInfo

  // instantiate point cloud on panorama_ready
  on_panorama_ready: function pointCloud_on_panorama_ready(e) {

    var panorama=this;

    if (panorama.pointCloud && panorama.pointCloud.active!==false) {

      // get panorama url to pointcloud url conversion details
      var urlReplace=panorama.pointCloud.urlReplace||PointCloud.prototype.defaults.urlReplace;
      var replaceThis=urlReplace.replaceThis;
      var replaceWithThis=urlReplace.replaceWithThis;
      var suffix=urlReplace.suffix;

      // instantiate pointcloud
      var pointCloud=panorama.pointCloud.instance=new PointCloud($.extend(true,{},panorama.pointCloud,{
        panorama: panorama,
        url: panorama.sphere.texture.dirName.replace(replaceThis,replaceWithThis)+p.list.currentImage+suffix
      }));
    }

  }, // pointCloud_on_panorama_ready

  // dispose pointcloud on panorama dispose
  on_panorama_dispose: function pointCloud_on_panorama_dispose(e) {
    var panorama=this;
    if (panorama.pointCloud && panorama.pointCloud.instance) {
      var scene=(panorama.pointCloud.instance.overlay)?panorama.pointCloud.instance.scene:panorama.scene;
      scene.remove(panorama.pointCloud.instance.object3D);
      delete panorama.pointCloud.instance;
    }
  } // pointCloud_on_panorama_dispose

});

setupEventDispatcher(PointCloud.prototype);

// subscribe to panorama events
Panorama.prototype.dispatchEventsTo(PointCloud.prototype);
<commit_msg>updated pointcloud.js particle mouse events<commit_after>/*
 * freepano - WebGL panorama viewer
 *
 * Copyright (c) 2015 FOXEL SA - http://foxel.ch
 * Please read <http://foxel.ch/license> for more information.
 *
 *
 * Author(s):
 *
 *      Luc Deschenaux <l.deschenaux@foxel.ch>
 *
 *
 * This file is part of the FOXEL project <http://foxel.ch>.
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Additional Terms:
 *
 *      You are required to preserve legal notices and author attributions in
 *      that material or in the Appropriate Legal Notices displayed by works
 *      containing it.
 *
 *      You are required to attribute the work as explained in the "Usage and
 *      Attribution" section of <http://foxel.ch/license>.
 */

function PointCloud(options) {
  if (!(this instanceof PointCloud)) {
    return new PointCloud(options);
  }
  $.extend(true,this,{},this.defaults,options);
  this.init();
}

$.extend(true,PointCloud.prototype,{

  defaults: {

    overlay: true,

    // paramaeters for converting panorama url to pointcloud json url
    urlReplace: {
      replaceThis: new RegExp(/\/pyramid\/.*/),
      replaceWithThis: '/pointcloud/',
      suffix: '-freepano.json'
    },

    // point cloud dot material
    dotMaterial: new THREE.PointCloudMaterial({
        map: THREE.ImageUtils.loadTexture('img/dot.png'),
        size: 0.15,
        color: 'yellow',
        sizeAttenuation: true,
        transparent: true,
        opacity: 0.8,
        alphaTest: 0.1,
        depthTest: false,
        depthWrite: false
    }), // pointCloud.defaults.dotMaterial

   // generate particle positions array from json
    parseJSON: function parseJSON(json) {

      var pointCloud=this;
      var panorama=pointCloud.panorama;

      var positions = new Float32Array(json.points.length * 3);

      var v=new THREE.Vector3();
      var Xaxis=new THREE.Vector3(1,0,0);
      var Yaxis=new THREE.Vector3(0,1,0);

      console.log('parsing cloud... ('+json.points.length+' points)');
      var i=0;

      // for each point defined in the json
      json.points.forEach(function(point,index) {
        // initialize vector at z = sphere radius
        v.x=0;
        v.y=0;
        v.z=1;

        // apply rotations
        v.applyAxisAngle(Xaxis,point[1]);
        v.applyAxisAngle(Yaxis,point[0]);

        // store position
        positions[i]=-v.x*point[2];
        positions[i+1]=v.y*point[2];
        positions[i+2]=v.z*point[2];
        i+=3;

      });
      console.log('parsing cloud... done');

      return positions;

    }, // pointCloud.defaults.parseJSON

    // sort point cloud particles by depth
    sortParticles: true,

    // raycaster options
    raycaster: {
      threshold: 0.5
    }

  }, // pointCloud.prototype.defaults

  init: function pointCloud_init(){
    var pointCloud=this;

    if (pointCloud.overlay) {
      pointCloud.scene=new THREE.Scene();
    }

    // init raycaster
    if (!(pointCloud.raycaster instanceof THREE.Raycaster)) {
      if (pointCloud.raycaster && pointCloud.raycaster.instance) {
        delete pointCloud.raycaster.instance;
      }
      pointCloud.raycaster.instance=new THREE.Raycaster(pointCloud.raycaster.options);
      pointCloud.raycaster.instance.params.PointCloud.threshold=pointCloud.raycaster.threshold||0.01;
    }

    // load url if any
    if (pointCloud.url) {
      pointCloud.fromURL(pointCloud.url);

    // load json if any
    } else if (pointCloud.json) {
      pointCloud.fromJSON(pointCloud.json);
    }

  }, // pointCloud_init

  // load point cloud json from url
  fromURL: function pointCloud_fromURL(url) {

    var pointCloud=this;
    pointCloud.url=url;

    $.ajax({

      url: pointCloud.url,

      error: function() {
        // trigger pointcloud 'loaderror' event
        pointCloud.dispatch('loaderror',Array.prototype.slice.call(arguments));
      }, // error

      success: function(json){

        // no data available ?
        if (!json.points) {
          // trigger pointcloud 'loaderror' event
          pointCloud.dispatch('loaderror',Array.prototype.slice.call(arguments));
          return;
        }

        // parse point cloud json
        pointCloud.fromJSON(json);

        // trigger pointcloud 'load' event
        pointCloud.dispatch('load');

      } // success

    });  // ajax

  }, // pointCloud_fromURL

  // load point cloud from json
  fromJSON: function pointCloud_fromJSON(json){

    var pointCloud=this;

    // keep json reference
    pointCloud.json=json;

    // instantiate point cloud geometry
    pointCloud.geometry=new THREE.BufferGeometry();

    // extract particles positions from JSON
    var positions=pointCloud.parseJSON(json);

    // add particles to geometry
    pointCloud.geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));

    // instantiate object3D
    pointCloud.object3D=new THREE.PointCloud(pointCloud.geometry,pointCloud.dotMaterial);
    pointCloud.object3D.sortParticles=pointCloud.sortParticles;

  }, // pointCloud_fromJSON

  // pointcloud 'load' event handler
  onload: function pointCloud_onload(e) {

    var pointCloud=this;
    var panorama=pointCloud.panorama;

    // add pointcloud to scene
    var scene=(pointCloud.overlay)?pointCloud.scene:panorama.scene;
    scene.add(pointCloud.object3D);

    panorama.drawScene();

  }, // pointCloud_onload

  // pointcloud 'loaderror' event handler
  onloaderror: function pointCloud_onloaderror(e) {
    throw e;
  }, // onloaderror

  // render pointcloud overlay on "panorama render" event
  on_panorama_render: function pointCloud_on_panorama_render(){

    var panorama=this;
    if (!panorama.pointCloud) {
      return;
    }

    var pointCloud=panorama.pointCloud.instance;
    if (!pointCloud) {
      return;
    }

    var cursor=pointCloud.cursor;
    if (cursor) {
      var scale=0.1/p.getZoom();
      cursor.sprite.scale.set(scale,scale,scale);
    }

    if (pointCloud.overlay) {
      panorama.renderer.clearDepth();
      panorama.renderer.render(pointCloud.scene,panorama.camera.instance);
    }

    pointCloud.dispatch('render');

  }, // on_panorama_render

  // trigger pointcloud 'particlemouseover' event on particle mouseover
  on_panorama_mousemove: function pointCloud_on_panorama_mousemove(e){

    var panorama=this;
    var pointCloud=panorama.pointCloud;

    if (
      !pointCloud ||
      !pointCloud.instance ||
      pointCloud.active===false ||
      !pointCloud.instance.object3D ||
      !pointCloud.instance.object3D.visible
    ) {
      return;
    }

    // compute mouse normalized coordinates
    var canvas=panorama.renderer.domElement;
    var offset=$(canvas).offset();
    var mouse={
      x: ((e.clientX-offset.left) / canvas.width) * 2 - 1,
      y: -((e.clientY-offset.top) / canvas.height) * 2 + 1
    }

    // setup raycaster
    var raycaster=pointCloud.instance.raycaster;
    raycaster.instance.setFromCamera(mouse,panorama.camera.instance);

    // get intersection list
    var intersections=raycaster.instance.intersectObject(pointCloud.instance.object3D);

    // trigger pointcloud mouseover event
    if (intersections.length) {
      pointCloud.instance.dispatch({
          type: 'particlemouseover',
          target: intersections,
          originalEvent: e
      });
    } else {
      if (pointCloud.hover){
        pointCloud.instance.dispatch({
            type: 'particlemouseout',
            target: pointCloud.hover.index
        });
      }
    }

  }, // pointCloud_on_panorama_render

  // snap to nearest intersecting particle
  onparticlemouseover: function on_pointcloud_particlemouseover(e){

    var pointCloud=this;
    var panorama=pointCloud.panorama;

    var particle_list=e.target;

    // get nearest point index
    panorama.getMouseCoords(e.originalEvent);
    var hover=pointCloud.nearestParticle(panorama.mouseCoords,particle_list);

    // if we were already hovering
    if (pointCloud.hover) {
      // and it was another point
      if (hover.index != pointCloud.hover.index){
        // then trigger 'particlemouseout'
        var e={
            type: 'particlemouseout',
            target: pointCloud.hover.index
        }
        // unless event handler doesnt agree to remove hover attribute
        if (pointCloud.dispatch(e)===false) {
          return false;
        }
      } else {
        // already hovering the same point, return
        return
      }
    }

    // mousein
    pointCloud.hover=hover;

    var material;
    var cursor=pointCloud.cursor;

    // instantiate cursor if needed
    if (!cursor) {
      cursor=pointCloud.cursor={
        material: new THREE.SpriteMaterial({
          map: THREE.ImageUtils.loadTexture('img/dot_hover.png'),
          depthTest: false,
          depthWrite: false

        }),
        geometry: new THREE.Geometry()
      }
      cursor.sprite=new THREE.Sprite(cursor.material);
      pointCloud.scene.add(cursor.sprite);
    }

    cursor.sprite.position.copy(new THREE.Vector3().copy(pointCloud.getParticlePosition(hover.index)).normalize().multiplyScalar(10));

    pointCloud.panorama.drawScene();

    pointCloud.dispatch({
        type: 'particlemousein',
        target: hover.index
    });

  }, // pointCloud_particleonmouseover

  onparticlemousein: function pointCloud_onparticlemousein(e) {
    var pointCloud=this;
    pointCloud.showParticleInfo(pointCloud.hover.index);
  }, // pointCloud_onparticlemousein

  onparticlemouseout: function pointCloud_onparticlemouseout(e) {
    var pointCloud=this;
    pointCloud.hideParticleInfo();
  }, // pointCloud_onparticlemousein

  // return particle with least square distance from coords in radians
  nearestParticle: function pointCloud_nearestParticle(coords,particle_list) {
    var pointCloud=this;
    var panorama=pointCloud.panorama;
    var candidate=0;
    var d2min=999;
    var point_list=pointCloud.json.points;

    $.each(particle_list,function(i){

      var point=point_list[this.index];

      // compute absolute angle difference
      var dthe=Math.abs(point[0]-panorama.mouseCoords.theta);
      var dphi=Math.abs(point[1]+panorama.mouseCoords.phi);

      // adjust delta when crossing boundaries
      // (assume distance is less than half image)
      if (dthe>Math.PI) dthe=Math.PI*2-dthe;
      if (dphi>Math.PI/2) dphi=Math.PI-dphi;

      // select least square distance
      var dsquare=dthe*dthe+dphi*dphi;
      if (dsquare<d2min) {
        d2min=dsquare;
        candidate=i;

      // select nearest point on z axis when equidistant from cursor
      } else if (dsquare==d2min) {
        if (point_list[candidate].point[2]>point[2]) {
          candidate=i;
        }
      }

    });

    return particle_list[candidate];

  }, // pointCloud_nearestParticle

  // return particle world coordinates
  getParticlePosition: function pointCloud_getParticlePosition(index) {
    var pointCloud=this;
    var point=pointCloud.json.points[index];

    // initialize vector
    var v=new THREE.Vector3(0,0,1);

    // apply rotations
    v.applyAxisAngle(Xaxis,point[1]);
    v.applyAxisAngle(Yaxis,point[0]);

    // return positions
    return {
      x: -v.x*point[2],
      y: v.y*point[2],
      z: v.z*point[2]
    }
  }, // pointCloud_getParticlePosition

  showParticleInfo: function pointCloud_showParticleInfo(index) {
    var pointCloud=this;
    var point=pointCloud.json.points[index];
    var panorama=pointCloud.panorama;

    var div = $('#particleInfo');
    if (!div.length) {
        div = $('
').appendTo(panorama.container).css({
            position: 'absolute',
            top: 0,
            left: 0,
            width: 128,
            backgroundColor: "rgba(0,0,0,.4)",
            color: 'white'
        });
    }

    var html = '
';
    html += 'Particle info
';
    html += 'theta: ' + point[0].toPrecision(6) + '
';
    html += 'phi: ' + point[1].toPrecision(6) + '
';
    html += 'distance: ' + point[2].toPrecision(6) + '
';
    html += 'index: ' + point[3] + '
';
    div.html(html);

  }, // pointCloud_showParticleInfo

  hideParticleInfo: function pointCloud_hideParticleInfo(){
    $('#particleInfo').hide(0);
  }, // pointCloud_hideParticleInfo

  // instantiate point cloud on panorama_ready
  on_panorama_ready: function pointCloud_on_panorama_ready(e) {

    var panorama=this;

    if (panorama.pointCloud && panorama.pointCloud.active!==false) {

      // get panorama url to pointcloud url conversion details
      var urlReplace=panorama.pointCloud.urlReplace||PointCloud.prototype.defaults.urlReplace;
      var replaceThis=urlReplace.replaceThis;
      var replaceWithThis=urlReplace.replaceWithThis;
      var suffix=urlReplace.suffix;

      // instantiate pointcloud
      var pointCloud=panorama.pointCloud.instance=new PointCloud($.extend(true,{},panorama.pointCloud,{
        panorama: panorama,
        url: panorama.sphere.texture.dirName.replace(replaceThis,replaceWithThis)+p.list.currentImage+suffix
      }));
    }

  }, // pointCloud_on_panorama_ready

  // dispose pointcloud on panorama dispose
  on_panorama_dispose: function pointCloud_on_panorama_dispose(e) {
    var panorama=this;
    if (panorama.pointCloud && panorama.pointCloud.instance) {
      var scene=(panorama.pointCloud.instance.overlay)?panorama.pointCloud.instance.scene:panorama.scene;
      scene.remove(panorama.pointCloud.instance.object3D);
      delete panorama.pointCloud.instance;
    }
  } // pointCloud_on_panorama_dispose

});

setupEventDispatcher(PointCloud.prototype);

// subscribe to panorama events
Panorama.prototype.dispatchEventsTo(PointCloud.prototype);
<|endoftext|>


<commit_before>/**
 * StudentController
 *
 * @description :: Server-side logic for managing Students
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

module.exports = {
	index: function(req, res) {

	},

	new: function(req, res) {

	},

	create: function(req, res) {

	},

	edit: function(req, res) {

	},

	update: function(req, res) {

	},

	destroy: function(req, res) {

	}
};
<commit_msg>configure index route to render view<commit_after>/**
 * StudentController
 *
 * @description :: Server-side logic for managing Students
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

module.exports = {
	index: function(req, res) {
		Student.find().sort('id ASC').exec(function (err, students) {
			return res.view({ students: students});
		});
	},

	new: function(req, res) {

	},

	create: function(req, res) {

	},

	edit: function(req, res) {

	},

	update: function(req, res) {

	},

	destroy: function(req, res) {

	}
};
<|endoftext|>


<commit_before>var ko = require('knockout')
require('knockout.validation') // No variable here is deliberate!

var apiRoutes = require('../../../api')
var postApi = require('../../../post-api-data')
var browser = require('../../../browser')
var supportedCities = require('../../../location/supportedCities')

import { categories } from '../../../../data/generated/need-categories'

var OfferItemModel = function (currCityId) {
  var self = this

  self.isSubmitted = ko.observable(false)
  self.isSuccess = ko.observable(false)

  ko.validation.init({
    insertMessages: true,
    decorateInputElement: true,
    parseInputAttributes: true,
    errorMessageClass: 'form__error',
    errorElementClass: 'form__input--error'
  }, true)

  self.firstName = ko.observable('').extend({ required: true })
  self.lastName = ko.observable('').extend({ required: true })
  self.email = ko.observable('').extend({ required: true })
  self.telephone = ko.observable('')
  self.city = ko.observable(currCityId)
  self.isManchester = ko.computed(function () {
    return self.city() === 'manchester'
  }, self)
  self.cities = supportedCities.locations
  self.cities.push({
    id: '',
    name: 'Other'
  })
  self.postcode = ko.observable('').extend({ required: true })
  self.description = ko.observable('').extend({ required: true })
  self.additionalInfo = ko.observable('')

  self.categories = ko.observableArray()
  self.selectedCategories = ko.computed(function () {
    return self.categories()
      .filter((c) => c.isChecked())
      .map((c) => c.key)
  }, self)

  self.otherCategory = ko.observable('').extend({
    required: {
      message: 'Select a category or describe here.',
      onlyIf: function () {
        return self.selectedCategories().length === 0
      }
    }
  })
  self.otherCategoryChecked = ko.computed(function () {
    return self.otherCategory().length > 0
  }, self)
  self.isOptedIn = ko.observable(false)

  self.submitForm = function () {
    if (self.errors().length === 0) {
      browser.loading()
      var payload = {
        'FirstName': self.firstName(),
        'LastName': self.lastName(),
        'Email': self.email(),
        'Telephone': self.telephone(),
        'City': self.city(),
        'Postcode': self.postcode(),
        'Description': self.description(),
        'AdditionalInfo': self.additionalInfo(),
        'SelectedCategories': self.selectedCategories(),
        'IsOptedIn': self.isOptedIn(),
        'OtherCategory': self.otherCategory()
      }

      postApi.post(apiRoutes.createOfferOfItems, payload)
        .then(function (result) {
          self.isSubmitted(true)
          browser.loaded()
          if (result.statusCode.toString().charAt(0) !== '2') {
            self.isSuccess(false)
            browser.scrollTo('.requests-detail__heading--i-want-to-volunteer')
          } else {
            self.isSuccess(true)
            browser.scrollTo('.requests-detail__heading--i-want-to-volunteer')
          }
        }, () => {
          browser.redirect('/500/')
        })
    } else {
      self.errors.showAllMessages()

      browser.scrollTo('#js-form')
    }
  }

  self.errors = ko.validation.group(self)

  self.init = () => {
    categories.forEach((c) => {
      c.isChecked = ko.observable(false)
    })
    self.categories(categories)
  }

  self.init()
}

module.exports = OfferItemModel
<commit_msg>Add required field city to Offer Items (#628)<commit_after>var ko = require('knockout')
require('knockout.validation') // No variable here is deliberate!

var apiRoutes = require('../../../api')
var postApi = require('../../../post-api-data')
var browser = require('../../../browser')
var supportedCities = require('../../../location/supportedCities')

import { categories } from '../../../../data/generated/need-categories'

var OfferItemModel = function (currCityId) {
  var self = this

  self.isSubmitted = ko.observable(false)
  self.isSuccess = ko.observable(false)

  ko.validation.init({
    insertMessages: true,
    decorateInputElement: true,
    parseInputAttributes: true,
    errorMessageClass: 'form__error',
    errorElementClass: 'form__input--error'
  }, true)

  self.firstName = ko.observable('').extend({ required: true })
  self.lastName = ko.observable('').extend({ required: true })
  self.email = ko.observable('').extend({ required: true })
  self.telephone = ko.observable('')
  self.city = ko.observable(currCityId).extend({ required: true })
  self.isManchester = ko.computed(function () {
    return self.city() === 'manchester'
  }, self)
  self.cities = supportedCities.locations
  self.cities.push({
    id: '',
    name: 'Other'
  })
  self.postcode = ko.observable('').extend({ required: true })
  self.description = ko.observable('').extend({ required: true })
  self.additionalInfo = ko.observable('')

  self.categories = ko.observableArray()
  self.selectedCategories = ko.computed(function () {
    return self.categories()
      .filter((c) => c.isChecked())
      .map((c) => c.key)
  }, self)

  self.otherCategory = ko.observable('').extend({
    required: {
      message: 'Select a category or describe here.',
      onlyIf: function () {
        return self.selectedCategories().length === 0
      }
    }
  })
  self.otherCategoryChecked = ko.computed(function () {
    return self.otherCategory().length > 0
  }, self)
  self.isOptedIn = ko.observable(false)

  self.submitForm = function () {
    if (self.errors().length === 0) {
      browser.loading()
      var payload = {
        'FirstName': self.firstName(),
        'LastName': self.lastName(),
        'Email': self.email(),
        'Telephone': self.telephone(),
        'City': self.city(),
        'Postcode': self.postcode(),
        'Description': self.description(),
        'AdditionalInfo': self.additionalInfo(),
        'SelectedCategories': self.selectedCategories(),
        'IsOptedIn': self.isOptedIn(),
        'OtherCategory': self.otherCategory()
      }

      postApi.post(apiRoutes.createOfferOfItems, payload)
        .then(function (result) {
          self.isSubmitted(true)
          browser.loaded()
          if (result.statusCode.toString().charAt(0) !== '2') {
            self.isSuccess(false)
            browser.scrollTo('.requests-detail__heading--i-want-to-volunteer')
          } else {
            self.isSuccess(true)
            browser.scrollTo('.requests-detail__heading--i-want-to-volunteer')
          }
        }, () => {
          browser.redirect('/500/')
        })
    } else {
      self.errors.showAllMessages()

      browser.scrollTo('#js-form')
    }
  }

  self.errors = ko.validation.group(self)

  self.init = () => {
    categories.forEach((c) => {
      c.isChecked = ko.observable(false)
    })
    self.categories(categories)
  }

  self.init()
}

module.exports = OfferItemModel
<|endoftext|>


<commit_before>var api_url = "http://www.hpi.uni-potsdam.de/hirschfeld/bachelorprojects/2013H1/api/";
var simulation_api_url = "http://www.hpi.uni-potsdam.de/hirschfeld/bachelorprojects/2013H1/simulation/";

var device_data = null;
var device_id = null;
var range_start = new Date().getTime()-24*2*60*60*1000;
var range_end = new Date().getTime();

// simulation-related
var bhkw_info = null;
var hs_info = null;
var rad_info = null;
var electric_consumer_info = null;
var plb_info = null;

$(document).ready(function(){
    // Login events
    $("#login_submit").click(login_user());
    $("#login_username").keypress(function(e) {
        if(e.which == 13) {
            login_user();
        }
    });
    $("#login_password").keypress(function(e) {
        if(e.which == 13) {
            login_user();
        }
    });

    $("#logout").click(function(event) {
        $.ajax({
            type: "POST",
            url: api_url + "logout/",
            crossDomain: true,
            xhrFields: {
              withCredentials: true
            }
        }).done(show_login_box());
    });

    // navigation items
    $("#home_button").click(function(event) {
        hide_all();
        $("#home").fadeIn();
    });

    $("#simulation_button").click(function(event) {
        hide_all();
        $("#simulation").fadeIn();

        $.getJSON( simulation_api_url + "device/0/info", function( data ) {
            bhkw_info = data;
        });
        $.getJSON( simulation_api_url + "device/1/info", function( data ) {
            hs_info = data;
        });
        $.getJSON( simulation_api_url + "device/2/info", function( data ) {
            rad_info = data;
        });
        $.getJSON( simulation_api_url + "device/3/info", function( data ) {
            electric_consumer_info = data;
        });
        $.getJSON( simulation_api_url + "device/4/info", function( data ) {
            plb_info = data;
        });

        setInterval(function(){
            refresh_simulation();
        }, 1000);

    });

    // load simulation svg
    $.get( "./static/img/demo.svg", function( data ) {
        var svg_item = document.importNode(data.documentElement,true);
        $("#simulation_container").append(svg_item);
    }, "xml");

    check_login_status();
});

function check_login_status(){
    $.ajax({
       url: api_url + "status/",
       xhrFields: {
          withCredentials: true
       }
    }).done(function( data ) {
        if(data['login']=="active"){
            $("#nav_username").text(data['user']);
            login_successful();
        } else {
            show_login_box();
        }
    });
}

function show_login_box(){
    // clean input fields
    $("#login_username").val('');
    $("#login_password").val('');
    $("#login_error").html('');
    // show modal box
    $('#login_box').modal({
        backdrop: 'static'
    });
}

function hide_all(){
    $("#home").hide();
    $("#devices").hide();
    $("#simulation").hide();
}

function login_user() {
    $.ajax({
        type: "POST",
        url: api_url + "login/",
        data: { username: $("#login_username").val(), password: $("#login_password").val(), },
        crossDomain: true,
        xhrFields: {
          withCredentials: true
        }
    }).done(function(data) {
        if(data['login']=="successful"){
            $("#nav_username").text(data['user']);
            login_successful();
        }else{
            login_failed();
        }
    });
}

function login_successful(){
    // get devices
    $.ajax({
       url: api_url + "devices/",
       xhrFields: {
          withCredentials: true
       }
    }).done(function( data ) {
        device_data = data;
        device_data.push({"id":9999,"name":"Simulation"});
        $("#device_list").html(''); // clear device list
        $.each(device_data, function(index, value){
            $("#device_list").append('
' + value['name'] + '
');
        });
    });

    hide_all();
    $('#login_box').modal('hide');
    $('#footer').fadeIn();
    $("#home").fadeIn();
}

function login_failed(){
    $('#login_error').html('
Login details invalid.
');
}

function show_device(id, device_name) {
    device_id = id;

    hide_all();

    $("#refresh_button").click(function(event) {
        range_end = new Date().getTime();
        $("#sensor_selection").html('');
        prepare_diagram();
    });

    $("#devices").fadeIn();
    $("#device_name").text(device_name);

    $("#diagram_container").html('');
    $("#sensor_selection").html('');

    if(id == 9999){
        prepare_simulation_diagram();
    }else{
        prepare_diagram(device_id);
    }
}

function prepare_simulation_diagram(){
    $.ajax({
       url: api_url + "device/1/entries/start/" + range_start + "/end/" + range_end + "/",
       xhrFields: {
          withCredentials: true
       }
    }).done(function(data0){
        $.ajax({
           url: api_url + "device/3/entries/start/" + range_start + "/end/" + range_end + "/",
           xhrFields: {
              withCredentials: true
           }
        }).done(function(data1){
            $.ajax({
               url: api_url + "device/4/entries/start/" + range_start + "/end/" + range_end + "/",
               xhrFields: {
                  withCredentials: true
               }
            }).done(function(data2){
                $.ajax({
                   url: api_url + "device/5/entries/start/" + range_start + "/end/" + range_end + "/",
                   xhrFields: {
                      withCredentials: true
                   }
                }).done(function(data3){
                    $.ajax({
                       url: api_url + "device/6/entries/start/" + range_start + "/end/" + range_end + "/",
                       data: $.extend(data3, dataDetails),
                       xhrFields: {
                          withCredentials: true
                       }
                    }).done(function(data4){
                        $.extend(data0,data1,data2,data3,data4);
                        draw_diagram(data0);
                    });
                });
            });
        });
    });
}

function prepare_diagram(device_id){
    $.ajax({
       url: api_url + "device/" + device_id + "/entries/start/" + range_start + "/end/" + range_end + "/",
       xhrFields: {
          withCredentials: true
       }
    }).done(function(data){draw_diagram(data);});
}

function refresh_simulation(){
    $.getJSON( simulation_api_url + "device/0/get", function( data ) {
        update_simulation(data,"bhkw");
    });
    $.getJSON( simulation_api_url + "device/1/get", function( data ) {
        update_simulation(data,"hs");
    });
    $.getJSON( simulation_api_url + "device/2/get", function( data ) {
        update_simulation(data,"rad");
    });
    $.getJSON( simulation_api_url + "device/3/get", function( data ) {
        update_simulation(data,"elec");
    });
    $.getJSON( simulation_api_url + "device/4/get", function( data ) {
        update_simulation(data,"plb");
    });
}

function update_simulation(data,namespace){
    if($("#simulation").is(":visible")){
        $.each(data, function(item_id, value) {
            var item = $('#' + namespace + "_" + item_id);
            if (item.length) {
                item.text(Math.floor(parseFloat(value)*1000)/1000 + " " + get_unit(item_id, namespace));
            }
        });
    }
}

function get_unit(item_id ,namespace){
    switch(namespace){
        case "bhkw":
            return bhkw_info[item_id];
        case "hs":
            return hs_info[item_id];
        case "rad":
            return rad_info[item_id];
        case "elec":
            return electric_consumer_info[item_id];
        case "plb":
            return plb_info[item_id];
    }
}
<commit_msg>Line removed<commit_after>var api_url = "http://www.hpi.uni-potsdam.de/hirschfeld/bachelorprojects/2013H1/api/";
var simulation_api_url = "http://www.hpi.uni-potsdam.de/hirschfeld/bachelorprojects/2013H1/simulation/";

var device_data = null;
var device_id = null;
var range_start = new Date().getTime()-24*2*60*60*1000;
var range_end = new Date().getTime();

// simulation-related
var bhkw_info = null;
var hs_info = null;
var rad_info = null;
var electric_consumer_info = null;
var plb_info = null;

$(document).ready(function(){
    // Login events
    $("#login_submit").click(login_user());
    $("#login_username").keypress(function(e) {
        if(e.which == 13) {
            login_user();
        }
    });
    $("#login_password").keypress(function(e) {
        if(e.which == 13) {
            login_user();
        }
    });

    $("#logout").click(function(event) {
        $.ajax({
            type: "POST",
            url: api_url + "logout/",
            crossDomain: true,
            xhrFields: {
              withCredentials: true
            }
        }).done(show_login_box());
    });

    // navigation items
    $("#home_button").click(function(event) {
        hide_all();
        $("#home").fadeIn();
    });

    $("#simulation_button").click(function(event) {
        hide_all();
        $("#simulation").fadeIn();

        $.getJSON( simulation_api_url + "device/0/info", function( data ) {
            bhkw_info = data;
        });
        $.getJSON( simulation_api_url + "device/1/info", function( data ) {
            hs_info = data;
        });
        $.getJSON( simulation_api_url + "device/2/info", function( data ) {
            rad_info = data;
        });
        $.getJSON( simulation_api_url + "device/3/info", function( data ) {
            electric_consumer_info = data;
        });
        $.getJSON( simulation_api_url + "device/4/info", function( data ) {
            plb_info = data;
        });

        setInterval(function(){
            refresh_simulation();
        }, 1000);

    });

    // load simulation svg
    $.get( "./static/img/demo.svg", function( data ) {
        var svg_item = document.importNode(data.documentElement,true);
        $("#simulation_container").append(svg_item);
    }, "xml");

    check_login_status();
});

function check_login_status(){
    $.ajax({
       url: api_url + "status/",
       xhrFields: {
          withCredentials: true
       }
    }).done(function( data ) {
        if(data['login']=="active"){
            $("#nav_username").text(data['user']);
            login_successful();
        } else {
            show_login_box();
        }
    });
}

function show_login_box(){
    // clean input fields
    $("#login_username").val('');
    $("#login_password").val('');
    $("#login_error").html('');
    // show modal box
    $('#login_box').modal({
        backdrop: 'static'
    });
}

function hide_all(){
    $("#home").hide();
    $("#devices").hide();
    $("#simulation").hide();
}

function login_user() {
    $.ajax({
        type: "POST",
        url: api_url + "login/",
        data: { username: $("#login_username").val(), password: $("#login_password").val(), },
        crossDomain: true,
        xhrFields: {
          withCredentials: true
        }
    }).done(function(data) {
        if(data['login']=="successful"){
            $("#nav_username").text(data['user']);
            login_successful();
        }else{
            login_failed();
        }
    });
}

function login_successful(){
    // get devices
    $.ajax({
       url: api_url + "devices/",
       xhrFields: {
          withCredentials: true
       }
    }).done(function( data ) {
        device_data = data;
        device_data.push({"id":9999,"name":"Simulation"});
        $("#device_list").html(''); // clear device list
        $.each(device_data, function(index, value){
            $("#device_list").append('
' + value['name'] + '
');
        });
    });

    hide_all();
    $('#login_box').modal('hide');
    $('#footer').fadeIn();
    $("#home").fadeIn();
}

function login_failed(){
    $('#login_error').html('
Login details invalid.
');
}

function show_device(id, device_name) {
    device_id = id;

    hide_all();

    $("#refresh_button").click(function(event) {
        range_end = new Date().getTime();
        $("#sensor_selection").html('');
        prepare_diagram();
    });

    $("#devices").fadeIn();
    $("#device_name").text(device_name);

    $("#diagram_container").html('');
    $("#sensor_selection").html('');

    if(id == 9999){
        prepare_simulation_diagram();
    }else{
        prepare_diagram(device_id);
    }
}

function prepare_simulation_diagram(){
    $.ajax({
       url: api_url + "device/1/entries/start/" + range_start + "/end/" + range_end + "/",
       xhrFields: {
          withCredentials: true
       }
    }).done(function(data0){
        $.ajax({
           url: api_url + "device/3/entries/start/" + range_start + "/end/" + range_end + "/",
           xhrFields: {
              withCredentials: true
           }
        }).done(function(data1){
            $.ajax({
               url: api_url + "device/4/entries/start/" + range_start + "/end/" + range_end + "/",
               xhrFields: {
                  withCredentials: true
               }
            }).done(function(data2){
                $.ajax({
                   url: api_url + "device/5/entries/start/" + range_start + "/end/" + range_end + "/",
                   xhrFields: {
                      withCredentials: true
                   }
                }).done(function(data3){
                    $.ajax({
                       url: api_url + "device/6/entries/start/" + range_start + "/end/" + range_end + "/",
                       xhrFields: {
                          withCredentials: true
                       }
                    }).done(function(data4){
                        $.extend(data0,data1,data2,data3,data4);
                        draw_diagram(data0);
                    });
                });
            });
        });
    });
}

function prepare_diagram(device_id){
    $.ajax({
       url: api_url + "device/" + device_id + "/entries/start/" + range_start + "/end/" + range_end + "/",
       xhrFields: {
          withCredentials: true
       }
    }).done(function(data){draw_diagram(data);});
}

function refresh_simulation(){
    $.getJSON( simulation_api_url + "device/0/get", function( data ) {
        update_simulation(data,"bhkw");
    });
    $.getJSON( simulation_api_url + "device/1/get", function( data ) {
        update_simulation(data,"hs");
    });
    $.getJSON( simulation_api_url + "device/2/get", function( data ) {
        update_simulation(data,"rad");
    });
    $.getJSON( simulation_api_url + "device/3/get", function( data ) {
        update_simulation(data,"elec");
    });
    $.getJSON( simulation_api_url + "device/4/get", function( data ) {
        update_simulation(data,"plb");
    });
}

function update_simulation(data,namespace){
    if($("#simulation").is(":visible")){
        $.each(data, function(item_id, value) {
            var item = $('#' + namespace + "_" + item_id);
            if (item.length) {
                item.text(Math.floor(parseFloat(value)*1000)/1000 + " " + get_unit(item_id, namespace));
            }
        });
    }
}

function get_unit(item_id ,namespace){
    switch(namespace){
        case "bhkw":
            return bhkw_info[item_id];
        case "hs":
            return hs_info[item_id];
        case "rad":
            return rad_info[item_id];
        case "elec":
            return electric_consumer_info[item_id];
        case "plb":
            return plb_info[item_id];
    }
}
<|endoftext|>