// UI
tkts.ui = {};

//
// USER INTERFACE
//
// Load the ui
//   show: the show we're presenting
tkts.ui.load = function(show, available_methods) {
  var boxoffice = new tkts.ui.BoxOffice(show, available_methods);
  tkts.util.Seating.preload();

  // Adjust hooks for performance buttons.
  for (var i=0, len=show.performances.length; i < len; ++i) {
    var p = show.performances[i];
    var button = $('select_p' + p.id);
    if (button) {
      button.onClick = boxoffice.selectPerformance.bind(boxoffice, p);
    }
  }

  boxoffice.start();
  $('dialog').show();
};

// Box Offices sell tickets, represents the general UI flow
//   show: the show we're selling
tkts.ui.BoxOffice = function(show, available_methods) {
  this.show = show;
  this.available_methods = available_methods;

  this.order = new tkts.order.Order(available_methods[0]);
  this.seats_are_waiting = false;
};

// Start the BoxOffice by going to the select performance page
tkts.ui.BoxOffice.prototype.start = function(evt) {
  this.goSelectPerformance();
};

// Display the select performance page
//   msg: the message to display
tkts.ui.BoxOffice.prototype.goSelectPerformance = function(msg) {
  if (msg) {
    tkts.util.flash(msg);
  }

  var div = $('wizard');
  div.className = "select_p";
  div.innerHTML = '';

  tkts.util.P(div, 'Please select a performance:', 'question');

  var performances = this.show.performances;
  if (performances.length > 3) {
    // Use a drop-down.
    var sel = document.createElement('select');
    sel.id = 'selected_performance';
    sel.className = 'select';
    for (var i=0, len=performances.length; i < len; ++i) {
      var p = performances[i];
      var opt = document.createElement('option');
      if (p.available < 1) {
        opt.value = 0;
      } else {
        opt.value = p.id;
        if (this.order.performance && p.id == this.order.performance.id) {
          opt.selected = 'selected';
        }
      }
      opt.appendChild(document.createTextNode(tkts.util.formatPerformance(p)));
      sel.appendChild(opt);
    }
    div.appendChild(sel);
    tkts.util.B(div, 'Continue >>',
        this.onSelectPerformance.bind(this), 'select');
  } else {
    for (var i=0, len=performances.length; i < len; ++i) {
      var p = performances[i];
      if (p.available < 1) {
        tkts.util.B(div, tkts.util.formatPerformance(p),
            function(){}, 'select');
      } else {
        tkts.util.B(div, tkts.util.formatPerformance(p),
            this.selectPerformance.bind(this, p), 'select');
      }
    }
  }
};

// Handle the Continue >> button form of performance selection.
tkts.ui.BoxOffice.prototype.onSelectPerformance = function() {
  var pid = $F('selected_performance');
  if (pid == '0') {
    return;
  }
  this.selectPerformance(this.show.findPerformance(pid));
};

// Select a given performance
//   performance: the performance to select
tkts.ui.BoxOffice.prototype.selectPerformance = function(performance) {
  tkts.util.flash();

  if (performance.available < 1) {
    this.goSelectPerformance('No more tickets are available for this ' +
        'performance.');
    return;
  }
  this.order.performance = performance;
  this.goSelectSection();
};

// Display the select section page, will skip if there is only one
//   msg: the message to display
tkts.ui.BoxOffice.prototype.goSelectSection = function(msg) {
  if (!this.order.performance) {
    this.goSelectPerformance();
    return;
  }

  var sections = this.order.performance.seatings;

  this.section_count = 0;
  var free_section = null;
  for (var i=0, len=sections.length; i < len; ++i) {
    var s = sections[i];
    if (s.available < 1) {
      continue;
    }
    ++this.section_count;
    free_section = s;
  }
  if (this.section_count < 1) {
    this.goSelectPerformance('There are no seats available to you for ' +
        'this performance.');
    return;
  } else if (this.section_count == 1) {
    // Only one option with free seats
    this.selectSection(free_section);
    return;
  }

  if (msg) {
    tkts.util.flash(msg);
  }

  var div = $('wizard');
  div.className = "select_s";
  div.innerHTML = '';

  this.addSelectSectionHeader(div);

  // TODO: dynamic image
  var img = tkts.util.N(div, 'img');
  img.title = 'York Theatre';
  img.alt = 'York Theatre';
  img.src = '/img/york.jpg';

  tkts.util.P(div, 'Please select the section of the theatre you '+
      'would like to sit in:', 'question');
  for (var i=0, len=sections.length; i < len; ++i) {
    var s = sections[i];
    if (s.available < 1) {
      continue;
    }
    tkts.util.B(div, tkts.util.formatSection(s),
        this.selectSection.bind(this, s), 'select');
  }
};

// Add the header used on the select section page
//   div: the div to add it to
tkts.ui.BoxOffice.prototype.addSelectSectionHeader = function(div) {
  var d = tkts.util.DIV(div);
  tkts.util.L(d, 'Performance:');
  tkts.util.P(d, tkts.util.formatPerformance(this.order.performance),
      'value');
  tkts.util.B(d, 'Change Performance', this.onEditPerformance.bind(this), 'edit');
};

// Edit the performance selected
tkts.ui.BoxOffice.prototype.onEditPerformance = function(evt) {
  tkts.util.flash();
  this.goSelectPerformance();
};

// Select a given section
//   section: the section to select
tkts.ui.BoxOffice.prototype.selectSection = function(section) {
  tkts.util.flash();
  if (section.available < 1) {
    this.goSelectSection('No tickets available for this section');
    return;
  }
  if (!this.order.section || this.order.section != section) {
    this.order.seats = [];
    this.order.section = section;
  }
  this.goSelectSeats();
};

// Display the select seats page, skip if general admission.
tkts.ui.BoxOffice.prototype.goSelectSeats = function(msg) {
  if (!this.order.section) {
    this.goSelectSection();
    return;
  }

  if (!this.order.section.layout) {
    tkts.util.flash('Please wait, layout loading...');
    this.seats_are_waiting = true;
    return;
  } else {
    this.seats_are_waiting = false;
  }

  if (msg) {
    tkts.util.flash(msg);
  }

  var div = $('wizard');
  div.className = "select_seats";
  div.innerHTML = '';

  this.addSelectSeatsHeader(div);

  tkts.util.P(div, 'Please select the seats you would like:', 'question');
  var layout = this.order.section.layout;
  var container = tkts.util.DIV(div);
  container.innerHTML = layout;

  this.seating = new tkts.util.Seating(container, true);
  this.seating.bindClicker(this.onClickSeat.bind(this));
  this.seating.deselectAll();

  if (this.order.seats) {
    this.seating.select(this.order.seats);
  }
  tkts.util.P(div, 'Blue seats are booked already, green still available, ' +
      'and grey are yet to be made available.', 'hint');
  tkts.util.B(div, 'Continue >>', this.onSelectSeats.bind(this), 'select');
};

// Event handler for when you click on an available seat.
tkts.ui.BoxOffice.prototype.onClickSeat = function(seat) {
  tkts.util.Seating.toggleSeat(seat);
};

// Header for seats.
tkts.ui.BoxOffice.prototype.addSelectSeatsHeader = function(div) {
  this.addSelectSectionHeader(div);
  var sections = this.order.performance.seatings;
  if (sections.length > 1) {
    var d = tkts.util.DIV(div);
    tkts.util.L(d, 'Section:');
    tkts.util.P(d, tkts.util.formatSection(this.order.section),
        'value');
    if (this.section_count > 1) {
      tkts.util.B(d, 'Change Section', this.onEditSection.bind(this), 'edit');
    }
  }
};

// Handle the next step!
tkts.ui.BoxOffice.prototype.onSelectSeats = function() {
  this.order.seats = this.seating.getSelected();
  if (this.order.seats.length <= 0) {
    this.goSelectSeats('You must select at least one seat!');
    return;
  } else if (this.order.seats.length > 20) {
    this.goSelectSeats('You can only book up to 20 seats in a single ' +
        'transaction');
    return;
  }
  var msg = 'Selected ' + this.order.seats.length;
  if (this.order.seats.length > 1) {
    msg += ' seats.';
  } else {
    msg += ' seat.';
  }
  this.goEnterDetails(msg);
};

// Display the enter details page
//   msg: the message to display
tkts.ui.BoxOffice.prototype.goEnterDetails = function(msg) {
  if (this.order.seats.length <= 0) {
    this.goSelectSeats();
    return;
  }

  if (msg) {
    tkts.util.flash(msg);
  }

  var div = $('wizard');
  div.className = "enter_details";
  div.innerHTML = '';

  this.addEnterDetailsHeader(div);

  tkts.util.P(div, 'Please enter the number of tickets you want:', 'question');
  for (var i=0, len=this.show.prices.length; i<len; ++i) {
    var price = this.show.prices[i];
    var value = 0;
    if (this.order.tickets && this.order.tickets[price.id]) {
      value = parseInt(this.order.tickets[price.id]);
    }
    tkts.util.F(div, tkts.util.formatPrice(price) + ':',
        'tickets' + price.id, value);
  }
  var count = $(tkts.util.F(div, 'Total:', 'count', this.order.count));
  count.disable();

  for (var i=0, len=this.show.prices.length; i<len; ++i) {
    var price = this.show.prices[i];
    Event.observe('tickets' + price.id,
        'change',
        this.updateCount.bind(this));
  }

  tkts.util.P(div, 'If you buy ACCESS tickets, you must show your ' +
      'card upon ticket collection', 'hint');

  tkts.util.P(div, 'Please enter your personal details:', 'question');
  tkts.util.F(div, 'First Name:',
      'first_name', this.order.first_name);
  tkts.util.F(div, 'Last Name:',
      'last_name', this.order.last_name);
  tkts.util.F(div, 'Access ID (optional):',
      'aid', this.order.aid);
  tkts.util.P(div, 'Please give us contact details to provide a receipt as ' +
      'well as contact you.', 'hint');
  tkts.util.P(div, 'These details will not be passed on to third ' +
      'parties.', 'hint');
  tkts.util.F(div, 'Email Address:',
      'email', this.order.email);
  tkts.util.F(div, 'Phone Number:',
      'phone', this.order.phone);
  tkts.util.FA(div, 'Comments', 'comments', this.order.comments, 4);
  tkts.util.B(div, 'Continue >>', this.enterDetails.bind(this), 'select');
};

// Update the count field when the number of tickets changes
tkts.ui.BoxOffice.prototype.updateCount = function() {
  $('count').value = '';
  var count = 0;
  var total = 0;
  for (var i=0, len=this.show.prices.length; i<len; ++i) {
    var price = this.show.prices[i];
    var ele = $('tickets' + price.id);
    if (ele && ele.present()) {
      var num = parseInt(ele.getValue());
      if (('' + num) != ele.getValue()) {
        return;
      }
      count += num;
      var cost = price.value * num;
      total += cost;
    }
  }
  $('count').value = count + ' - ' + tkts.util.formatCost(total);
};

// Add the enter details header to a given div
//   div: the div to add the header too
tkts.ui.BoxOffice.prototype.addEnterDetailsHeader = function(div) {
  this.addSelectSeatsHeader(div);
  if (this.order.seats) {
    var seats = this.order.seats;
    var d = tkts.util.DIV(div);
    tkts.util.L(d, 'Seats:');
    var val = '';
    for (var i=0, len=seats.length; i < len; ++i) {
      var seat = seats[i];
      if (val) {
        val += ', ';
      }
      val += seat[1] + seat.slice(3);
    }
    tkts.util.P(d, val, 'value');
    tkts.util.B(d, 'Change Seats', this.onEditSeats.bind(this), 'edit');
  }
};

// Edit the performance selected
tkts.ui.BoxOffice.prototype.onEditSeats = function(evt) {
  tkts.util.flash();
  this.goSelectSeats();
};

// Change the section of the theatre
tkts.ui.BoxOffice.prototype.onEditSection = function(evt) {
  tkts.util.flash();
  this.goSelectSection();
};

// Record the order details
tkts.ui.BoxOffice.prototype.enterDetails = function() {
  tkts.util.flash();
  tkts.util.clearErrors();
  this.order.first_name = tkts.util.getName('first_name');
  this.order.last_name = tkts.util.getName('last_name');
  this.order.email = tkts.util.getEmail('email');

  var aid = $('aid');
  if (aid.present()) {
    this.order.aid = $F(aid);
    if (('' + parseInt(this.order.aid)) != this.order.aid) {
      tkts.util.addError(aid, 'Invalid access id');
      this.order.aid = 0;
    }
  } else {
    this.order.aid = null;
  }

  this.order.phone = tkts.util.getPhone('phone');
  this.order.comments = $F('comments');

  this.order.tickets = {};
  this.order.count = 0;
  this.order.total_cost = 0;
  for (var i=0, len=this.show.prices.length; i<len; ++i) {
    var price = this.show.prices[i];
    var count = $('tickets' + price.id);
    if (!count || !count.present()) {
      continue;
    }
    var num = tkts.util.getCount(count);
    if (!num || num == 0) {
      continue;
    }
    this.order.count += num;
    this.order.total_cost += num * price.value;
    this.order.tickets[price.id] = num;
  }
  if (this.order.count > this.order.section.available) {
    tkts.util.addError('count', 'Not enough tickets free in this section, max '+
        this.order.section.available);
  } else if (this.order.count < 1) {
    tkts.util.addError('count', 'You must purchase at least one');
  } else if (this.order.seats.length != this.order.count) {
    tkts.util.addError('count', 'You selected ' + this.order.seats.length +
        ' seats!');
    tkts.util.addError('count', 'You selected ' + this.order.seats.length +
        ' seats!');
  }

  if (!this.order.valid()) {
    // The order isn't valid for some reason, we're going to assume
    // that they've been presented with an error already.
    return;
  }

  this.goConfirmOrder();
};

// Display the confirm order page
//   msg: the message to add
tkts.ui.BoxOffice.prototype.goConfirmOrder = function(msg) {
  if (!this.order.performance) {
    this.goSelectPerformance();
    return;
  } else if (!this.order.section) {
    this.goSelectSection();
    return;
  } else if (this.order.seats.length <= 0) {
    this.goSelectSeats();
    return;
  } else if (!this.order.valid()) {
    this.goEnterDetails();
    return;
  }
  if (msg) {
    tkts.util.flash(msg);
  }

  // Clear all errors.
  tkts.util.clearErrors();

  var div = $('wizard');
  div.className = "confirm_order";
  div.innerHTML = '';
  this.addConfirmOrderHeader(div);

  tkts.util.P(div, 'After booking, you can collect tickets from our desk, or ' +
      'from the box office on the night. If you have any problems, please ' +
      'email ' + this.show.company.owner, 'hint');


    // drop down.

  tkts.util.P(div,
      'Please confirm all of the above details, and click the button ' +
      'below to reserve your tickets.', 'stronghint');

  if (this.available_methods.length > 1) {
    tkts.util.P(div,
      'Please choose the method of payment', 'stronghint');
    // Buttons! :)
    for (var i=0, len=this.available_methods.length; i < len; ++i) {
      var method = this.available_methods[i];
      tkts.util.B(div,
          method,
          this.choosePaymentMethod.bind(this, method),
          'select');

    }
  } else {
    tkts.util.B(div, 'Reserve Tickets', this.confirmOrder.bind(this), 'select');
  }
  tkts.util.P(div,
      'Make sure to only click the button once, and please wait.',
      'stronghint');
};

tkts.ui.BoxOffice.prototype.choosePaymentMethod = function(method) {
  this.order.payment_method = method;
  this.confirmOrder();
};

// Add the header to the confirm order div
//   div: the div to add things to
tkts.ui.BoxOffice.prototype.addConfirmOrderHeader = function(div) {
  this.addEnterDetailsHeader(div);

  tkts.util.V(div, 'First Name:', this.order.first_name);
  tkts.util.V(div, 'Last Name:', this.order.last_name);
  if (this.order.aid) {
    tkts.util.V(div, 'Access ID:', this.order.aid);
  }
  tkts.util.V(div, 'Email Address:', this.order.email);
  tkts.util.V(div, 'Phone Number:', this.order.phone);

  for (var i=0, len=this.show.prices.length; i<len; ++i) {
    var price = this.show.prices[i];
    var qty = 0;
    if (this.order.tickets && this.order.tickets[price.id]) {
      qty = parseInt(this.order.tickets[price.id]);
    }
    if (qty <= 0) {
      continue;
    }
    var cost = price.value * qty;
    tkts.util.V(div, tkts.util.formatPrice(price) + ' x ' + qty + ':',
        tkts.util.formatCost(cost));
  }
  tkts.util.V(div, 'Total [' + this.order.count + ' tickets]:',
      tkts.util.formatCost(this.order.total_cost));
  if (this.order.comments) {
    tkts.util.V(div, 'Comments:', this.order.comments);
  }
  tkts.util.B(div, 'Edit Details', this.editDetails.bind(this), 'edit');
};

// Edit details
tkts.ui.BoxOffice.prototype.editDetails = function(evt) {
  tkts.util.flash();
  this.goEnterDetails();
};

// Confirm an order, reserving tickets
tkts.ui.BoxOffice.prototype.confirmOrder = function() {
  tkts.util.flash('Contacting Server, please wait...');
  $('wizard').hide();
  $('loader').show();
  tkts.util.clearErrors()
  new Ajax.Request(document.location, {
    method: 'post',
    parameters: { order: this.order.json() },
    onSuccess: this.onOrderReserved.bind(this),
    onFailure: this.onOrderFailed.bind(this)
  });
};

// Callback on a successful order RPC
//   resp: the response
tkts.ui.BoxOffice.prototype.onOrderReserved = function(resp) {
  tkts.util.flash('Response received, processing..');
  $('loader').hide();
  var div = $('wizard');
  div.innerHTML = '';
  div.show();

  resp = resp.responseJSON;
  this.show.performances = resp.performances;
  this.section_count = 0;
  this.order.reset(this.show);

  // The server responded.
  if (resp.code == 'OK') {
    // We're good to go!
    this.order.ref = resp.ref;
    this.order.total_cost = resp.total_cost;
    this.order.free = resp.free;
    this.order.turl = resp.turl;
    this.goPayPal();
  } else if (resp.code == 'NOT_AVAIL:PERFORMANCE') {
    // During the process of our booking, we ran out of tickets for that
    // performance.
    this.order.clearPerformance();
    this.goSelectPerformance('Sorry, while you were completing your order, ' +
        'tickets were sold out for the performance you have selected. We ' +
        'invite you to see the show another time.');
  } else if (resp.code == 'NOT_AVAIL:SECTION') {
    // During the process of our booking, we ran out of tickets for the
    // section chosen.
    this.order.clearSection();
    this.goSelectSection('Sorry, while you were completing your order, ' +
        'the tickets you selected were sold. We invite you to please select ' +
        'new seats.');
  } else if (resp.code == 'NOT_AVAIL:SEATS') {
    // During the process of our booking, we ran out of tickets for the
    // seats chosen.
    this.order.seats = [];
    this.goSelectSeats('Sorry, while you were completing your order, ' +
        'the tickets you selected were sold. We invite you to please select ' +
        'new seats.');
  } else if (resp.code == 'NOT_AVAIL') {
    // During the process of our booking, we ran out of tickets.
    // Bugger.
    this.order.clearPerformance();
    this.goSelectPerformance('Sorry, while you were completing your order, '+
        'tickets were sold out! Please contact us directly or try again ' +
        'later in the case additional seats become available.');
  } else if (resp.code == 'OTHER') {
    this.goSelectPerformance('Sorry, while you were completing your order, ' +
        'an internal error occurred. Please contact us directly or try again '+
        'later.');
  } else {
    this.goConfirmOrder('Sorry, an error occurred communicating your order ' +
        'to the server, please try again.');
  }
};

// Callback to use when RPC fails
//  resp: the response object
tkts.ui.BoxOffice.prototype.onOrderFailed = function(resp) {
  tkts.util.flash('Response received, processing..');
  $('loader').hide();
  $('wizard').show();
  this.goConfirmOrder(
      'Failed to communicate with server, please try again later.');
};

// Display the before-paypal page
//   msg: the message to display
tkts.ui.BoxOffice.prototype.goPayPal = function(msg) {
  if (!this.order.ref) {
    this.goConfirmOrder('Order has not been reserved yet');
    return;
  } else {
    tkts.util.flash('Reservation successful!');
  }

  $('wizard').innerHTML = '';

  if (this.order.free) {
    document.location = this.order.turl;
  } else {
    document.location = '/orders/' + this.order.ref + '/paypal';
  }
};

