tkts = {};

// Utility
tkts.util = {};

//
// UTILITY METHODS, best not to be picky
//
// Format a number as a price in dollars.
//   cost: the number
tkts.util.formatCost = function(cost) {
  return '$' + tkts.util.formatCostForPayPal(cost);
};

// Format a cost in cents as XX.XX
//   cost: the cost in cents
tkts.util.formatCostForPayPal = function(cost) {
  cost = parseInt(cost);
  var dollars = Math.floor(cost / 100);
  var cents = cost - dollars*100;
  return dollars + '.' + cents.toPaddedString(2);
};

// Format the availability of a group
//   group: the group
tkts.util.formatAvailability = function(group) {
  if (group.available > 0) {
    return '[' + group.available + ' tickets available]';
  } else if (group.capacity > group.available) {
    return '[Allocation exhausted: book through Seymour centre box office]';
  } else {
    return '[SOLD OUT]';
  }
};

// Format a performance name
//   p: the performance object
tkts.util.formatPerformance = function(p) {
  return p.name + ' ' + tkts.util.formatAvailability(p);
};

// Format a section of the theatre
//   s: the section object
tkts.util.formatSection = function(s) {
  return s.name + ' ' + tkts.util.formatAvailability(s);
};

// Format a price object to text
//   p: the price object
tkts.util.formatPrice = function(p) {
  return p.name.capitalize() + ' - ' + tkts.util.formatCost(p.value) + 'ea.';
};

// Display a message in the message section.
//   msg: the message to display, blank if none.
tkts.util.flash = function(msg) {
  var ele = $('msg');
  if (!msg) {
    ele.hide();
    return;
  }
  ele.innerHTML = msg;
  ele.show();
};

// Add an error on the given element
//   ele: the element to add an error on
//   msg: the error message
tkts.util.addError = function(ele, msg) {
  ele = $(ele);
  new Insertion.After(ele,
      '<p class="error">&lt; ' + msg + '</p>');
  ele.addClassName('error_field');
};

// Remove all errors from the page
tkts.util.clearErrors = function() {
  var errors = $$('.error');
  for (var i=0, len=errors.length; i < len; ++i) {
    errors[i].hide();
  }
  var error_fields = $$('.error_field');
  for (var i=0, len=error_fields.length; i < len; ++i) {
    error_fields[i].removeClassName('error_field');
  }
};

// Create a div tag and add it to the container
//   p: the container to add the div to
tkts.util.DIV = function(p) {
  var div = document.createElement('div');
  p.appendChild(div);
  return div;
};

// Shortcut to make a node with text contents
//  type: the type of node to create
//   txt: the text inside the node
//   cls: the class of the node
tkts.N = function(type, txt, cls) {
  var n = document.createElement(type);
  if (cls) {
    n.className = cls;
  }
  if (txt) {
    n.appendChild(document.createTextNode(txt));
  }
  return n;
};

// Same as above, but add it to a div.
//  div: the div to add the node to.
tkts.util.N = function(div, type, txt, cls) {
  var n = tkts.N(type, txt, cls);
  div.appendChild(n);
  return n;
};

// Label tag
//   div: the div to add the label to
//   txt: the txt of the label
tkts.util.L = function(div, txt) {
  tkts.util.N(div, 'label', txt);
};

// Paragraph tag
//   div: the div to add the tag to
//   txt: the text inside the tag
//   cls: the class of the paragraph tag
tkts.util.P = function(div, txt, cls) {
  tkts.util.N(div, 'p', txt, cls);
};

// Button
//   div: the div to add the button to
//  name: the name to put on the button
// callback: the callback function to use when clicked
//   cls: the class name for the button
tkts.util.B = function(div, name, callback, cls) {
  var button = tkts.N('input');
  button.type = 'button';
  button.value = name;
  if (cls) {
    button.className = cls;
  }
  Event.observe(button, 'click', callback);
  div.appendChild(button);
  return $(button);
};

// Input
//   div: the div to add the input to
//    id: the name of the input field
// value: the value for the field to have initially
tkts.util.I = function(div, id, value, type) {
  var input = tkts.N('input');
  if (id) {
    input.id = id;
    input.name = id;
  }
  input.className = 'input';
  if (type) {
    input.type = type;
  }
  if (value || value == 0) {
    input.value = value;
  } else {
    input.value = '';
  }
  div.appendChild(input);
  return input;
};

// Text Area
//   div: the div to add the input to
//    id: the name/id of the input field
// value: the value to have initially
tkts.util.IA = function(div, id, value, height) {
  var input = tkts.N('textarea');
  if (id) {
    input.id = id;
    input.name = id;
  }
  input.className = 'input';
  if (value) {
    input.innerHTML = value;
  }
  if (height) {
    input.rows = height;
  } else {
    input.rows = 4;
  }
  input.cols = 80;
  div.appendChild(input);
  return input;
};

// Hidden Input
//   div: div to add it to
//    id: the name of the input field
// value: the value for the field
tkts.util.HI = function(div, id, value) {
  return tkts.util.I(div, id, value, 'hidden');
};


// Construct a field and add it to a given div.
//   div: the div to add it to
//  name: the name of the value
//    id: the id/name to assign to the input
// value: the value of the field to default to
tkts.util.F = function(div, name, id, value) {
  var f = tkts.util.DIV(div);
  tkts.util.L(f, name);
  return tkts.util.I(f, id, value);
};

// Construct a field area and add it to a given div.
//   div: the div to add it to
//  name: the name of the value
//    id: the id/name to assign to the input
// value: the value of the field to default to
tkts.util.FA = function(div, name, id, value, height) {
  var f = tkts.util.DIV(div);
  tkts.util.L(f, name);
  return tkts.util.IA(f, id, value, height);
};

// Construct a value and add it to a given div.
//   div: the div to add it to
//  name: the name of the value
// value: the actual value
tkts.util.V = function(div, name, value) {
  var v = tkts.util.DIV(div);
  tkts.util.L(v, name);
  tkts.util.P(v, value, 'value');
};

// Get a string of minimum length from an element, adding an error if
// needed.
//   ele: the element
//   minlen: the minimum string length
tkts.util.getString = function(ele, minlen, msg) {
  var str = $F(ele);
  if (!str || str.length < 1) {
    tkts.util.addError(ele, 'Missing');
    return null;
  } else if (str.length < minlen) {
    if (!msg) {
      msg = 'Too Short';
    }
    tkts.util.addError(ele, msg);
    return null;
  }
  return str;
};

// Get the value of a field element expecting a name.
//   ele: the field element.
tkts.util.getName = function(ele) {
  var name = tkts.util.getString(ele, 2);
  return name;
};

// Get the value of a field as a value datetime object.
tkts.util.getDateTime = function(ele) {
  var v = tkts.util.getString(ele, 0);

  if (v) {
    if (!v.match('\\d+-\\d+-\\d+ \\d+:\\d+')) {
      tkts.util.addError(ele, 'Time must be: Y-M-D H:M');
      return null;
    }
  }
  return v;
};

// Get the value of a field element expecting an email.
//   ele: the field element.
tkts.util.getEmail = function(ele) {
  var email = tkts.util.getString(ele, 4);

  if (email) {
    if (!email.include('@')) {
      tkts.util.addError(ele, 'Invalid email address, must contain @');
      return null;
    }
  }

  return email;
};

// Get the value of a field element expecting a phone number.
//   ele: the field element.
tkts.util.getPhone = function(ele) {
  var phone = tkts.util.getString(ele, 8, 'Not a phone number');

  if (phone) {
    var chars = phone.toArray();
    for (var i=0, len=chars.length; i < len; ++i) {
      var c = chars[i];
      if (c >= '0' && c <= '9') {
        continue;
      }
      if (c == ' ' || c == '+' || c == '-') {
        continue;
      }
      if (!c) {
        continue;
      }
      tkts.util.addError(ele, 'Not a phone number');
      return null;
    }
  }
  return phone;
};

// Get the value of a field expecting a non-negative integer
//   ele: the integer
tkts.util.getCount = function(ele) {
  var val = $F(ele);
  var num = parseInt(val);
  if (num < 0) {
    tkts.util.addError(ele, 'Cannot be negative');
    return null;
  }
  if (('' + num) != val) {
    tkts.util.addError(ele, 'Not a number');
    return null;
  }
  return num;
};

// Seating Manager
tkts.util.Seating = function(container, avail_only) {
  this.seating = $($(container).down('.S'));
  this.avail_only = avail_only;
  this.seats = this.getSeats();
};

tkts.util.Seating.n_types = $A(['a', 'x', 'b', 'xy', 'xr']);
tkts.util.Seating.s_types = tkts.util.Seating.n_types.map(function(t) {
    return t + 's';
});
tkts.util.Seating.s_classes = tkts.util.Seating.s_types.map(function(t) {
    return '.' + t;
});

tkts.util.Seating.prototype.selectSeats = function(e) {
  if (this.avail_only) {
    return e.select('.a', '.as');
  } else {
    return e.select('.s');
  }
};

tkts.util.Seating.preload = function() {
  // Not implemented.
};

tkts.util.Seating.prototype.getSeats = function() {
  return this.selectSeats(this.seating);
};

tkts.util.Seating.prototype.relatedClicker = function(e) {
  return e.up('.S').down('.' + e.id + '_c');
};

tkts.util.Seating.prototype.bindClicker = function(callback) {
  for (var i=0, len=this.seats.length; i < len; ++i) {
    var seat = this.seats[i];
    Event.observe(this.relatedClicker(seat), 'click', callback.bind(this, seat));
  }

  // bind row clicker
  var rows = this.seating.select('.RR', '.RL');
  for (var i=0, len=rows.length; i < len; ++i) {
    var row = rows[i].up('.r');
    var clicker = this.relatedClicker(rows[i]);
    Event.observe(clicker, 'click', this.onClickRow.bind(
          this,
          row,
          callback));
  }
};

tkts.util.Seating.prototype.onClickRow = function(row, callback) {
  this.selectSeats(row).each(callback);
};

tkts.util.Seating.toggleSeat = function(seat) {
  if (tkts.util.Seating.selectSeat(seat)) {
    return;
  } else {
    tkts.util.Seating.deselectSeat(seat);
  }
};

tkts.util.Seating.selectSeat = function(seat) {
  for (var i=0, len=tkts.util.Seating.n_types.length; i < len; ++i) {
    if (seat.hasClassName(tkts.util.Seating.n_types[i])) {
      seat.removeClassName(tkts.util.Seating.n_types[i]);
      seat.addClassName(tkts.util.Seating.s_types[i]);
      return true;
    }
  }
  return false;
};

tkts.util.Seating.deselectSeat = function(seat) {
  for (var i=0, len=tkts.util.Seating.s_types.length; i < len; ++i) {
    if (seat.hasClassName(tkts.util.Seating.s_types[i])) {
      seat.removeClassName(tkts.util.Seating.s_types[i]);
      seat.addClassName(tkts.util.Seating.n_types[i]);
      return true;
    }
  }
  return false;
};

tkts.util.Seating.forceType = function(seat, type) {
  seat.className = 's ' + type;
};

tkts.util.Seating.prototype.deselectAll = function() {
  this.seats.each(tkts.util.Seating.deselectSeat);
};

tkts.util.Seating.prototype.select = function(seats) {
  for (var i=0, len=seats.length; i < len; ++i) {
    tkts.util.Seating.selectSeat($(seats[i]));
  }
};

tkts.util.Seating.prototype.getSelected = function() {
  // Relatively slow operation.
  return this.seating.select(tkts.util.Seating.s_classes).map(function(seat) {
    return seat.id;
  });
};

// Trigger cron work.
new Ajax.Request('/work')

