function get_property(element, property) {
  var idElement = $(element);
  var regexp1 = new RegExp('^' + property+'-([a-z0-9_]+)');
  var regexp2 = new RegExp(' ' + property+'-([a-z0-9_]+)');
  for (var i = 0; i < 20; i++) {
    if ($(idElement).is('html')) {
      return null;
    }
    var cssClass = idElement.attr('class');
    if (cssClass) {
      var match = regexp1.exec(cssClass);
      if (match) {
		return match[1];
      }
      match = regexp2.exec(cssClass);
      if (match) {
		return match[1];
      }
    }
    idElement = idElement.parent();
  }
  alert('ran into endless loop trying to get ' + property + ' from ' + $(element).html());
  return null;
}

function ajax_json_get(url, data, callback) {
	return ajax_json(url, data, callback, 'GET');
}

function ajax_json(url, data, callback, method) {
	method = method ? method : 'POST';
	$.ajax({ type: method, url: url, data: data, dataType: 'json', success: function(json) {
		if (json.alert) {
			alert(json.alert);
		} else if (json.error) {
			alert(json.error);
		} else if (json.confirm) {
			if (confirm(json.confirm)) {
				data.confirm = 1;
				ajax_json(url, data, callback);
			}
		} else {
			callback(json);
		}
	}, error: function() {
		alert('There has been an unexpected error.');
	} })
}

function maxlength(field, max) {
	var f = $('[name='+field+']');
	var length = f.val().length;
	if (length > max) {
		f.val(f.val().substr(0, max));
		length = max;
	}
	$('#'+field+'_chars').html(max - length);
}

function string_to_tag(s) {
  if (!s) {
    return '';
  }
  s = s.toLowerCase();
  s = s.replace(/ & /g, ' and ');
  s = s.replace(/^\s+|\s+$/g, ''); // trim
  s = s.replace(/[ ]+/g, '-');
  s = s.replace(/[-]+/g, '-');
  s = s.replace(/[^a-z0-9-]+/g, '');
  return s;
}

function h(s) {
  if (s == null) {
    return '';
  }
  s = s.toString();
  s = s.replace(/&/g, '&amp;');
  s = s.replace(/\"/g, '&quot;');
  s = s.replace(/</g, '&lt;');
  s = s.replace(/>/g, '&gt;');
  return s;
}

function u(s) {
  return encodeURIComponent(s);
}

function classattr(attrs) {
  var a = [];
  for (var k in attrs) {
    if (attrs[k]) {
      a.push(k);
    }
  }
  return a.length ? ' class="' + a.join(' ') + '"' : '';
}

function uri(uri, params) {
  if (!params || !uri) {
    return uri;
  }
  var parts = uri.split(/\?/);
  var path = parts[0];
  var args = {};

  if (parts.length > 1) {
    var args_list = parts[1].split(/\&/);
    for (var i=0; i < args_list.length; i++) {
      parts = args_list[i].split(/=/);
      args[parts[0]] = decodeURIComponent(parts[1]);
    }
  }

  for (var k in params) {
    if (params[k] === null) {
      delete args[k];
    } else {
      args[k] = params[k];
    }
  }

  var query = '';
  for (var k in args) {
    query += '&' + k + '=' + encodeURIComponent(args[k]);
  }
  if (!query) {
    return path;
  } else {
    return path + '?' + query.substring(1);
  }
}

function truncate(string, length) {
  if (string === null) {
    return '';
  }
  string = string.toString();
  if (!length || string.length <= length) {
    return string;
  }
  return string.substring(0, length - 2) + '...';
}

function element(name, attribs, is_open) {
  var html = '<' + name;
  if (attribs) {
    for (var k in attribs) {
      if (attribs[k] !== null) {
        html += ' ' + k + '="' + h(attribs[k]) + '"';
      }
    }
  }
  if (!is_open) {
    html += ' /';
  }
  html += '>';
  return html;
}

function link(href, name, attribs, length) {
  name = name !== null ? name : href;

  // shortcut: if third param is number, treat it as length param
  if (!length && typeof(attribs) == 'number') {
    length = attribs;
    attribs = {};
  } else {
    attribs = attribs ? attribs : {};
  }
  attribs.href = href;
  var text = length ? truncate(name, length) : name;
  return element('a', attribs, true) + h(text) + '</a>';
}

function link_image(href, attribs, iattribs) {
  // shortcut: if first param is string, shift values
  if ( !iattribs ) {
	  iattribs = attribs;
    attribs = {};
  }
  attribs.href = href;
  var image = element('img', iattribs);
  return element('a', attribs, true) + image + '</a>';
}

function input_text(name, value, attribs) {
  attribs = attribs ? attribs : {};
  attribs.name = name;
  attribs.type = attribs.type ? attribs.type : 'text';
  if (typeof(attribs.value) == 'undefined') {
    attribs.value = value;
  }
  return element('input', attribs);
}

function input_file(name, attribs) {
  attribs = attribs ? attribs : {};
  attribs.name = name;
  attribs.type = 'file';
  return element('input', attribs);
}

function input_hidden(name, value, attribs) {
  attribs = attribs ? attribs : {};
  attribs.name = name;
  attribs.value = value;
  attribs.type = 'hidden';
  return element('input', attribs);
}

function input_submit(value, attribs) {
  attribs = attribs ? attribs : {};
  attribs.value = value;
  attribs.type = 'submit';
  return element('input', attribs);
}

function input_radio(name, value, attribs) {
  attribs = attribs ? attribs : {};
  attribs.type = 'radio';
  attribs.name = name;
  attribs.value = value;
  if (request && request[name] == value) {
    attribs.checked = 'checked';
  }
  return element('input', attribs);
}

function input_checkbox(name, checked, attribs) {
  attribs = attribs ? attribs : {};
  attribs.name = name;
  attribs.type = 'checkbox';
  if (checked) {
    attribs.checked = 'checked';
  }
  return element('input', attribs);
}

function textarea(name, value, attribs) {
  attribs = attribs ? attribs : {};
  attribs.name = name;
  return element('textarea', attribs, true) + h(value) + '</textarea>';
}

function select(name, options, value, attribs, options_attribs) {
  attribs = attribs ? attribs : {};
  attribs.name = name;
  var html = element('select', attribs, true);
  html += select_options(options, value, options_attribs);
  html += '</select>';
  return html;
}

function select_options(options, value, attribs) {
  var html = '';
  if (options instanceof Array) {
    for (var i=0; i<options.length; i++) {
      var k = options[i];
      var v = options[i];
      if (typeof(v) == 'object') {
        k = v.getName();
        v = v._id;
      }
      var options_attribs = { value: v };
      if (value == v) {
        options_attribs.selected = 'selected';
      }
      html += element('option', options_attribs, true) + h(k) + '</option>';
    }
  } else {
    for (var k in options) {
      var options_attribs = { value: options[k] };
      if (value == options[k]) {
        options_attribs.selected = 'selected';
      }
      html += element('option', options_attribs, true) + h(k) + '</option>';
    }
  }
  return html;
}

function mailto(email) {
  var mailto = '<a href="mailto:'+email+'">'+email+'</a>';
  var html = '<script type="text/javascript">var dw = function(s) { document.write(s); };';
  var word = '';
  for (var i=0; i < mailto.length; i++) {
    word += mailto[i];
    if (i % 4 == 3 || i == mailto.length-1) {
      html += 'dw(\'' + word + '\');';
      word = '';
    }
  }
  html += '</script><noscript><a href="/contact">use contact page</a></noscript>';
  return html;
}

function button(label, attribs) {
  return element('button', attribs, true) + h(label) + '</button>';
}

function pluralize(number, singular, plural) {
  plural = plural ? plural : singular + 's';
  return number == 1 ? singular : plural;
}

function commify(number) {
  if (!number) {
    return 0;
  }
  number = parseInt(number);
  number += '';
  var x = number.split('.');
  var x1 = x[0];
  var x2 = x.length > 1 ? '.' + x[1] : '';
  var rgx = /(\d+)(\d{3})/;
  while (rgx.test(x1)) {
    x1 = x1.replace(rgx, '$1' + ',' + '$2');
  }
  return x1 + x2;
}

function elapsed_time(time) {
  if (time < 60000) {
    var number = Math.floor(time / 1000);
    var unit = pluralize(number, 'second');
  } else if (time < 3600000) {
    var number = Math.floor(time / 60000);
    var unit = pluralize(number, 'minute');
  } else if (time < 86400000) {
    var number = Math.floor(time / 3600000);
    var unit = pluralize(number, 'hour');
  } else if (time < 604800000) {
    var number = Math.floor(time / 86400000);
    var unit = pluralize(number, 'day');
  } else {
    return 'a while'; // do this later?
  }
  return number + ' ' + unit;
}

function nice_time(date) {
  date = date ? date : new Date();
  var time = date.strftime('%l:%M %p');
  var day = date.strftime('%B %e');
  var year = date.getFullYear();

  var now = new Date();
  if (day == now.strftime('%B %e')) {
    return time;
  }
  var yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
  if (day == yesterday.strftime('%B %e')) {
    return time + ' yesterday';
  }
  if (now.getFullYear() == year) {
    return time + ' on ' + day;
  }
  return time + ' on ' + day + ', ' + year;
}

function create_hash(iterator, key_field, val_field) {
  var obj = {};
  iterator.forEach(function(item) {
    if (!key_field) {
      obj[item] = item;
    } else {
      var k = typeof(key_field) == 'function' ? key_field(item) : item[key_field];
      var v = typeof(val_field) == 'function' ? val_field(item) : item[val_field];
      obj[k] = v;
    }
  });
  return obj;
}

function merge_hash(obj1, obj2) {
  if (obj1 instanceof Array && obj2 instanceof Array) {
    var array = [];
    for (var i = 0; i < obj1.length; i++) {
      array.push(obj1[i]);
    }
    for (i = 0; i < obj2.length; i++) {
      array.push(obj2[i]);
    }
    return array;
  }
  var obj = {};
  for (var k in obj1) {
    obj[k] = obj1[k];
  }
  for (k in obj2) {
    obj[k] = obj2[k];
  }
  return obj;
}

function strtotime(string) {
  if (!string) {
    return null;
  }

  var now = new Date();
  var year = now.getFullYear();
  var month = now.getMonth();
  var day = now.getDate();
  var hour = now.getHours();
  var minute = now.getMinutes();
  var second = now.getSeconds();
  var pm = null;
  var words = string.toLowerCase().replace(/[^\/a-z0-9-: ]/g, '');
  words = words.replace(/([0-9]+)([a-z]+)/g,'$1 $2');
  words = words.split(/ /);

  var months = ['january', 'february', 'march', 'april',
                'may', 'june', 'july', 'august',
                'september', 'october', 'november', 'december'];

  for (var n=0; n < words.length; n++) {
    var word = words[n];
    var num = parseInt(word);
    if (word.indexOf(':') > -1) {
      var time_parts = word.split(/\:/);
      hour = Math.round(time_parts[0]);
      minute = Math.round(time_parts[1]);
      if (time_parts.length > 2) {
        second = Math.round(time_parts[2]);
      } else {
        second = 0;
      }
    } else if (word.indexOf('/') > -1) {
      var date_parts = word.split(/\//);
      month = Math.round(date_parts[0]) - 1;
      day = Math.round(date_parts[1]);
      if (date_parts.length > 2) {
        year = Math.round(date_parts[2]);
        if (year < 100) {
          year += 2000;
        }
      }
    } else if (word.match(/^[0-9]+-[0-9-]+$/)) {
      var date_parts = word.split(/-/);
      if (date_parts.length > 2) {
        year = Math.round(date_parts[0]);
        month = Math.round(date_parts[1]) - 1;
        day = Math.round(date_parts[2]);
      } else {
        month = Math.round(date_parts[0]) - 1;
        day = Math.round(date_parts[1]);
      }
    } else if (num && num > 1900) {
      year = num;
    } else if (num && num > 0 && num <= 31) {
      var next_word = words[n+1] ? words[n+1] : null;
      if (['a', 'p', 'am', 'pm'].indexOf(next_word) > -1) {
        hour = Math.round(word);
        minute = 0;
      } else {
        day = Math.round(word);
      }
    } else if (word == 'am' || word == 'a') {
      pm = 'am';
    } else if (word == 'pm' || word == 'p') {
      pm = 'pm';
    } else if (word == 'tomorrow') {
      var tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
      year = tomorrow.getFullYear();
      month = tomorrow.getMonth();
        day = tomorrow.getDate();
    } else {
      for (var i=0; i<months.length; i++) {
        if (months[i].substring(0, word.length) == word) {
          month = i;
        }
      }
    }
  }

  if (pm && hour == 12) {
    hour = 0;
  }
  if (hour < 12 && pm == 'pm') {
    hour += 12;
  }
  return new Date(year, month, day, hour, minute, second);
}