18d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// Copyright 2010 Google Inc.
28d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi//
38d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// Licensed under the Apache License, Version 2.0 (the "License");
48d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// you may not use this file except in compliance with the License.
58d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// You may obtain a copy of the License at
68d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi//
78d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi//     http://www.apache.org/licenses/LICENSE-2.0
88d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi//
98d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// Unless required by applicable law or agreed to in writing, software
108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// distributed under the License is distributed on an "AS IS" BASIS,
118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// See the License for the specific language governing permissions and
138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// limitations under the License.
148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi//
158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @fileoverview Render form appropriate for RPC method.
188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @author rafek@google.com (Rafe Kaplan)
198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoivar FORM_VISIBILITY = {
238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  SHOW_FORM: 'Show Form',
248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  HIDE_FORM: 'Hide Form'
258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi};
268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoivar LABEL = {
298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  OPTIONAL: 'OPTIONAL',
308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  REQUIRED: 'REQUIRED',
318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  REPEATED: 'REPEATED'
328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi};
338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoivar objectId = 0;
368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Variants defined in protorpc/messages.py.
408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoivar VARIANT = {
428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  DOUBLE: 'DOUBLE',
438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  FLOAT: 'FLOAT',
448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  INT64: 'INT64',
458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  UINT64: 'UINT64',
468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  INT32: 'INT32',
478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  BOOL: 'BOOL',
488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  STRING: 'STRING',
498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  MESSAGE: 'MESSAGE',
508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  BYTES: 'BYTES',
518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  UINT32: 'UINT32',
528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  ENUM: 'ENUM',
538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  SINT32: 'SINT32',
548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  SINT64: 'SINT64'
558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi};
568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Data structure used to represent a form to data element.
608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {Object} field Field descriptor that form element represents.
618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {Object} container Element that contains field.
628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @return {FormElement} New object representing a form element.  Element
638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     starts enabled.
648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @constructor
658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction FormElement(field, container) {
678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  this.field = field;
688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  this.container = container;
698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  this.enabled = true;
708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Display error message in error panel.
758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {string} message Message to display in panel.
768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction error(message) {
788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $('<div>').appendTo($('#error-messages')).text(message);
798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Display request errors in error panel.
848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {object} XMLHttpRequest object.
858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction handleRequestError(response) {
878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var contentType = response.getResponseHeader('content-type');
888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (contentType == 'application/json') {
898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var response_error = $.parseJSON(response.responseText);
908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var error_message = response_error.error_message;
918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      if (error.state == 'APPLICATION_ERROR' && error.error_name) {
928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          error_message = error_message + ' (' + error.error_name + ')';
938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      }
948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  } else {
958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      error_message = '' + response.status + ': ' + response.statusText;
968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  error(error_message);
998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
1008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
1038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Send JSON RPC to remote method.
1048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {string} path Path of service on originating server to send request.
1058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {string} method Name of method to invoke.
1068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {Object} request Message to send as request.
1078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {function} on_success Function to call upon successful request.
1088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
1098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction sendRequest(path, method, request, onSuccess) {
1108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $.ajax({url: path + '.' + method,
1118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          type: 'POST',
1128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          contentType: 'application/json',
1138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          data: $.toJSON(request),
1148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          dataType: 'json',
1158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          success: onSuccess,
1168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          error: handleRequestError
1178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi         });
1188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
1198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
1228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Create callback that enables and disables field element when associated
1238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * checkbox is clicked.
1248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {Element} checkbox Checkbox that will be clicked.
1258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form element that will be toggled for editing.
1268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {Object} disableMessage HTML element to display in place of element.
1278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @return Callback that is invoked every time checkbox is clicked.
1288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
1298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction toggleInput(checkbox, form, disableMessage) {
1308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  return function() {
1318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    var checked = checkbox.checked;
1328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (checked) {
1338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      buildIndividualForm(form);
1348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      form.enabled = true;
1358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      disableMessage.hide();
1368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    } else {
1378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      form.display.empty();
1388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      form.enabled = false;
1398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      disableMessage.show();
1408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
1418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  };
1428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
1438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
1468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Build an enum field.
1478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form to build element for.
1488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
1498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction buildEnumField(form) {
1508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.descriptor = enumDescriptors[form.field.type_name];
1518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.input = $('<select>').
1528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      appendTo(form.display);
1538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $('<option>').
1558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      appendTo(form.input).attr('value', '').
1568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      text('Select enum');
1578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $.each(form.descriptor.values, function(index, enumValue) {
1588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      option = $('<option>');
1598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      option.
1608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          appendTo(form.input).
1618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          attr('value', enumValue.name).
1628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          text(enumValue.name);
1638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      if (enumValue.number == form.field.default_value) {
1648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        option.attr('selected', 1);
1658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      }
1668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
1678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
1688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
1718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Build nested message field.
1728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form to build element for.
1738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
1748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction buildMessageField(form) {
1758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.table = $('<table border="1">').appendTo(form.display);
1768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  buildMessageForm(form, messageDescriptors[form.field.type_name]);
1778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
1788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
1818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Build boolean field.
1828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form to build element for.
1838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
1848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction buildBooleanField(form) {
1858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.input = $('<input type="checkbox">');
1868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.input[0].checked = Boolean(form.field.default_value);
1878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
1888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
1918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Build text field.
1928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form to build element for.
1938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
1948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction buildTextField(form) {
1958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.input = $('<input type="text">');
1968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.input.
1978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      attr('value', form.field.default_value || '');
1988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
1998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
2028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Build individual input element.
2038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form to build element for.
2048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
2058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction buildIndividualForm(form) {
2068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.required = form.label == LABEL.REQUIRED;
2078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (form.field.variant == VARIANT.ENUM) {
2098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    buildEnumField(form);
2108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  } else if (form.field.variant == VARIANT.MESSAGE) {
2118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    buildMessageField(form);
2128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  } else if (form.field.variant == VARIANT.BOOL) {
2138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    buildBooleanField(form);
2148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  } else {
2158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    buildTextField(form);
2168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
2178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.display.append(form.input);
2198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  // TODO: Handle base64 encoding for BYTES field.
2218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (form.field.variant == VARIANT.BYTES) {
2228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    $("<i>use base64 encoding</i>").appendTo(form.display);
2238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
2248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
2258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
2288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Add repeated field.  This function is called when an item is added
2298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Repeated form element to create item for.
2308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
2318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction addRepeatedFieldItem(form) {
2328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var row = $('<tr>').appendTo(form.display);
2338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  subForm = new FormElement(form.field, row);
2348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.fields.push(subForm);
2358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  buildFieldForm(subForm, false);
2368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
2378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
2408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Build repeated field.  Contains a button that can be used for adding new
2418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * items.
2428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form to build element for.
2438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
2448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction buildRepeatedForm(form) {
2458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.fields = [];
2468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.display = $('<table border="1" width="100%">').
2478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      appendTo(form.container);
2488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var header_row = $('<tr>').appendTo(form.display);
2498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var header = $('<td colspan="3">').appendTo(header_row);
2508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var add_button = $('<button>').text('+').appendTo(header);
2518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  add_button.click(function() {
2538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    addRepeatedFieldItem(form);
2548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
2558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
2568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
2598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Build a form field.  Populates form content with values required by
2608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * all fields.
2618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Repeated form element to create item for.
2628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param allowRepeated {Boolean} Allow display of repeated field.  If set to
2638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     to true, will treat repeated fields as individual items of a repeated
2648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     field and render it as an individual field.
2658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
2668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction buildFieldForm(form, allowRepeated) {
2678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  // All form fields are added to a row of a table.
2688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var inputData = $('<td>');
2698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  // Set name.
2718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (allowRepeated) {
2728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    var nameData = $('<td>');
2738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    nameData.text(form.field.name + ':');
2748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    form.container.append(nameData);
2758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
2768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  // Set input.
2788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.repeated = form.field.label == LABEL.REPEATED;
2798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (allowRepeated && form.repeated) {
2808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    inputData.attr('colspan', '2');
2818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    buildRepeatedForm(form);
2828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  } else {
2838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (!allowRepeated) {
2848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        inputData.attr('colspan', '2');
2858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
2868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    form.display = $('<div>');
2888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    var controlData = $('<td>');
2908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (form.field.label != LABEL.REQUIRED && allowRepeated) {
2918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        form.enabled = false;
2928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var checkbox_id = 'checkbox-' + objectId;
2938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      objectId++;
2948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      $('<label for="' + checkbox_id + '">Enabled</label>').appendTo(controlData);
2958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var checkbox = $('<input id="' + checkbox_id + '" type="checkbox">').appendTo(controlData);
2968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var disableMessage = $('<div>').appendTo(inputData);
2978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      checkbox.change(toggleInput(checkbox[0], form, disableMessage));
2988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    } else {
2998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      buildIndividualForm(form);
3008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
3018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (form.repeated) {
3038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      // TODO: Implement deletion of repeated items.  Needs to delete
3048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      // from DOM and also delete from form model.
3058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
3068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    form.container.append(controlData);
3088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
3098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  inputData.append(form.display);
3118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.container.append(inputData);
3128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
3138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
3168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Top level function for building an entire message form.  Called once at form
3178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * creation and may be called again for nested message fields.  Constructs a
3188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * a table and builds a row for each sub-field.
3198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @params {FormElement} form Form to build message form for.
3208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
3218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction buildMessageForm(form, messageType) {
3228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.fields = [];
3238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  form.descriptor = messageType;
3248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (messageType.fields) {
3258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    $.each(messageType.fields, function(index, field) {
3268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var row = $('<tr>').appendTo(form.table);
3278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var fieldForm = new FormElement(field, row);
3288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      fieldForm.parent = form;
3298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      buildFieldForm(fieldForm, true);
3308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      form.fields.push(fieldForm);
3318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    });
3328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
3338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
3348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
3378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * HTML Escape a string
3388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
3398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction htmlEscape(value) {
3408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (typeof(value) == "string") {
3418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return value
3428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      .replace(/&/g, '&amp;')
3438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      .replace(/>/g, '&gt;')
3448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      .replace(/</g, '&lt;')
3458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      .replace(/"/g, '&quot;')
3468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      .replace(/'/g, '&#39;')
3478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      .replace(/ /g, '&nbsp;');
3488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  } else {
3498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return value;
3508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
3518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
3528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
3558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * JSON formatted in HTML for display to users.  This method recursively calls
3568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * itself to render sub-JSON objects.
3578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {Object} value JSON object to format for display.
3588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {Integer} indent Indentation level for object being displayed.
3598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @return {string} Formatted JSON object.
3608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
3618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction formatJSON(value, indent) {
3628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var indentation = '';
3638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  for (var index = 0; index < indent; ++index) {
3648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    indentation = indentation + '&nbsp;&nbsp;';
3658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
3668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var type = typeof(value);
3678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var result = '';
3698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (type == 'object') {
3718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (value.constructor === Array) {
3728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      result += '[<br>';
3738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      $.each(value, function(index, item) {
3748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        result += indentation + formatJSON(item, indent + 1) + ',<br>';
3758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      });
3768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      result += indentation + ']';
3778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    } else {
3788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      result += '{<br>';
3798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      $.each(value, function(name, item) {
3808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        result += (indentation + htmlEscape(name) + ': ' +
3818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                   formatJSON(item, indent + 1) + ',<br>');
3828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      });
3838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      result += indentation + '}';
3848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
3858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  } else {
3868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    result += htmlEscape(value);
3878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
3888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  return result;
3908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
3918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
3948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Construct array from repeated form element.
3958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form element to build array from.
3968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @return {Array} Array of repeated elements read from input form.
3978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
3988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction fromRepeatedForm(form) {
3998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var values = [];
4008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $.each(form.fields, function(index, subForm) {
4018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    values.push(fromIndividualForm(subForm));
4028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
4038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  return values;
4048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
4058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
4088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Construct value from individual form element.
4098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form element to get value from.
4108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @return {string, Float, Integer, Boolean, object} Value extracted from
4118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     individual field.  The type depends on the field variant.
4128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
4138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction fromIndividualForm(form) {
4148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  switch(form.field.variant) {
4158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  case VARIANT.MESSAGE:
4168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return fromMessageForm(form);
4178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    break;
4188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  case VARIANT.DOUBLE:
4208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  case VARIANT.FLOAT:
4218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return parseFloat(form.input.val());
4228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  case VARIANT.BOOL:
4248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return form.input[0].checked;
4258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    break;
4268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  case VARIANT.ENUM:
4288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  case VARIANT.STRING:
4298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  case VARIANT.BYTES:
4308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return form.input.val();
4318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  default:
4338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    break;
4348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
4358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  return parseInt(form.input.val(), 10);
4368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
4378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
4408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Extract entire message from a complete form.
4418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {FormElement} form Form to extract message from.
4428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @return {Object} Fully populated message object ready to transmit
4438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     as JSON message.
4448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
4458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction fromMessageForm(form) {
4468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var message = {};
4478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $.each(form.fields, function(index, subForm) {
4488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (subForm.enabled) {
4498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var subMessage = undefined;
4508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      if (subForm.field.label == LABEL.REPEATED) {
4518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        subMessage = fromRepeatedForm(subForm);
4528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      } else {
4538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        subMessage = fromIndividualForm(subForm);
4548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      }
4558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      message[subForm.field.name] = subMessage;
4578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
4588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
4598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  return message;
4618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
4628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
4658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Send form as an RPC.  Extracts message from root form and transmits to
4668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * originating ProtoRPC server.  Response is formatted as JSON and displayed
4678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * to user.
4688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
4698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction sendForm() {
4708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $('#error-messages').empty();
4718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $('#form-response').empty();
4728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  message = fromMessageForm(root_form);
4738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (message === null) {
4748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return;
4758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
4768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  sendRequest(servicePath, methodName, message, function(response) {
4788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    $('#form-response').html(formatJSON(response, 0));
4798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    hideForm();
4808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
4818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
4828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
4858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Reset form to original state.  Deletes existing form and rebuilds a new
4868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * one from scratch.
4878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
4888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction resetForm() {
4898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var panel = $('#form-panel');
4908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var serviceType = serviceMap[servicePath];
4918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var service = serviceDescriptors[serviceType];
4928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  panel.empty();
4948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  function formGenerationError(message) {
4968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    error(message);
4978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    panel.html('<div class="error-message">' +
4988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi               'There was an error generating the service form' +
4998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi               '</div>');
5008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
5018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    // Find method.
5038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var requestTypeName = null;
5048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $.each(service.methods, function(index, method) {
5058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (method.name == methodName) {
5068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        requestTypeName = method.request_type;
5078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
5088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
5098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (!requestTypeName) {
5118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    formGenerationError('No such method definition for: ' + methodName);
5128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return;
5138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
5148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  requestType = messageDescriptors[requestTypeName];
5168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (!requestType) {
5178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    formGenerationError('No such message-type: ' + requestTypeName);
5188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return;
5198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
5208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var root = $('<table border="1">').
5228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      appendTo(panel);
5238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  root_form = new FormElement(null, null);
5258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  root_form.table = root;
5268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  buildMessageForm(root_form, requestType);
5278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $('<button>').appendTo(panel).text('Send Request').click(sendForm);
5288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $('<button>').appendTo(panel).text('Reset').click(resetForm);
5298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
5308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
5338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Hide main RPC form from user.  The information in the form is preserved.
5348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Called after RPC to server is completed.
5358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
5368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction hideForm() {
5378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var expander = $('#form-expander');
5388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var formPanel = $('#form-panel');
5398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  formPanel.hide();
5408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  expander.text(FORM_VISIBILITY.SHOW_FORM);
5418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
5428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
5458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Toggle the display of the main RPC form.  Called when form expander button
5468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * is clicked.
5478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
5488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction toggleForm() {
5498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var expander = $('#form-expander');
5508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var formPanel = $('#form-panel');
5518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (expander.text() == FORM_VISIBILITY.HIDE_FORM) {
5528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    hideForm();
5538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  } else {
5548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    formPanel.show();
5558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    expander.text(FORM_VISIBILITY.HIDE_FORM);
5568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
5578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
5588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
5618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Create form.  Called after all service information and file sets have been
5628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * loaded.
5638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
5648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction createForm() {
5658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $('#form-expander').click(toggleForm);
5668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  resetForm();
5678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
5688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
5718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Display available services and their methods.
5728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
5738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction showMethods() {
5748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var methodSelector = $('#method-selector');
5758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (serviceMap) {
5768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    $.each(serviceMap, function(serviceName) {
5778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var descriptor = serviceDescriptors[serviceMap[serviceName]];
5788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      methodSelector.append(descriptor.name);
5798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var block = $('<blockquote>').appendTo(methodSelector);
5808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      $.each(descriptor.methods, function(index, method) {
5818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        var url = (formPath + '?path=' + serviceName +
5828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                   '&method=' + method.name);
5838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        var label = serviceName + '.' + method.name;
5848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        $('<a>').attr('href', url).text(label).appendTo(block);
5858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        $('<br>').appendTo(block);
5868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      });
5878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    });
5888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
5898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
5908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
5938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Populate map of fully qualified message names to descriptors.  This method
5948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * is called recursively to populate message definitions nested within other
5958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * message definitions.
5968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {Object} messages Array of message descriptors as returned from the
5978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     RegistryService.get_file_set call.
5988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {string} container messages may be an Array of messages nested within
5998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     either a FileDescriptor or a MessageDescriptor.  The container is the
6008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     fully qualified name of the file descriptor or message descriptor so
6018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     that the fully qualified name of the messages in the list may be
6028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *     constructed.
6038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
6048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction populateMessages(messages, container) {
6058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  if (messages) {
6068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    $.each(messages, function(messageIndex, message) {
6078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      var messageName = container + '.' + message.name;
6088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      messageDescriptors[messageName] = message;
6098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      if (message.message_types) {
6118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        populateMessages(message.message_types, messageName);
6128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      }
6138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      if (message.enum_types) {
6158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        $.each(message.enum_types, function(enumIndex, enumerated) {
6168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          var enumName = messageName + '.' + enumerated.name;
6178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          enumDescriptors[enumName] = enumerated;
6188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        });
6198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      }
6208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    });
6218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  }
6228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
6238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
6268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Populates all descriptors from a FileSet descriptor.  Each of the three
6278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * descriptor collections (service, message and enum) map the fully qualified
6288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * name of a definition to it's descriptor.
6298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
6308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction populateDescriptors(file_set) {
6318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  serviceDescriptors = {};
6328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  messageDescriptors = {};
6338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  enumDescriptors = {};
6348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $.each(file_set.files, function(index, file) {
6358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if (file.service_types) {
6368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      $.each(file.service_types, function(serviceIndex, service) {
6378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        var serviceName = file['package'] + '.' + service.name;
6388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        serviceDescriptors[serviceName] = service;
6398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      });
6408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    }
6418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    populateMessages(file.message_types, file['package']);
6438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
6448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
6458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
6488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Load all file sets from ProtoRPC registry service.
6498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {function} when_done Called after all file sets are loaded.
6508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
6518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction loadFileSets(when_done) {
6528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  var paths = [];
6538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  $.each(serviceMap, function(serviceName) {
6548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    paths.push(serviceName);
6558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
6568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  sendRequest(
6588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      registryPath,
6598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      'get_file_set',
6608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      {'names': paths},
6618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      function(response) {
6628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          populateDescriptors(response.file_set, when_done);
6638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          when_done();
6648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  });
6658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
6668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/**
6698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Load all services from ProtoRPC registry service.  When services are
6708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * loaded, will then load all file_sets from the server.
6718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * @param {function} when_done Called after all file sets are loaded.
6728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */
6738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifunction loadServices(when_done) {
6748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi  sendRequest(
6758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      registryPath,
6768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      'services',
6778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      {},
6788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      function(response) {
6798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        serviceMap = {};
6808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        $.each(response.services, function(index, service) {
6818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi          serviceMap[service.name] = service.definition;
6828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        });
6838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        loadFileSets(when_done);
6848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi      });
6858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}
686