// $Id: craqbox.js,v 1.2 2007/04/12 09:50:14 unconed Exp $

// Avoid colliding with a global '$' variable.
(function($) {
  /**
   * Chainable jQuery method $(...).craqbox(...).
   */
  $.fn.craqbox = function(o) {
    $.craqbox(this, o);
    return this;
  };

  /**
   * Static jQuery method $.craqbox(...) that returns the Craqbox object.
   */
  $.craqbox = function(a, o) {
    a = $(a).get(0);
    
    return a.craqbox || (a.craqbox = new $._craqbox(a, o));
  };

  /**
   * Private constructor for the Craqbox object.
   */
  $._craqbox = function(a, o) {
    var cb = this;

    // Configurable options for craqbox.
    var defaults = {
      attachEvent: 'click',
      animation: { opacity: 'toggle' },          // TODO: implement.
      cacheKey: null,
      closeButtonLabel: 'x',
      closeButtonTitle: 'Close',
      closeButtonClass: 'close_button',
      closeButtonContainerClass: 'close_button_container',
      completeCallback: function() { },
      content: null,
      contentClass: 'content',
      craqboxId: 'craqbox',
      dragable: true,
      ease: 'easein',                           // TODO: implement.
      heading: 3,
      hiderClass: 'craqbox_hider',
      hiderOpacity: 0.5,
      hiderSpeed: 'fast',
      horizontalAlign: true,
      iframeBorder: 0,
      iframeClass: 'frame_class',
      iframeScroll: 'no',
      inSpeed: 'normal',
      links: {},
      outSpeed: 'fase',
      padding: 10,
      removeCallback: function() { },
      title: null,
      titleBar: true,
      titleBarClass: 'title_bar',
      type: 'iframe',                          // iframe / image / dom / html
      url: null,
      width: 700,
      verticalAlign: false
    };

    // Create options object.
    cb.o = $.extend(defaults, o || {});

    /**
     * Absolute position of an element.
     */
    cb.absolutePosition = function(el) {
      var left = 0;
      var top  = 0;
      el = $(el)[0];
      while (el.offsetParent) {
        left += el.offsetLeft;
        top  += el.offsetTop;
        el = el.offsetParent;
      }
      left += el.offsetLeft;
      top  += el.offsetTop;
      return { x:left, y:top };
    };

    /**
     * Build the content for the appropriate type.
     */
    cb.build = function(newOptions) {
      // Update options.
      cb.o = $.extend(cb.o, newOptions || {});
      // Setup content cache.
      cb.cache = cb.cache || [];
      // Build our content.
      var content = '';
      // The key to use for caching the content.
      var key;
      switch (cb.o.type) {
        case 'node':
          url = a.href;
          $('body').css( "cursor", "wait");
          $.get(url, function(data) {
            $('#'+ cb.o.craqboxId +' .'+ cb.o.contentClass).removeClass('craqbox_spinner');
//                content = $('div.craqbox').html( data );
            d = $('<div></div>');
	          d.html( data );
            c = $( 'div.node div.content', d ).eq(0);
            t = $( 'div.terms', d );
            p = $( 'div.node div.picture', d ).eq(0);
            c.prepend( p ).append(t);
            // title = $('h2.title', d );
            // cb.o.title = title.text();
            cb.o.title = a.text;
            $('div.fivestar-widget', c).rating();
            $('input.fivestar-submit', c).hide();
            cb.show(c);
            $('body').css( "cursor", "auto" );
          });
          break;
      
      
        case 'iframe':
          key = cb.o.cacheKey || cb.o.url || a.href;
          var src = cb.o.url || cb.o.links[a.href] || a.href;
          if (!src) {
            return false;
          }
          if (!cb.cache[key]) {
            content = $('<iframe>').attr({
              src: src,
              iframeborder: cb.o.iframeBorder,
              scrolling: cb.o.iframeScroll,
              className: cb.o.iframeClass
            });
            cb.cache[key] = content;
          }
          else {
            content = cb.cache[key];
          }
          break;
        case 'image':
          key = cb.o.cacheKey || cb.o.url || a.href;
          console.log('key: '+ key);
          var src = cb.o.url || cb.o.links[a.href] || a.href;
          if (!src) {
            return false;
          }
          cb.o.title = cb.o.title || ($(a).attr('title') || $('img[@title]', a).attr('title'));
          console.log('title: '+ cb.o.title);
          if (!cb.cache[key]) {
            content = $('<img>').attr({ src: src, alt: a.title || key });
            cb.cache[key] = content;
          }
          else {
            content = cb.cache[key];
          }
          break;
        case 'dom':
          if (cb.o.cacheKey && !cb.cache[cb.o.cacheKey]) {
            content = $(cb.o.content);
            cb.cache[cb.o.content] = content;
          }
          else if (cb.o.cacheKey && cb.cache[cb.o.cacheKey]) {
            content = $(cb.cache[cb.o.content]);
          }
          else {
            content = $(cb.o.content);
          }
          content = $(cb.o.content);
          break;
        case 'html':
          key = cb.o.cacheKey || a.href;
console.log( "case = html, key = " + key + " o = " );
console.log( cb.o );
          if (!cb.cache[key]) {
            if (cb.o.url) {
              $('#'+ cb.o.craqboxId +' .'+ cb.o.contentClass).addClass('craqbox_spinner');
              $.get(cb.o.url, function(data) {
                $('#'+ cb.o.craqboxId +' .'+ cb.o.contentClass).removeClass('craqbox_spinner');
                content = $('<div>').html(data);
                cb.cache[key] = content;
                cb.show(content);
              });
            }
            else if (cb.o.content) {
              content = cb.o.content;
              cb.cache[key] = content;
            }
            else {
              return false;
            }
          }
          else {
            content = cb.cache[key];
          }
          break;
      }
      // Display a craqbox if we have content.
      if (content) {
        cb.show(content);
      }

      return cb;
    };

    /**
     * Center the craqbox.
     */
    cb.center = function(x, y) {
      var c = $('#'+ cb.o.craqboxId);
      if (!x) {
        x = 0;
      }
      if (!y) {
        y = 0;
      }
      if (cb.o.verticalAlign) {
        var h = self.innerHeight || document.documentElement.clientHeight || $('body')[0].clientHeight || 0;
        c.css('top', ((h - $('#'+ cb.o.craqboxId).height()) / 2 + y) +'px');
      }
      else {
        c.css('top', (cb.o.padding) +'px');
      }
      if (cb.o.horizontalAlign) {
        c.css('left', (($(document.body).width() - cb.o.width) / 2 + x) +'px');
      }
      else {
        c.css('left', (cb.o.padding) +'px');
      }
      // Reset the hiders size.
      cb.hider();
    };

    /**
     * Background shader.
     */
    cb.hider = function(toggle) {
      var yScroll;
      var xScroll;

      // Handle finding the proper document.body size so we can "hide" the content.
      // All the cool browsers.
      if (window.innerHeight && window.scrollMaxY || window.innerWidth && window.scrollMaxX) {
        yScroll = window.innerHeight + window.scrollMaxY;
        xScroll = window.innerWidth + window.scrollMaxX;
        var deff = document.documentElement;
        var wff = (deff && deff.clientWidth) || document.body.clientWidth || window.innerWidth || self.innerWidth;
        var hff = (deff && deff.clientHeight) || document.body.clientHeight || window.innerHeight || self.innerHeight;
        xScroll -= (window.innerWidth - wff);
        yScroll -= (window.innerHeight - hff);
      }
      // All other Explorers.
      else if (document.body.scrollHeight > document.body.offsetHeight || document.body.scrollWidth > document.body.offsetWidth) {
        yScroll = document.body.scrollHeight;
        xScroll = document.body.scrollWidth;
      }
      // Explorer 6 Strict.
      else {
        yScroll = document.body.offsetHeight;
        xScroll = document.body.offsetWidth;
      }
      // Hide the hider.
      if (toggle == 'hide') {
        $('#'+ cb.o.craqboxId +'_hider').fadeOut(cb.hiderSpeed, function() {
          $('#'+ cb.o.craqboxId +'_hider').removeClass('visible');
        });
      } 
      // Display the hider.
      else {
        // Make the site fade out a little.
        if ($('#'+ cb.o.craqboxId +'_hider').length > 0) {
          // Remove old click event to get new removeCallback() in cb.remove.
          $('#'+ cb.o.craqboxId +'_hider')
          .unbind('click')
          .bind('click', cb.remove)
          .css({ width: xScroll +'px', height: (document.body.offsetHeight) +'px' });
          // Fade back in if not visible.
          if (!$('#'+ cb.o.craqboxId +'_hider').is('.visible')) {
            $('#'+ cb.o.craqboxId +'_hider').fadeTo(cb.o.hiderSpeed, cb.o.hiderOpacity, function() {
              $('#'+ cb.o.craqboxId +'_hider').addClass('visible');
            });
          }
        }
        else {
          // Create the hider.
          $('<div>')
          .attr('id', cb.o.craqboxId +'_hider')
          .css({opacity: 0, width: xScroll +'px', height: (document.body.offsetHeight) +'px' })
          .click(cb.remove)
          .appendTo(document.body)
          .fadeTo(cb.o.hiderSpeed, cb.o.hiderOpacity, function() { $(this).addClass('visible') });
        }
      }
    };

    /**
     * Fix browser issues.
     *  - embeds / objects / selects in IE 6 have zIndex issues.
     *  - selects in Firefox do weird things with multiple = true;
     */
    cb.hiderFixes = function(state) {
      $('object, embed, select').css('display', (state == 'off') ? 'block' : 'none');
    };

    /**
     * Remove a craqbox.
     */
    cb.remove = function(event) {
      $(window).unbind('scroll', cb.scroll).unbind('resize', cb.scroll);
      $('#'+ cb.o.craqboxId).fadeOut(cb.o.outSpeed, function() {
        // Remove old content.
        $('#'+ cb.o.craqboxId + ' .'+ cb.o.contentClass).children().remove();
        // Remove browser fixes for hider.
        cb.hiderFixes('off');
        // Process removeCallback().
        cb.o.removeCallback();
      });
      cb.hider('hide');

      return false;
    };

    /**
     * Make craqbox scroll with the window scrollbar.
     */
    cb.scroll = function(event) {
      var yScrollTop;
      var xScrollLeft;

      // Handle grabbing the proper scroll values for each browser.
      // All the cool browsers.
      if (self.pageYOffset || self.pageXOffset) {
        yScrollTop = self.pageYOffset;
        xScrollLeft = self.pageXOffset;
      }
      // Explorer 6 Strict.
      else if (document.documentElement && document.documentElement.scrollTop || document.documentElement.scrollLeft ) {
        yScrollTop = document.documentElement.scrollTop;
        xScrollLeft = document.documentElement.scrollLeft;
      }
      // All other Explorers.
      else if (document.body) {
        yScrollTop = document.body.scrollTop;
        xScrollLeft = document.body.scrollLeft;
      }

      // Position craqbox.
      cb.center(xScrollLeft, yScrollTop);
    };

    /**
     * Display the content.
     */
    cb.show = function(content) {
      // Do a few fixes because of weird browser issues with zIndex.
      cb.hiderFixes();
      // Display the hider.
      cb.hider();
      // Only redraw our Craqbox if we need to.
      if ($('#'+ cb.o.craqboxId).length > 0) {
        // Set the title.
        if (cb.o.title) {
          $('#'+ cb.o.craqboxId + ' h'+ cb.o.heading).html(cb.o.title);
        }
        // Reset the close button event to get the proper removeCallback().
        $('#'+ cb.o.craqboxId +' .'+ cb.o.closeButtonClass).unbind('click').bind('click', cb.remove);
        if ($('#'+ cb.o.craqboxId +'_hider').is('.visible')) {
          // Fade out the old content first.
          $('#'+ cb.o.craqboxId + ' .'+ cb.o.contentClass).fadeOut(cb.o.outSpeed, function() {
            // TODO: this is currently used to fix a bug with jQuery calling the completeCallback on this fadeOut twice.
            var faded = $('#'+ cb.o.craqboxId + ' .'+ cb.o.contentClass).attr('faded');
            if (!faded || faded == 0) {
              // Remove old content.
              $('#'+ cb.o.craqboxId + ' .'+ cb.o.contentClass).children().remove();
              // Show new content.
              $('#'+ cb.o.craqboxId + ' .'+ cb.o.contentClass)
              .append(content)
              .fadeIn(cb.o.inSpeed, function() {
                cb.center();
                cb.o.completeCallback();
                $('#'+ cb.o.craqboxId + ' .'+ cb.o.contentClass).attr('faded', 0);
              });
              
              $('#'+ cb.o.craqboxId + ' .'+ cb.o.contentClass).attr('faded', 1);
            }
          });
        }
        else {
          $('#'+ cb.o.craqboxId).fadeTo(cb.o.inSpeed, 1.0);
          // Show new content.
          $('#'+ cb.o.craqboxId + ' .'+ cb.o.contentClass).append(content).fadeIn(cb.o.inSpeed, function() {
            cb.center();
            cb.o.completeCallback();
          });
        }

      } 
      // Create Craqbox UI.
      else {
        // Hide the site a bit with a "shader".
        cb.hider();

        // Create a close button.
        var closeButton = $('<a>')
        .attr({ title: cb.o.closeButtonTitle, className: cb.o.closeButtonClass, href: '#close' })
        .html(cb.o.closeButtonLabel)
        .click(function() { cb.remove(); return false; });

        // Add a title bar.
        if (cb.o.titleBar) {
          var titleBar = $('<div>')
          .addClass(cb.o.titleBarClass)
          .append($('<div>').addClass(cb.o.closeButtonContainerClass).append(closeButton));

          // Add drag and drop support.
          if (cb.o.dragable) {
            var mouseMove = function(event) {
              // Only support dragging on holding the title bar.
              if (event.target == $('#'+ cb.o.craqboxId +' .'+ cb.o.titleBarClass)[0]) {
                /* TODO: get this working.
                var craqbox = $('#'+ cb.o.craqboxId);
                var p = cb.absolutePosition(craqbox);
                craqbox.css({top: (event.clientY - p.y) +'px', left: (event.clientX - p.x) +'px' });
                */
              }

              return false;
            };
            var mouseDown = function() { $(document).bind('mousemove', mouseMove); };

            $(document)
            .bind('mousedown', mouseDown)
            .bind('mouseup', function(event) { $(document).unbind('mousemove', mouseMove);  });
          }


          if (cb.o.title) {
            $('<h'+ cb.o.heading +'>').addClass('title').html(cb.o.title).appendTo(titleBar);
          }
        }

        // Display the container.
        $('<div>')
        .attr('id', cb.o.craqboxId)
        .css({ width: cb.o.width +'px' })
        .append(titleBar ? $(titleBar) : closeButton)
        .hide()
        .appendTo(document.body);

        // Display the content.
        $('<div>')
        .addClass(cb.o.contentClass)
        .append(content).hide().appendTo($('#'+ cb.o.craqboxId)).fadeIn(cb.o.inSpeed, function() {
          cb.o.completeCallback();
        });
        // Center and display our results to the screen.
        cb.center();
        $('#'+ cb.o.craqboxId).fadeTo(cb.o.inSpeed, 1.0);
      }
      // Bind the scroll event to the window.
      $(window).bind('scroll', cb.scroll).bind('resize', cb.scroll);
    };

    // Attach the Craqbox.
    if (cb.o.attachEvent) {
      $(a).bind(cb.o.attachEvent, function() { cb.build(); return false; });
    }

    return cb;
  };
})(jQuery);

/*
if (Drupal.jsEnabled) {
  $(document).ready(function() {
    $('td.view-field-node-title a').each(function() {
      var o = {
	type: 'node',
	closeButtonTitle: 'Close',
	closeButtonLabel: 'Close'
      };
      $(this).craqbox(o);

    });
  });
}
*/