var Navigation = {
  ready: false,

  navigation: null,
  remote: null,
  panel: null,
  current: null,

  items: [],
  buttons: [],
  steps: [],

  // Set up list navigation.
  setup: function(navigation, remote, panel) {
    var that = this;

    this.navigation = $(navigation);
    this.remote     = $(remote);
    if (!(this.navigation && this.remote)) {
      return;
    }

    this.items = this.navigation.select("li");
    if (this.items.length === 0) {
      return;
    }
    this.items.first().addClassName("first");
    this.items.last().addClassName("last");

    this.panel = $(panel);
    if (this.panel) {
      this.steps = this.panel.immediateDescendants();
      if (this.steps.length !== this.items.length) {
        this.panel = null;
      }
    }

    // Add remote buttons for each item.
    this.items.each(function(element) {
      var img = element.down("img");
      var alt, p, a;

      if (img && (alt = img.readAttribute("alt"))) {
        p = new Element("p");
        a = that.createLink(alt, null, element);
        p.appendChild(a);
        that.remote.appendChild(p);
        that.buttons.push(p);
      }
    });
    this.buttons.first().addClassName("first");
    this.buttons.last().addClassName("last");

    this.items.each(function(element) {
      // Add "previous" buttons to items, except first and last.
      if (element !== that.items.first() && element !== that.items.last()) {
        a = that.createLink("Previous", "previous", element.previous());
        a.hide();
        element.appendChild(a);
      }
      // Add "this" buttons to items, except first.
      if (element !== that.items.first()) {
        a = that.createLink("Next", "this", element);
        a.hide();
        element.appendChild(a);
      }
      // Add "backtrack" button to the penultimate item, if exists.
      if (element.next() && element.next() === that.items.last()) {
        a = that.createLink("Previous", "backtrack", element);
        a.hide();
        element.appendChild(a);
      }
    });

    if (this.panel) {
      this.items.each(function(element, index) {
        var step = that.steps[index];
        var links = [];
        var ul;

        ul = new Element("ul");
        ul.addClassName("step-links");

        // Add "previous" buttons to items, except first.
        if (element !== that.items.first()) {
          links.push(
            that.createLink("Previous", null, element.previous()));
        }
        // Add "next" buttons to items, except last.
        if (element !== that.items.last()) {
          links.push(
            that.createLink("Next", null, element.next()));
        }

        links.each(function(a, index) {
          var li;

          li = new Element("li");
          li.appendChild(a);
          ul.appendChild(li);

          if (index === 0) {
            li.addClassName("first");
          }
        });

        step.appendChild(ul);
      });
    }

    this.ready = true;
    this.show(this.items.first());

    new Effect.Appear(this.navigation);
    new Effect.Appear(this.remote);
  },

  // Create show buttons.
  createLink: function(text, className, element) {
    var a, span;
    var that = this;

    a = new Element("a");
    a.setAttribute("href", ".");
    if (text) {
      span = new Element("span");
      span.appendChild(document.createTextNode(text));
      a.appendChild(span);
    }
    if (className) {
      a.addClassName(className);
    }
    if (element) {
      Event.observe(a, "click", function(event) {
        that.show(element);
        Event.stop(event);
      });
    }

    return a;
  },

  // Navigate to element.
  show: function(element) {
    var index;
    var wrapper, list;
    var x;
    var that = this;

    if (!this.ready) {
      return;
    }
    if (!element) {
      return;
    }
    if (this.current && this.current === element) {
      return;
    }

    // Update remote control buttons and steps.
    if (this.current) {
      index = this.items.indexOf(this.current);
      if (index !== -1) {
        this.buttons[index].down().removeClassName("selected");
        if (this.panel) {
          this.steps[index].hide();
        }
      }
    }
    index = this.items.indexOf(element);
    if (index !== -1) {
      this.buttons[index].down().addClassName("selected");
      if (this.panel) {
        this.steps[index].show();
      }
    }

    // Hide item buttons.
    if (this.current) {
      this.current.select("a.previous, a.this, a.backtrack").invoke("hide");
    }
    element.select("a.previous, a.this, a.backtrack").invoke("hide");

    // Make picked element current.
    this.current = element;

    wrapper = element.up("", 1);
    list    = element.up();

    // Compute the slider position as a negative offset. The last item, when
    // not first at the same time, is a special case.
    x = element.positionedOffset().left;
    if (element === this.items.last() && this.items.length > 1) {
      x += element.getWidth() - wrapper.getWidth();
    }

    // Invoke Scriptaculous magic.
    new Effect.Move(list, {
      x: -x,
      y: 0,
      mode: "absolute",
      afterFinish: function() {
        // Turn on "previous" button, except first nor last.
        if (element !== that.items.first() && element !== that.items.last()) {
          element.down("a.previous").show();
        }
        // Turn on "this" (actually next) button, except for last.
        if (element !== that.items.last()) {
          element.next().down("a.this").show();
        }
        // Turn on "backtrack" button except if first and last.
        if (element === that.items.last() && element !== that.items.first()) {
          element.previous().down("a.backtrack").show();
        }
      }
    });
  }
};
