/**
 * Plurk Widget
 * ------------
 *
 * Supported parameters:
 *
 *  - height      the height in pixels (has no effect if CSS is disabled)
 *  - no_css      set to "true" if you don't want any CSS applied
 *  - user_id     the user_id whose plurks we want to display
 *  - interval    the reloading interval in seconds (30 per default, 0
 *                for no reloading at all.)
 *  - small       set to "true" to enablee the small version of the widget.
 *
 * If you are an advanced user and want to style the widget with custom CSS,
 * here are the classes the widget uses:
 *
 * plurk-widget         the overall div that wraps the widget
 * plurk-logo           a div that is usually used to display the logo
 * plurk-timeline       the div containing the messages on the timeline
 * plurk-loading-pane   a div that is displayed while data is retrieved
 * plurk-message        a div that contains the message of a user
 * plurk-nickname       a link to the users's profile
 * plurk-qualifier      the span for the qualifier
 * plurk-qualifier-x    the span for the qualifier x (x == says, thinks etc)
 *
 * For further information, you can reference the css file at
 *      http://www.plurk.com/static/widget/widget.css
 *
 * (c) Copyright 2008 by Galt Networks.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

;(function() {
  
  // globals and constants
  var
    SERVER_URL = null,
    SCRIPT_REGEX = new RegExp('^(http://.*?)/static/widget/plurkwidget.js(?:\\?(.*?))$'),
    QUALIFIER_COLORS = {
      is:     '#e57c43', says:   '#E2560B', feels:  '#2D83BE',
      thinks: '#689CC1', wants:  '#8DB241', wishes: '#5BB017',
      has:    '#7A9A37', loves:  '#B20C0C', hates:  '#111111',
      asks:   '#8361bc', will:   '#B46DB9', was:    '#525252',
      had:    '#8C8C8C', likes:  '#CB2728', shares: '#A74949',
      gives:  '#620E0E'
    },
    TIME_UNITS = [
      [60 * 60 * 24 * 30, 'month'], [60 * 60 * 24 * 7, 'week'],
      [60 * 60 * 24, 'day'], [60 * 60, 'hour'], [60, 'minute']
    ],
    widget, lastRequest, fish, timeline, options, backside = null;

  // general purpose helpers
  function each(s, f) {
    if (!s) return; var r;
    if (s.length !== undefined)
      for (var x = 0, y = s.length; x < y; ++x) {
        if (typeof (r = f.call(s[x], x)) !== 'undefined')
          return r;
      }
    else for (var k in s)
      if (typeof (r = f.call(this, k, s[k])) !== 'undefined')
        return r;
  }
  function map(s, f) {
    var rv = [];
    each(s, function(a, b) { rv.push(f.call(this, a, b)); });
    return rv;
  }
  function urlencode(d) {
    return map(d, function(k, v) {
      return encodeURIComponent(k) + '=' + encodeURIComponent(v)
    }).join('&');
  }

  // formatting
  function timedelta(d) {
    var delta = ((new Date()).getTime() - d.getTime()) / 1000, value;
    return each(TIME_UNITS, function() {
      if ((value = Math.floor(delta / this[0])) > 0)
        return value + ' ' + this[1] + (value != 1 ? 's' : '');
    }) || '0 minutes';
  }

  // DOM
  function $N(n) { return document.getElementsByTagName(n)[0]; }
  function $E(n, a) {
    var rv = document.createElement(n);
    each(a, function(k, v) { rv.setAttribute(k, v); });
    return rv;
  }
  function $$E(p, n, a) { return p.appendChild($E(n, a)); }
  function $T(n, t) { n.appendChild(document.createTextNode(t)); return n; }
  function $H(n, h) { var t = $$E(n, 'span'); t.innerHTML = h; return n; }

  // CSS
  function css(n, a, c) {
    each(a, function(k, v) { n.style[k] = v; });
    if (c) n.className = c; return n;
  }
  function hide(e) { e.style.display = 'none'; return e; }
  function show(e) { e.style.display = ''; return e; }

  // events
  function on(obj, event, func) {
    obj['on' + event] = function(e) {
      e = e || window.event;
      func.call(this, e);
      e.cancelBubble = true;
      if (e.stopPropagation) e.stopPropagation();
      return false;
    };
    if (obj.captureEvents) obj.captureEvents(Event[event.toUpperCase()]);
  }

  // communication system
  if (!this.$__plurkWidgetReceiveData) {
    $__plurkWidgetReceivers = [];
    $__plurkWidgetReceiveData = function(data) {
      $__plurkWidgetReceivers[data.receiverID](data);
    }
  }
  var receiverID = $__plurkWidgetReceivers.length;
  $__plurkWidgetReceivers.push(function(data) {
    lastRequest.parentNode.removeChild(lastRequest);
    if (data.plurks) updatePlurks(data.plurks, data.private);
    lastRequest = null;
  });

  // widget code
  function initializeWidget() {
    options.small = options.small === 'true';
    if (options.no_css !== 'true')
      $$E($N('head'), 'link', {
        href: SERVER_URL + '/static/widget/widget.css',
        rel:  'stylesheet',
        type: 'text/css'
      });
    css(widget, {visibility: 'hidden'});
    widget.className += ' plurk-widget-' + (options.small ? 'small' : 'regular');
    var logo = css($$E(widget, 'a', {href: '#'}), {
      background: 'url(' + SERVER_URL + '/static/widget/plurk-widget-logo.gif) no-repeat -85px 0'
    }, 'plurk-logo');
    on(logo, 'click', showBackside);
    timeline = css($$E(widget, 'div'), {
      height:     (options.height || (options.small ? 80 : 300)) + 'px'
    }, 'plurk-timeline');
    if (options.small) {
      var message = css($$E(widget, 'div'), null, 'plurk-small-message');
      $T(message, 'What\'s plurk you\'re asking?  A funky way to share your ' +
         'thoughts with your friends. Just ');
      $T($$E(message, 'a', {'href': 'http://www.plurk.com/'}), 'follow me');
      $T(message, ' and get started.');
    }
    fish = css($$E(timeline, 'div'), {
      background: 'url(' + SERVER_URL + '/static/loading.gif) ' +
                  'no-repeat center center',
      height:     '90px'
    }, 'plurk-loading-pane'),
    callLink = $$E(widget, 'div'),
    callLink.innerHTML = '<a href="'+ SERVER_URL + '/redeemByWidget?from_uid=' + options.user_id +'">Sign up at plurk.com</a> to' +
    ' follow and respond to these plurks',
    callTo = css(callLink, null, 'call-action');
    requestPlurks();
    if (options.interval && options.interval !== '0')
      setInterval(requestPlurks, (parseInt(options.interval, 10) || 30) * 1000);
  }

  function requestPlurks() {
    if (lastRequest || backside !== null) return;
    hide(fish);
    lastRequest = $$E($N('head'), 'script', {
      type: 'text/javascript',
      src:  SERVER_URL + '/API/Widget.getUserPlurks?user_id=' +
            options.user_id + '&receiver_id=' + receiverID +
            '&per_chunk=' + (options.small ? 1 : 10)
    });
  }

  function updatePlurks(plurks, is_private) {
    timeline.innerHTML = '';
    timeline.appendChild(show(fish));
    if (plurks.length) each(plurks, function(idx) {
      var plurk = css($$E(timeline, 'div'), null, 'plurk-message');      
      $T(css($$E(plurk, 'a', {href: SERVER_URL + '/' + this.username}),
         null, 'plurk-nickname'), this.username);
      if (this.qualifier != ':') {
        $H(plurk, '&nbsp;');
        var shade = QUALIFIER_COLORS[this.en_qualifier];
        $T(css($$E(plurk, 'span'), {
          backgroundColor:  shade,
          padding:          '0 3px 0 3px',
          color:            'white'
        }, 'plurk-qualifier plurk-qualifier-' + this.en_qualifier),
           this.qualifier);
      }
      $H(plurk, '&nbsp;' + this.content);
      $T($$E($T(css($$E(plurk, 'div'), null, 'plurk-meta'),
         timedelta(this.pub_date) + ' ago | '), 'a', {
        href: SERVER_URL + '/p/' + (this.id).toString(36),
        target: '_blank'
      }), this.responses == 1 ? '1 response' : this.responses + ' responses');
    });
    else {
      var empty = css($$E(timeline, 'div'), null, 'plurk-empty');
      $T($$E(empty, 'strong'), 'Ouch. ');
      $T(empty, is_private
        ? 'I\'m sorry.  Your timeline is private.  Nobody can read your plurks. ' +
          'There is nothing this widget can display.'
        : 'Currently you don\'t have any plurks to be displayed. Start plurking now :).'
      );
    }
    hide(fish);
    css(widget, {visibility: 'visible'});
  }

  function showBackside() {
    each(widget.childNodes, function() { hide(this) });
    backside = css($$E(widget, 'div'), {
      background:   '#9E4414',
      color:        'white',
      height:       '100%',
      margin:		'-34px 0 0 0'
    });
    each([
      'Plurk is a quick and easy way to keep in touch with your family and ' +
      'friends.',
      'Too much hassle or don\'t have time to blog?  Getting tired of ' +
      'social networks because instead of getting real life updates of ' +
      'your friends, you get tons of spam?',
      'A constant update of life!  Don\'t miss out.'
    ], function() { $T(css($$E(backside, 'p'), {
      padding:      '10px 10px 0 10px',
      lineHeight:   '1.5',
      margin:       '0'
    }), this); });
    var buttons = css($$E(backside, 'div'), {
      textAlign:    'center',
      padding:      '10px 0'
    });
    css($$E($$E(buttons, 'a', {href: SERVER_URL + '/redeemByWidget?from_uid=' + options.user_id}), 'img', {
      src: SERVER_URL + '/static/widget/plurk-widget-signup.png'}),
      {border: 'none'});
    on(css($$E(buttons, 'img', {src: SERVER_URL +
      '/static/widget/plurk-widget-back.png'}),
      {marginLeft: '4px', cursor: 'pointer'}),
      'click', hideBackside);
  }

  function hideBackside() {
    widget.removeChild(backside);
    each(widget.childNodes, function() { show(this); });
    backside = null;
  }

  // widget setup
  widget = css($E('div'), null, 'plurk-widget');
  (options = each(document.getElementsByTagName('script'), function() {
    if (SCRIPT_REGEX.exec(this.src)) {
      var t, p = {__node__: this};
      SERVER_URL = RegExp.$1;
      return each((RegExp.$2 || '').split('&'), function() {
        p[(t = this.split('=', 2))[0]] = t[1] || '';
      }), p;
    }
  })).__node__.parentNode.replaceChild(widget, options.__node__);
  initializeWidget();

})();
