$.fn.searchForm = function(board, title, userOptions, callback) {

  // the board needs to be specified for the api calls to work
  if (!board)
    return;

  if (typeof userOptions == 'function') {
    callback = userOptions;
    userOptions = {};
  }
  else if (!userOptions) {
    userOptions = {};
  }

  var $root = $(this);
  var activeTarget = null;
  var formClass = 'container';
  var formAction = '/search_map_results.php';

  var values = {
     bathrooms: [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6]
    ,bedrooms: [0, 1, 2, 3, 4, 5, 6]
    ,price: [
        0, 25000, 50000, 75000, 100000
       ,110000, 120000, 130000, 140000, 150000, 160000, 170000, 180000, 190000, 200000
       ,210000, 220000, 230000, 240000, 250000, 260000, 270000, 280000, 290000, 300000
       ,320000, 340000, 360000, 380000, 400000, 420000, 440000, 460000, 480000, 500000
       ,550000, 600000, 650000, 700000, 750000, 800000, 850000, 900000, 950000, 1000000
       ,1250000, 1500000, 2000000, 2500000, 3000000, 4000000, 5000000, 10000000, 20000000
     ]
    ,propertyClass: { residential: 'Residential', condo: 'Condo', rural: 'Rural', commercial: 'Commercial' }
  };

  var downloadAreas = function(name, callback) { 
    $.ajax({
       url: '/listings/v1/' + board + '/get_zones.json'
      ,success: function(data) {
         values.areas = {};
         $.each(data.zones, function(i, value) {
           values.areas[i] = value.zoneName;
         });
         var options = instructions[name];
         options.values = values.areas;
         buildList(name, options);
         if (typeof callback == 'function') {
           callback();
         }
       }
    });
  };


  var order;
  if (userOptions && userOptions.order) {
    order = userOptions.order;
  }
  else {
  order = {
     property_info: {
        region: { type: 'list', input: 'checkbox', name: 'parea[]', title: 'Area', keys: true, dataCallback: downloadAreas }
       ,neighbourhood: { type: 'list', input: 'checkbox', name: 'form_LOC_SUBAREA[]', title: 'All Neighborhoods' }
       ,prop_type: { type: 'list', input: 'checkbox', name: 'property_class[]', title: 'Property Types', keys: true, values: values.propertyClass }
       ,advanced: { type: 'toggleLink', content: 'Advanced<br/>Search (+)' }
       ,search_button: { type: 'submitButton', content: 'Search Now' }
     }
    ,property_details: {
        min_price: { type: 'list', name: 'PRICE_min', title: '$ Min', fieldFormat: 'number', fieldPrefix: '$', values: values.price }
       ,price_range_separator: { type: 'separator', content: 'to' }
       ,max_price: { type: 'list', name: 'PRICE_max', title: '$ Max', fieldFormat: 'number', fieldPrefix: '$', values: values.price }
       ,beds: { type: 'list', name: 'BEDROOMS_NUM_min', title: 'Bedrooms', titleSuffix: '+ Beds', values: values.bedrooms }
       ,baths: { type: 'list', name: 'BATHROOMS_NUM_min', title: 'Bathrooms', titleSuffix: '+ Baths', values: values.bathrooms }
     }
  };
  }
  var instructions = {};

  var handlerSetup = function() {
    // when a user clicks a field name, display or hide the field
    $('div span.field-title').live('click', function(result) {
      $(this).parent().toggleClass('block');
      var fieldOptions = $(this).parent().children('li');
      if (fieldOptions.css('display') == 'none') {
        fieldOptions.css('display', 'block');
      }
      else {
        fieldOptions.css('display', 'none');
      }
    });

    // custom event to hand indirect checkbox clicks
    $(document).bind('checkboxClicked', function(event) {
      var $checkbox = $(event.target);
      $checkbox.click();
      $checkbox.parent().parent().trigger('processClick');
    });

    // call the click method of the checkbox adjacent to the label that itself was just clicked
    $('ul li label').live('click', function() {
      $checkbox = $(this).siblings('input');
      $checkbox.trigger('checkboxClicked');
    });

    var $listItems = $root.find('li');
    $listItems.live('click', function() {
      var value = $(this).attr('data-value');
      if (value && value != '') {
        var fieldName = $(this).parents('ul.form-field').attr('form-field');
        try {
          var $hiddenField = $root.find('input[name=' + fieldName + ']');
          $hiddenField.val(value);
        } catch (e) {}
      }
      //var $fieldTitle = $(this).parents('ul.form-field').children('span.form-field');
      //$fieldTitle.click();
    });

    $('div.region ul li input[type=checkbox]').live('click', function(result) {
      var areaKey = $(this).val();
      toggleSubareas('neighbourhood', areaKey);
    });

    $('div.prop_type').bind('processClick', function(event) {
      $list = $(event.target);
      $title = $list.parent().find('span.field-title'); 
      $allCheckboxes = $list.find('input[type=checkbox]:checked');
      if ($allCheckboxes.length > 1) {
        $title.html($allCheckboxes.length + ' Property Types');
      }
      else if ($allCheckboxes.length == 1) {
        $soloCheckbox = $($allCheckboxes[0]);
        var label = $soloCheckbox.siblings('label').html();
        if (label) {
          $title.html(label);
        }
      }
      else {
        $title.html('Property Type');
      };
    });

    $('div.region').bind('processClick', function(event) {
      $list = $(event.target);
      $title = $list.parent().find('span.field-title'); 
      $allCheckboxes = $list.find('input[type=checkbox]:checked');
      if ($allCheckboxes.length > 1) {
        $title.html($allCheckboxes.length + ' Regions');
      }
      else if ($allCheckboxes.length == 1) {
        $soloCheckbox = $($allCheckboxes[0]);
        var label = $soloCheckbox.siblings('label').html();
        if (label) {
          $title.html(label);
        }
      }
      else {
        $title.html('Region');
      };
    });

    $('div.neighbourhood').bind('processClick', function(event) {
      $list = $(event.target);
      $title = $list.parent().find('span.field-title'); 
      $allCheckboxes = $list.find('input[type=checkbox]:checked');
      if ($allCheckboxes.length > 1) {
        $title.html($allCheckboxes.length + ' Neighborhoods');
      }
      else if ($allCheckboxes.length == 1) {
        $soloCheckbox = $($allCheckboxes[0]);
        var label = $soloCheckbox.siblings('label').html();
        if (label) {
          $title.html(label);
        }
      }
      else {
        $title.html('All Neighborhoods');
      };
    });

    $('div.field').bind('hideDropdowns', function(event) {
      var $target = $(event.target);
      $target.each(function() {
        if ($(this).hasClass('block')) {
          $(this).removeClass('block');
        }
      });
    });

    $('div.field ul li input[type=checkbox]').live('click', function(result) {
      $(this).parent().parent().trigger('processClick');
    });

    $('body').click(function(event) {
      var $target = $(event.target);
      var $enclosingDiv = $target.parents('div.field');
      var newTarget = $enclosingDiv.attr('data-class') || null;
      if (newTarget && newTarget != '') {
        if (activeTarget != newTarget) {
          $('div.field').trigger('hideDropdowns');
          activeTarget = newTarget;
        }
        // no change if the active and new targets match
      }
      else {
        $('div.field').trigger('hideDropdowns');
        activeTarget = null;
      }
    });

    $('ul.neighbourhood li.parent-neighbourhood input').live('click', function(result) {
      var areaKey = $(this).parent().attr('data-value');
      var $allCheckboxes = $(this).parent().parent().find('li[data-parent-value=' + areaKey + '] input');
      if ($allCheckboxes.length <= 0) {
        return;
      }

      if ($(this).attr('checked') == false) {
        //$allCheckboxes.attr('checked', false);
        $allCheckboxes.each(function() {
          if ($(this).attr('checked') == true) {
            $(this).click();
          }
        });
      }
      else {
        //$allCheckboxes.attr('checked', true);
        $allCheckboxes.each(function() {
          if ($(this).attr('checked') == false) {
            $(this).click();
          }
        });
      }
    });

    $('ul.default-input li').live('click', function() {
      var $spanTitle = $(this).parent().parent().children('span.field-title');
      var newTitle = $(this).html();
      var titleSuffix = $spanTitle.attr('data-title-suffix');
      if (titleSuffix && titleSuffix != '') {
        newTitle += titleSuffix;
      }
      $spanTitle.html(newTitle);
      $spanTitle.parent().removeClass('block');
    });

    $('a.check-all').live('click', function() {
      //$(this).siblings('ul').find('input').attr('checked', true);
      $(this).siblings('ul').find('input').each(function() {
        if ($(this).attr('checked') == false) {
          $(this).click();
        }
      });
      $(this).siblings('ul').trigger('processClick');
    });

    $('a.check-none').live('click', function() {
      //$(this).siblings('ul').find('input').attr('checked', false);
      $(this).siblings('ul').find('input').each(function() {
        if ($(this).attr('checked') == true) {
          $(this).click();
        }
      });
      $(this).siblings('ul').trigger('processClick');
    });

    $('button.search_button').live('click', function() {
      var $searchForm = $(this).parents('form.container');
      if ($searchForm) {
        $searchForm.submit();
      }
    });
  }

  var toggleSubareas = function(name, areaKey) {
    var $subareasList = $('div.' + name + ' ul li[data-parent-value=' + areaKey + ']');
    if ($subareasList && $subareasList.length >= 1) {
      removeSubareas(name, areaKey);
    }
    else {
      getSubareas(name, areaKey);
    }
  }

  var getSubareas = function(name, areaKey) {
    var area = values.areas[areaKey];
    var $spanTitle = $('div.' + name + ' span.field-title');
    $spanTitle.html('Loading...');
    $.ajax({
       url: '/listings/v1/' + board + '/get_communities.json'
      ,data: 'zone=' + area
      ,success: function(data) {
         if (!values.subareas) {
           values.subareas = {};
         }
         values.subareas[area] = [];
         for (var i in data.communities) {
           values.subareas[area][i] = data.communities[i].name;
         };

         var areaSubareasCode = '<li';
         areaSubareasCode += ' class="parent-neighbourhood"';
         areaSubareasCode += ' data-value="' + areaKey + '"';
         if (area.length > 20) {
           var areaName = area.substring(0, 20) + '...';
         }
         else {
           var areaName = area;
         }

         if (board == 'CGY') {
           if (areaName == 'Zone A') {
             var inputCode = '<input type="checkbox" value="' + areaKey + '" name="form_LOC_SUBAREA[]" /><label>North West</label>';
           }
           else if (areaName == 'Zone B') {
             var inputCode = '<input type="checkbox" value="' + areaKey + '" name="form_LOC_SUBAREA[]" /><label>North East</label>';
           }
           else if (areaName == 'Zone C') {
             var inputCode = '<input type="checkbox" value="' + areaKey + '" name="form_LOC_SUBAREA[]" /><label>South West</label>';
            }
           else if (areaName == 'Zone D') {
             var inputCode = '<input type="checkbox" value="' + areaKey + '" name="form_LOC_SUBAREA[]" /><label>South East</label>';
           }
           else {
             var inputCode = '<input type="checkbox" value="' + areaKey + '" name="form_LOC_SUBAREA[]" /><label>' + areaName + '</label>';
           }
         }
         else {
           var inputCode = '<input type="checkbox" value="' + areaKey + '" name="form_LOC_SUBAREA[]" /><label>' + areaName + '</label>';
         }
         areaSubareasCode += '>' + inputCode + '</li>';
         var $areaSubareas = $(areaSubareasCode);
         $('[name=neighbourhood]').append($areaSubareas);

         for (var i in values.subareas[area]) {
           var subareaValue = values.subareas[area][i];
           var areaSubareasCode = '<li';
           areaSubareasCode += ' data-parent-value="' + areaKey + '"';
           areaSubareasCode += ' style="padding-left:15px;"';
           if (subareaValue.length > 20) {
             var subareaName = subareaValue.substring(0, 20) + '...';
           }
           else {
             var subareaName = subareaValue;
           }
           var inputCode = '<input type="checkbox" value="' + subareaValue + '" name="form_LOC_SUBAREA[]" /><label>' + subareaName + '</label>';
           areaSubareasCode += '>' + inputCode + '</li>';
           var $areaSubareas = $(areaSubareasCode);
           $('[name=neighbourhood]').append($areaSubareas);
         } // end foreach values.subareas
         var title = $spanTitle.attr('data-title');
         $spanTitle.html(title);
       }
    });
  }

  var removeSubareas = function(name, areaKey) {
    var area = values.areas[areaKey];
    if (values.subareas && values.subareas[areaKey]) {
      values.subareas[areaKey] = null;
    }

    var $subareaParent = $('div.' + name + ' ul li[data-value=' + areaKey + ']');
    $subareaParent.remove();

    var $subareaList = $('div.' + name + ' ul li[data-parent-value=' + areaKey + ']');
    $subareaList.remove();
  }

  var newField = function(name, title, options) {
    if (typeof options != 'object') {
      var options = {};
    }

    var fieldCode = '<div';
    var styleClass = 'field ' + name;
    fieldCode += ' class="' + styleClass + '"';
    fieldCode += ' data-class=" ' + name + '"';
    fieldCode += '></div>';
    $field = $(fieldCode);

    var titleCode = '<span';
    titleCode += ' class="field-title"';
    titleCode += ' data-title="' + title + '"';
    if (options.titleSuffix && options.titleSuffix != '') {
      titleCode += ' data-title-suffix="' + options.titleSuffix + '"';
    }
    titleCode += '>' + title + '</span>';

    var $title = $(titleCode);
    $field.append($title);

    var listCode = '<ul';
    listCode += ' name="' + name + '"';
    if (options.name && options.name != '') {
      listCode += ' form-field=' + options.name + '"';
    }
    var listStyleClass = 'nostyle form-field ' + name;
    if (options.input && options.input != '') {
      listStyleClass += ' ' + options.input + '-input';
    }
    else {
      listStyleClass += ' default-input';
    }
    listCode += ' class="' + listStyleClass + '"';
    listCode += '></ul>';

    var $list = $(listCode);
    $field.append($list);

    if (typeof options.input != 'undefined' && options.input == 'checkbox') {
      var linkAllCode = '<a';
      linkAllCode += ' href="#"';
      linkAllCode += ' class="check-all"';
      linkAllCode += '>Check All</a>';

      var $linkAll = $(linkAllCode);
      $field.append($linkAll);

      var linkNoneCode = '<a';
      linkNoneCode += ' href="#"';
      linkNoneCode += ' class="check-none"';
      linkNoneCode += '>Check None</a>';

      $linkNone = $(linkNoneCode);
      $field.append($linkNone);
    }

    return $field;
  };


  var newElement = function(type, name, content) {
    var elementCode = '<' + type;
    elementCode += ' class="' + name + '"';
    if (type == 'a') {
      elementCode += ' href="#"';
    }
    elementCode += '>' + content + '</' + type + '>';
    var $element = $(elementCode);
    if (!$element) {
      return null;
    }
    else {
      return $element;
    }
  }

  var buildList = function(listName, options) {
    Number.prototype.numFormat = function(c, d, t){
      var n = this, c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "," : d, t = t == undefined ? "." : t, s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
      return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
    };

    var $list = $('div.' + listName + ' ul');
    if (!$list) {
      return;
    }
    var listValues = options.values || [];
    for (i in listValues) {
      var itemCode = '<li>';
      var value = listValues[i];
      var name;
      var key;

      if (options.names && options.names[i]) {
        name = options.names[i];
      }
      else {
        name = value;
      }

      if (options.fieldFormat && options.fieldFormat == 'number') {
        name = parseInt(name).numFormat(0, '.', ',');
      }
      if (options.fieldPrefix) {
        name = options.fieldPrefix + name;
      }
      if (options.fieldSuffix) {
        name = name + options.fieldSuffix;
      }

      if (typeof options.keys != 'undefined' && options.keys == true) {
        key = i;
      }
      else {
        key = value;
      }

      if (options.input && options.input == 'checkbox') {
        var inputCode = '';
        inputCode += '<input type="checkbox" value="' + key + '" ';
        if (options.name && options.name != '') {
          inputCode += 'name="' + options.name + '" ';
        }
        inputCode += '/>';
        if (board == 'CGY') {
          if (name == 'Zone A') {
            inputCode += '<label>North West</label>';
          }
          else if (name == 'Zone B') {
            inputCode += '<label>North East</label>';
          }
          else if (name == 'Zone C') {
            inputCode += '<label>South West</label>';
          }
          else if (name == 'Zone D') {
            inputCode += '<label>South East</label>';
          }
          else {
            inputCode += '<label>' + name + '</label>';
          }
        }
        else {
          inputCode += '<label>' + name + '</label>';
        }
        var content = inputCode;
      }
      else {
        itemCode += ' data-value="' + key + '"';
        var content = name;
      }
      itemCode += '>' + content + '</li>';
      try {
        var $item = document.createElement(itemCode);
      }
      catch (e) {
        var $item = null;
      }
      if (typeof $item == 'undefined' || $item === null) {
        var $item = document.createElement('li');
      }
      $item.setAttribute('data-value', key);
      $item.innerHTML = content;
      $list.append($($item));
    }
    var $spanTitle = $('div.' + listName + ' span.field-title');
    var title = $spanTitle.attr('data-title');
    $spanTitle.html(title);
  }

  var buildForm = function(board, title, callback) {
    var formCode = '<form';
    if (formClass) {
      formCode += ' class="' + formClass + '"';
    }
    if (formAction) {
      formCode += ' action="' + formAction + '"';
    }
    formCode += '></form>';
    var $form = $(formCode);

    $formTitle = $('<h1>' + title + '</h1>');
    $form.append($formTitle);

    var dataCallbackNames = [];
    var dataCallbackFunctions = [];
    var buildOrder = [];
    for (var i in order) {
      var rowCode = '<div';
      rowCode += ' class="' + i + '"';
      rowCode += '></div>';
      var $row = $(rowCode);

      var fields = order[i];
      for (var j in order[i]) {
        var options = order[i][j];
        instructions[j] = options;
        buildOrder.push(j);
        if (typeof options.dataCallback == 'function' && options.dataInitialize !== false) {
          dataCallbackNames.push(j);
          dataCallbackFunctions.push(options.dataCallback);
        }
        var $element = null;
        if (typeof options.type != 'undefined') {
          if (options.type == 'list') {
            $element = newField(j, options.title, options);
          }
          else if (options.type == 'toggleLink') {
            $element = newElement('a', j, options.content);
          }
          else if (options.type == 'submitButton') {
            $element = newElement('button', j, options.content);
          }
          else if (options.type == 'separator') {
            $element = newElement('em', j, options.content);
          }
        }
        if ($element != null) {
          $row.append($element);
        }
        if (options.input != 'checkbox' && typeof options.name != 'undefined' && options.name != '') {
          var hiddenCode = '<input';
          hiddenCode += ' type="hidden"';
          hiddenCode += ' name="' + options.name + '"';
          hiddenCode += ' />';
          var $hidden = $(hiddenCode);
          $form.append($hidden);
        }
      }

      $form.append($row);
    }
    $root.append($($form));
    for (var name in instructions) {
      var options = instructions[name];
      if (options.values && (options.values.length > 0 || typeof options.values == 'object')) {
        buildList(name, options);
      }
    }
    for (var i in dataCallbackNames) {
      var name = dataCallbackNames[i];
      var $spanTitle = $('div.' + name + ' span.field-title');
      $spanTitle.html('Loading...');
    }
    //handlerSetup();
    if (typeof callback == 'function') {
      callback();
    }
    var dataFunctions = function(names, functions, callback) {
      if (typeof names != 'object' || names.length <= 0 || typeof functions != 'object' || functions.length <= 0) {
        if (typeof callback == 'function') {
          callback();
        }
        return;
      }
      var name = names.shift();
      var fn = functions.shift();
      fn(name, function() {
        dataFunctions(names, functions, callback);
      });
    };
    if (dataCallbackNames.length > 0 && dataCallbackFunctions.length > 0) {
      dataFunctions(dataCallbackNames, dataCallbackFunctions, function() {
        handlerSetup();
        if (typeof postCallback == 'function') {
          postCallback();
        }
      });
    }
  };

  buildForm(board, title, callback);
};

$.fn.searchFormReplace = function(board, options, callback) {
  Number.prototype.numFormat = function(c, d, t){
    var n = this, c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "," : d, t = t == undefined ? "." : t, s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
    return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
  };

  var $root = $(this);
  var data = {
     bathrooms: { values: [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6] }
    ,bedrooms: {  values: [0, 1, 2, 3, 4, 5, 6] }
    ,lot_size: { values: [1.0, 2.0, 3.0, 4.0, 5.0, 7.5, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 75.0, 100.0, 200.0] }
    ,price: {
        values: [
           0, 25000, 50000, 75000, 100000
          ,110000, 120000, 130000, 140000, 150000, 160000, 170000, 180000, 190000, 200000
          ,210000, 220000, 230000, 240000, 250000, 260000, 270000, 280000, 290000, 300000
          ,320000, 340000, 360000, 380000, 400000, 420000, 440000, 460000, 480000, 500000
          ,550000, 600000, 650000, 700000, 750000, 800000, 850000, 900000, 950000, 1000000
          ,1250000, 1500000, 2000000, 2500000, 3000000, 4000000, 5000000, 10000000, 20000000
        ]
     }
    ,propertyClass: {
        values: ['residential', 'condo', 'rural', 'commercial']
       ,names: ['Residential', 'Condo', 'Rural', 'Commercial']
     }
  };

  if (typeof options == 'object' && typeof options.data == 'object') {
    for (var i in options.data) {
      if (typeof options.data[i].values == 'object') {
        data[i] = options.data[i];
      }
    }
  }

  for (var i in data) {
    if (typeof data[i].names == 'undefined' && typeof data[i].values == 'object') {
      data[i].names = [];
      for (var j in data[i].values) {
        var nameIndex = data[i].names.length;
        if (i == 'price') {
          data[i].names[nameIndex] = '$' + parseInt(data[i].values[j]).numFormat(0, '.', ',');
        }
        else if (i == 'lot_size') {
          if (parseInt(data[i].values[j]) == 1) {
            data[i].names[nameIndex] = data[i].values[j] + ' acre';
          }
          else {
            data[i].names[nameIndex] = data[i].values[j] + ' acres';
          }
        }
        else {
          data[i].names[nameIndex] = data[i].values[j];
        }
      }
    }
  }

  var $fields = $(this).find('div.field');
  $fields.each(function() {
    var $this = $(this);
    var dataFieldType = $this.attr('data-field-type');
    var dataFieldName = $this.attr('data-field-name');

    if (!dataFieldType || !dataFieldName) {
      // do not process the element if no type or name is specified
      return;
    }

    if (dataFieldType == 'list') {
      var dataListClass = $this.attr('data-list-class');
      var dataListType = $this.attr('data-list-type') || null;
      var dataListTitle = $this.attr('data-list-title') || dataListClass;
      $this.addClass(dataListClass);
      if (dataListType == 'checkbox') {
        dataFieldName += '[]';
      }
      if (typeof data[dataListClass] == 'object') {
        // add the title of the list
        $listTitle = $('<span class="field-title ' + dataListClass + '" data-title="' + dataListTitle + '">' + dataListTitle + '</span>');
        $this.append($listTitle);
        
        // add the list elements
        $list = $('<ul name="' + dataListClass + '" form-field="' + dataFieldName + '" class="form-field checkbox-input ' + dataListClass + '"></ul>');
        var vals = data[dataListClass].values;
        var names = data[dataListClass].names;
        for (var i in vals) {
          if (dataListType == 'checkbox') {
            var $listItem = $('<li data-value="' + vals[i] + '"></li>');
            $listItem.append('<input type="checkbox" value="' + vals[i] + '" name="' + dataFieldName + '" />');
            $listItem.append('<label>' + names[i] + '</label>');
            $list.append($listItem);
          }
          else {
            var $listItem = $('<li data-value="' + vals[i] + '">' + names[i] + '</li>');
            $list.append($listItem);
          }
        }
        $this.append($list);
        if (dataListType == 'checkbox') {
          // add the check all and none buttons for checkbox lists
          $this.append('<a href="#" class="check-all">Check All</a>');
          $this.append('<a href="#" class="check-none">Check None</a>');
        }
      }
      if (dataListType != 'checkbox') {
        var $hidden = '<input type="hidden" name="' + dataFieldName + '" value="" />';
        $root.append($hidden);
      }
    }
  });

  $root.append('<input type="hidden" name="nosessdata" value="1" />');

  $root.children('div').each(function() {
    $(this).append('<div style="clear:both;"></div>');
  });

  //$(this).find('div.form-row').each(function() {
  //  $(this).append('<div style="clear:both;"></div>');
  //});

  // attach a form that points to the results page
  var action = '/search_map_results.php';
  var $form = $('<form class="widget-container" action="' + action + '"></form>');
  $form.html($(this).html());
  $(this).empty().append($form);

  //var $button = $(this).find('button.submit');
  //$button.live('click', function() {
  //  $form.submit();
  //});

  var generalHandlerSetup = function() {
    if (typeof searchWidgetHandlerSetUp != 'undefined' && searchWidgetHandlerSetUp == true)
      return;

    // when a user clicks a field name, display or hide the field
    $('div span.field-title').live('click', function(result) {
      $(this).parent().toggleClass('block');
      //$(this).parent().toggleClass('hidden-list');
      var $field = $(this).parent().children('ul');

      // adjust the top value
      var fieldTop = parseInt($field.css('top')) || parseInt($field.position().top) || 0;
      var originalTopOffset = $field.offset().top;
      var fieldTopOffset = $(this).offset().top;
      var linkHeight = parseInt($(this).siblings('a.check-all').css('height')) || 0;
      var fieldTopConstOffset = 2;
      var newTopValue = fieldTop + (fieldTopOffset - originalTopOffset) + parseInt($(this).css('height')) + linkHeight + fieldTopConstOffset;
      $field.css('top', newTopValue + 'px');

      // adjust the left value
      var fieldLeft = parseInt($field.css('left')) || parseInt($field.position().left) || 0;
      var originalLeftOffset = $field.offset().left;
      var fieldLeftOffset = $(this).offset().left;
      var fieldLeftConstOffset = -40;
      var newLeftValue = fieldLeft + (fieldLeftOffset - originalLeftOffset) + fieldLeftConstOffset;
      $field.css('left', newLeftValue + 'px');

      // adjust the width of the check all and none links if necessary
      var linkWidth = Math.floor(parseInt($(this).parent().width()) / 2);
      $(this).siblings('a').css('width', linkWidth + 'px');

      // adjust the right position of the check none link
      var checkWidth = parseInt($(this).siblings('a.check-all').css('width')) || 0;
      //var checkConstOffset = 25;
      var checkConstOffset = 0;
      $(this).siblings('a.check-none').css('left', (checkWidth + checkConstOffset) + 'px');

      // ensure the list elements have a valid width
      var $fieldElements = $field.children('li');
      var currentElementWidth = parseInt($fieldElements.css('width'));
      var newElementWidth = parseInt($field.siblings('span').css('width'));
      if (newElementWidth < 150)
        newElementWidth = 150;
      var newElementFullWidth = newElementWidth + 22;
      $fieldElements.css('width', newElementWidth + 'px');
      $field.css('width', newElementFullWidth + 'px');
    });

    // custom event to hand indirect checkbox clicks
    $(document).bind('checkboxClicked', function(event) {
      var $checkbox = $(event.target);
      $checkbox.click();
      $checkbox.parent().parent().trigger('processClick');
    });

    // call the click method of the checkbox adjacent to the label that itself was just clicked
    $('ul li label').live('click', function() {
      $checkbox = $(this).siblings('input');
      $checkbox.trigger('checkboxClicked');
    });

    // replace the header name
    $('ul.form-field li').live('click', function() {
      var dataListType = $(this).parent().parent().attr('data-list-type');
      var $fieldTitle = $(this).parent().siblings('span.field-title');
      if (typeof dataListType != 'undefined' && dataListType == 'checkbox') {
        var selectedName = $(this).html();
        var defaultFieldTitle = $(this).parent().parent().attr('data-list-title');
        var $checked = $(this).parent().children('li').children('input[type=checkbox]:checked');
        var checkedCount = $checked.length;
        if (checkedCount > 0) {
          $fieldTitle.html(defaultFieldTitle + ' (' + checkedCount + ')');
        }
        else {
          $fieldTitle.html(defaultFieldTitle);
        }
      }
      else {
        var selectedName = $(this).html();
        $fieldTitle.html(selectedName);
      }
    });

    $('div.region ul li input[type=checkbox]').live('click', function(result) {
      var areaKey = $(this).val();
      toggleSubareas('neighbourhood', areaKey);
    });

    $('div.field').live('hideDropdowns', function(event) {
      var $target = $(event.target);
      $target.each(function() {
        if ($(this).hasClass('block')) {
          $(this).removeClass('block');
        }
      });
    });

    $('div.field ul li input[type=checkbox]').live('click', function(result) {
      $(this).parent().parent().trigger('processClick');
    });

    $('body').click(function(event) {
      var $target = $(event.target);
      var $enclosingDiv = $target.parents('div.field');
      var newTarget = $enclosingDiv.attr('data-class') || null;
      if (newTarget && newTarget != '') {
        if (activeTarget != newTarget) {
          $('div.field').trigger('hideDropdowns');
          activeTarget = newTarget;
        }
        // no change if the active and new targets match
      }
      else {
        $('div.field').trigger('hideDropdowns');
        activeTarget = null;
      }
    });

    $('ul.default-input li').live('click', function() {
      var $spanTitle = $(this).parent().parent().children('span.field-title');
      var newTitle = $(this).html();
      var titleSuffix = $spanTitle.attr('data-title-suffix');
      if (titleSuffix && titleSuffix != '') {
        newTitle += titleSuffix;
      }
      $spanTitle.html(newTitle);
      $spanTitle.parent().removeClass('block');
    });

    $('a.check-all').live('click', function() {
      $(this).siblings('ul').find('input').each(function() {
        if ($(this).attr('checked') == false) {
          $(this).click();
        }
      });
      $(this).siblings('ul').trigger('processClick');
      var $fieldTitle = $(this).siblings('span.field-title');
      var defaultFieldTitle = $(this).parent().attr('data-list-title');
      var $checked = $(this).siblings('ul').children('li').children('input[type=checkbox]:checked');
      var checkedCount = $checked.length;
      if (checkedCount > 0) {
        $fieldTitle.html(defaultFieldTitle + ' (' + checkedCount + ')');
      }
      else {
        $fieldTitle.html(defaultFieldTitle);
      }
      return false; // to make sure the focus stays the same
    });

    $('a.check-none').live('click', function() {
      $(this).siblings('ul').find('input').each(function() {
        if ($(this).attr('checked') == true) {
          $(this).click();
        }
      });
      $(this).siblings('ul').trigger('processClick');
      var $fieldTitle = $(this).siblings('span.field-title');
      var defaultFieldTitle = $(this).parent().attr('data-list-title');
      var $checked = $(this).siblings('ul').children('li').children('input[type=checkbox]:checked');
      var checkedCount = $checked.length;
      if (checkedCount > 0) {
        $fieldTitle.html(defaultFieldTitle + ' (' + checkedCount + ')');
      }
      else {
        $fieldTitle.html(defaultFieldTitle);
      }
      return false; // to make sure the focus stays the same
    });

    $('button.search').live('click', function() {
      var $searchForm = $(this).parents('form.widget-container');
      if ($searchForm) {
        $searchForm.submit();
      }
    });

    searchWidgetHandlerSetUp = true;
  }
  generalHandlerSetup();

  var localHandlerSetup = function() {
    var $listItems = $root.find('li');
    $listItems.live('click', function() {
      var value = $(this).attr('data-value');
      if (value && value != '') {
        var fieldName = $(this).parents('ul.form-field').attr('form-field');
        try {
          var $hiddenField = $root.find('input[name=' + fieldName + ']');
          $hiddenField.val(value);
        } catch (e) {}
      }
    });
  };
  localHandlerSetup();

}

