'use strict';
/*jslint white: true, onevar: true, undef: true, nomen: true, eqeqeq: true,
  plusplus: true, bitwise: true, regexp: true, strict: true, newcap: true,
  immed: true, indent: 2 */
/*global document $ GM_openInTab*/
// ==UserScript==
// @name UEH event scraper
// @namespace http://unitedelementsofhate.net/javscripts/greasemonkey
// @description Scrape event data from an ever growing collection of sites, use
//   this data to prefill the form on unitedelementsofhate.net/event
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
// @include http://tivoli.nl/agenda/informatie/atid/*
// @include http://www.tivoli.nl/agenda/informatie/atid/*
// @include http://adnoiseam.net/news/*
// @include http://www.adnoiseam.net/news/*
// @include http://adnoiseam.net/content/view/*
// @include http://www.adnoiseam.net/content/view/*
// @include http://last.fm/event/*
// @include http://www.last.fm/event/*
// @include http://013.nl/event/*
// @include http://www.013.nl/event/*
// @include http://occii.org/nightdetails.asp?*
// @include http://www.occii.org/nightdetails.asp?*
// @include http://facebook.com/event.php?*
// @include http://www.facebook.com/event.php?*
// @include http://watt-rotterdam.nl/*
// @include http://www.watt-rotterdam.nl/*
// ==/UserScript==

(function () {
  /**
   * EventForm
   */
  function EventForm(event) {
    this.host = "http://unitedelementsofhate.net";
    this.path = "/events/new";
    this.event = event;
  }
  EventForm.prototype.getQueryString = function getQueryString() {
    return $.param(this.eventToDict(this.event));
  };
  EventForm.prototype.eventToDict = function eventToDict(event) {
    return {
      'event[title]': event.title || '',
      'event[local_start_date(3i)]': event.localStartDate.day || '',
      'event[local_start_date(2i)]': event.localStartDate.month || '',
      'event[local_start_date(1i)]': event.localStartDate.year || '',
      'event[local_start_date(4i)]': event.localStartDate.hour || '',
      'event[local_start_date(5i)]': event.localStartDate.minute || '',
      'event[local_end_date(3i)]': event.localEndDate.day || '',
      'event[local_end_date(2i)]': event.localEndDate.month || '',
      'event[local_end_date(1i)]': event.localEndDate.year || '',
      'event[local_end_date(4i)]': event.localEndDate.hour || '',
      'event[local_end_date(5i)]': event.localEndDate.minute || '',
      'event[venue]': event.venue || '',
      'event[city]': event.city || '',
      'event[country]': event.country || '',
      'event[state]': event.state || '',
      //'event[timezone_identifier]': event.timezoneIdentifier || '',
      'event[url]': event.url || '',
      'event[body]': event.body || '',
      'event[author_name]': event.authorName || '',
      'event[author_email]': event.authorEmail || ''
    };
  };
  EventForm.prototype.getUrl = function getUrl() {
    return this.host + this.path + '?' + this.getQueryString();
  };

  /**
   * EventDate
   */
  function EventDate() {
    this.day = null;
    this.month = null;
    this.year = null;
    this.hour = null;
    this.minute = null;
  }

  /**
   * Event
   */
  function Event() {
    this.title = null;
    this.localStartDate = new EventDate();
    this.localEndDate = new EventDate();
    this.venue = null;
    this.city = null;
    this.country = null;
    this.state = null;
    this.timezoneIdentifier = null;
    this.url = null;
    this.body = null;
    this.authorName = 'Jaap';
    this.authorEmail = 'jaap@u-e-h.net';
  }

  /**
   * EventScraper
   */
  function EventScraper() {
    this.callbacks = {};
    this.event = new Event();
    // this.event.title
    // this.event.localStartDate
    // this.event.localEndDate
    // this.event.venue
    // this.event.city
    // this.event.country
    // this.event.state
    this.event.url = document.location.href;
    // this.event.body
  }
  EventScraper.prototype.registerCallback = function registerCallback(type, fn) {
    if (!this.callbacks[type]) {
      this.callbacks[type] = [];
    }
    this.callbacks[type].push(fn);
  };
  EventScraper.prototype.doCallback = function doCallback(type, returnValue) {
    var callbacks = (this.callbacks[type] || []).slice(0), callback = null;
    while ((callback = callbacks.pop())) {
      callback(returnValue);
    }
  };
  EventScraper.prototype.utils = {
    'strToTitleCase': function strToTitleCase(str) {
      return str.replace(/([\w&`'‘’"“.@:\/\{\(\[<>_]+-? *)/g, function (match, p1, index, title) {
        if (index > 0 && title.charAt(index - 2) !== ":" &&
          match.search(/^(a(nd?|s|t)?|b(ut|y)|en|for|i[fn]|o[fnr]|t(he|o)|vs?\.?|via)[ \-]/i) > -1) {
          return match.toLowerCase();
        }
        if (title.substring(index - 1, index + 1).search(/['"_{(\[]/) > -1) {
          return match.charAt(0) + match.charAt(1).toUpperCase() + match.substr(2);
        }
        if (match.substr(1).search(/[A-Z]+|&|[\w]+[._][\w]+/) > -1 ||
          title.substring(index - 1, index + 1).search(/[\])}]/) > -1) {
          return match;
        }
        return match.charAt(0).toUpperCase() + match.substr(1);
      });
    },
    'formatBody': function formatBody(str) {
      return $.trim(str.replace(/<br>/g, "\n"));
    }
  };
  EventScraper.prototype.scrape = function scrape() {
    this.doCallback('scrape', this.event);
    return this.event;
  };
  EventScraper.prototype.drawGui = function drawGui() {
    var selector = arguments[0], container = $(selector)[0],
      that = this, button = null;
    container.innerHTML += '<button type="button" class="scrape">Scrape</button>';
    button = $('.scrape', container);
    button.bind('click', function () {
      that.scrape();
    });
  };

  /**
   * TivoliEventScraper
   */
  function TivoliEventScraper() { }
  TivoliEventScraper.prototype = new EventScraper();
  TivoliEventScraper.prototype.constructor = TivoliEventScraper;
  TivoliEventScraper.prototype.drawGui = function () {
    EventScraper.prototype.drawGui.call(this, '#container .topbar');
  };
  TivoliEventScraper.prototype.scrape = function scrape() {
    var date = null,
      that = this,
      body = [];
    this.event.title = this.utils.strToTitleCase(
      $('#content .page-agenda-title')[0].innerHTML.toLowerCase()
    );
    date = $('#content .page-agenda-date')[0].innerHTML.split(' ');
    this.event.localStartDate.day = parseInt(date[1], 10);
    this.event.localStartDate.month = TivoliEventScraper.MONTHS[date[2]];
    this.event.localStartDate.year = parseInt(date[3], 10);
    this.event.localStartDate.hour = 23;
    this.event.localStartDate.minute = 0;
    this.event.venue = $('#content .page-agenda-location2 a')[0].innerHTML;
    this.event.city = 'Utrecht';
    this.event.country = 'Netherlands';
    $.each($('#content .page-column-right p'), function (k, v) {
      body.push(that.utils.formatBody(v.innerHTML));
    });
    this.event.body = body.join("\n\n");
    this.doCallback('scrape', this.event);
    return this.event;
  };
  TivoliEventScraper.MONTHS = {'jan': 1, 'feb': 2, 'mrt': 3, 'apr': 4, 'mei': 5,
    'jun': 6, 'jul': 7, 'aug': 8, 'sep': 9, 'okt': 10, 'nov': 11, 'dec': 12};


  /**
   * AdnoiseamEventScraper
   */
  function AdnoiseamEventScraper() { }
  AdnoiseamEventScraper.prototype = new EventScraper();
  AdnoiseamEventScraper.prototype.constructor = TivoliEventScraper;
  AdnoiseamEventScraper.prototype.drawGui = function () {
    EventScraper.prototype.drawGui.call(this, '.MAIN .rowbox .contentpaneopen td:first-child');
  };
  AdnoiseamEventScraper.prototype.scrape = function scrape() {
    var dataline, date, title_location, location = null,
      that = this,
      body = [];

    dataline = $.trim($('.MAIN .rowbox .contentpaneopen .contentheading')[0].innerHTML).split(':');
    date = dataline[0].split(' ');
    title_location = dataline[1].split(' in ');
    location = title_location[1].split(', ');

    this.event.title = this.utils.strToTitleCase(title_location[0]);
    this.event.localStartDate.day = parseInt(date[1], 10);
    this.event.localStartDate.month = AdnoiseamEventScraper.MONTHS[date[0]];
    this.event.localStartDate.year = new Date().getFullYear();
    this.event.localStartDate.hour = 23;
    this.event.localStartDate.minute = 0;
    this.event.city = this.utils.strToTitleCase(location[0]);
    this.event.country = AdnoiseamEventScraper.COUNTRIES[location[1]];
    $.each($('.MAIN .rowbox .contentpaneopen .introtext'), function (k, v) {
      body.push(that.utils.formatBody(v.innerHTML));
    });
    $.each($('.MAIN .rowbox .contentpaneopen .introtext + img'), function (k, v) {
      body.push('[img]' + v.src + '[/img]');
    });
    this.event.body = body.join("\n\n");
    this.doCallback('scrape', this.event);
    return this.event;
  };
  AdnoiseamEventScraper.MONTHS = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5,
    'Jun': 6, 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12};
  AdnoiseamEventScraper.COUNTRIES = {'NL': 'Netherlands', 'BE': 'Belgium',
    'DE': 'Germany', 'UK': 'United Kingdom', 'USA': 'United States of America',
    'ES': 'Spain', 'PL': 'Poland', 'GR': 'Greece'};

  /**
   * LastFmEventScraper
   */
  function LastFmEventScraper() {}
  LastFmEventScraper.prototype = new EventScraper();
  LastFmEventScraper.prototype.constructor = LastFmEventScraper;
  LastFmEventScraper.prototype.drawGui = function () {
    EventScraper.prototype.drawGui.call(this, '#details .buttons');
  };
  LastFmEventScraper.prototype.scrape = function scrape() {
    var date = $('#calsheet .dtstart')[0].getAttribute('title'),
      body = [],
      that = this;
    this.event.title = this.utils.strToTitleCase($('#details .summary')[0].innerHTML);
    this.event.localStartDate.day = +date.substr(6, 2);
    this.event.localStartDate.month =  +date.substr(4, 2);
    this.event.localStartDate.year = +date.substr(0, 4);
    this.event.localStartDate.hour = +date.substr(9, 2);
    this.event.localStartDate.minute = +date.substr(11, 2);
    this.event.venue = $('#venue .fn')[0].innerHTML;
    this.event.city = $('#venue .locality')[0].innerHTML;
    this.event.country = $('#venue .country-name')[0].innerHTML;
    if ($('#details .url').length) {
      this.event.url = $('#details .url')[0].href;
    }
    $.each($('#wikiAbstract, #wikiSecondPart'), function (k, v) {
      var node = v.firstChild;
      while (node) {
        if (node.nodeValue && $.trim(node.nodeValue)) {
          body.push(that.utils.formatBody(node.nodeValue));
        }
        node = node.nextSibling;
      }
    });
    $.each($('#largePoster a:contains("original")'), function (k, v) {
      body.push('[img]' + v.href + '[/img]');
    });
    this.event.body = body.join("\n");
    this.doCallback('scrape', this.event);
    return this.event;
  };

  /**
   * O13EventScraper
   */
  function O13EventScraper() { }
  O13EventScraper.prototype = new EventScraper();
  O13EventScraper.prototype.constructor = O13EventScraper;
  O13EventScraper.prototype.drawGui = function drawGui() {
    EventScraper.prototype.drawGui.call(this, '#share-this');
  };
  O13EventScraper.prototype.scrape = function scrape() {
    var date = $('#event .date')[0].innerHTML.split(' '),
      body = [],
      that = this;
    this.event.title = $('#event .title')[0].innerHTML;
    this.event.localStartDate.day = +date[1];
    this.event.localStartDate.month =  O13EventScraper.MONTHS[date[2]];
    this.event.localStartDate.year = 2000 + (+date[3]);
    this.event.localStartDate.hour = 22;
    this.event.localStartDate.minute = 0;
    this.event.venue = '013';
    this.event.city = 'Tilburg';
    this.event.country = 'Netherlands';
    body.push("Lineup:\n" + $('#event .lineup')[0].innerHTML.replace(/\+/g, "\n"));
    $.each($('#event, #general-info'), function (k, v) {
      var node = v.firstChild;
      while (node) {
        if (node.nodeValue && $.trim(node.nodeValue)) {
          body.push(that.utils.formatBody(node.nodeValue.replace(/\|/g, '')));
        }
        node = node.nextSibling;
      }
    });
    this.event.body = body.join("\n\n");
    this.doCallback('scrape', this.event);
    return this.event;
  };
  O13EventScraper.MONTHS = {'jan': 1, 'feb': 2, 'mrt': 3, 'apr': 4, 'mei': 5,
    'jun': 6, 'jul': 7, 'aug': 8, 'sep': 9, 'okt': 10, 'nov': 11, 'dec': 12};

  /**
   * OcciiEventScraper
   */
  function OcciiEventScraper() { }
  OcciiEventScraper.prototype = new EventScraper();
  OcciiEventScraper.prototype.constructor = OcciiEventScraper;
  OcciiEventScraper.prototype.drawGui = function drawGui() {
    EventScraper.prototype.drawGui.call(this, 'h1');
  };
  OcciiEventScraper.prototype.scrape = function scrape() {
    var date = $('.eventDescr')[0].innerHTML.split(' '),
      body = [],
      that = this;
    this.event.title = $('.eventName')[0].innerHTML;
    this.event.localStartDate.day = parseInt(date[1], 10);
    this.event.localStartDate.month = OcciiEventScraper.MONTHS[date[3]];
    this.event.localStartDate.year = +date[4];
    this.event.localStartDate.hour = 22;
    this.event.localStartDate.minute = 0;
    this.event.venue = 'OCCII';
    this.event.city = 'Amsterdam';
    this.event.country = 'Netherlands';
    $.each($('.actName, .eventDetails, .sterlink2, .actDescr'), function (k, v) {
      if (v.className === 'actName') {
        body.push("\n" + that.utils.strToTitleCase(v.innerHTML.toLowerCase()));
      }
      else if (v.href) {
        body.push(v.href);
      }
      else {
        body.push(that.utils.formatBody(v.innerHTML));
      }
    });
    this.event.body = body.join("\n");
    this.doCallback('scrape', this.event);
    return this.event;
  };
  OcciiEventScraper.MONTHS = {'January': 1, 'February': 2, 'March': 3, 'April': 4,
    'May': 5, 'June': 6, 'July': 7, 'August': 8, 'September': 9, 'October': 10,
    'November': 11, 'December': 12};

  /**
   * FacebookEventScraper
   */
  function FacebookEventScraper() { }
  FacebookEventScraper.prototype = new EventScraper();
  FacebookEventScraper.prototype.constructor = FacebookEventScraper;
  FacebookEventScraper.prototype.drawGui = function drawGui() {
    EventScraper.prototype.drawGui.call(this, '#event_profile_actions');
  };
  FacebookEventScraper.prototype.scrapeTime = function scrapeTimes(selector) {
    var node, parts, date, year_time, time, hour;
      node = $(selector)[0];
    if (!node || !node.nextSibling.nextSibling) {
      return;
    }
    parts = node.nextSibling.nextSibling.innerHTML.split(', ');
    date = parts[1].split(' ');
    year_time = parts[2].split(' ');
    time = year_time[2].split(':');
    hour = time[1].indexOf('pm') > -1 ? +time[0] + 12 : +time[0];
    return {
      'day': +date[1],
      'month': FacebookEventScraper.MONTHS[date[0]],
      'year': year_time[0],
      'hour': hour,
      'minute': time[1]
    }
  }
  FacebookEventScraper.prototype.scrape = function scrape() {
    var body = [],
      that = this,
      start = this.scrapeTime("td.label:contains('Start Time:')"),
      end = this.scrapeTime("td.label:contains('End Time:')");
    this.event.title = $('.event_profile_title h3')[0].innerHTML;
    if (start) {
      this.event.localStartDate.day = start.day;
      this.event.localStartDate.month = start.month;
      this.event.localStartDate.year = start.year;
      this.event.localStartDate.hour = start.hour;
      this.event.localStartDate.minute = start.minute;
    }
    if (end) {
      this.event.localEndDate.day = end.day;
      this.event.localEndDate.month = end.month;
      this.event.localEndDate.year = end.year;
      this.event.localEndDate.hour = end.hour;
      this.event.localEndDate.minute = end.minute;
    }
    $.each($('.description'), function (k, v) {
      body.push(that.utils.formatBody(v.innerHTML));
    });
    this.event.body = body.join("\n");
    this.doCallback('scrape', this.event);
    return this.event;
  };
  FacebookEventScraper.MONTHS = {'January': 1, 'February': 2, 'March': 3, 'April': 4,
    'May': 5, 'June': 6, 'July': 7, 'August': 8, 'September': 9, 'October': 10,
    'November': 11, 'December': 12};

  /**
   * WattEventScraper
   */
  function WattEventScraper() { }
  WattEventScraper.prototype = new EventScraper();
  WattEventScraper.prototype.constructor = WattEventScraper;
  WattEventScraper.prototype.drawGui = function () {
    EventScraper.prototype.drawGui.call(this, '.detail-foot');
  };
  WattEventScraper.prototype.scrape = function scrape() {
    var date = null,
      that = this,
      body = [];
    this.event.title = $('.detail-head h1')[0].innerHTML;
    date = $('.date')[0].innerHTML;
    this.event.localStartDate.day = parseInt(/<span>([0-9]+)<\/span>/.exec(date)[1], 10);
    this.event.localStartDate.month = parseInt(/<\/span>([0-9]+)/.exec(date)[1], 10);
    this.event.localStartDate.year = new Date().getFullYear();
    this.event.localStartDate.hour = 23;
    this.event.localStartDate.minute = 0;
    this.event.venue = 'Watt';
    this.event.city = 'Rotterdam';
    this.event.country = 'Netherlands';
    if ($('.detail-head h2')[0]) {
      body.push($('.detail-head h2')[0].innerHTML);
    }
    $.each($('.description'), function (k, v) {
      body.push(that.utils.formatBody(v.innerHTML));
    });
    this.event.body = body.join("\n\n");
    this.doCallback('scrape', this.event);
    return this.event;
  };

   /**
    * main
    */
  (function () {
    var scraper = null;
    switch (document.location.host) {
    case 'tivoli.nl':
    case 'www.tivoli.nl':
      scraper = new TivoliEventScraper();
      break;
    case 'adnoiseam.net':
    case 'www.adnoiseam.net':
      scraper = new AdnoiseamEventScraper();
      break;
    case 'last.fm':
    case 'www.last.fm':
      scraper = new LastFmEventScraper();
      break;
    case '013.nl':
    case 'www.013.nl':
      scraper = new O13EventScraper();
      break;
    case 'occii.org':
    case 'www.occii.org':
      scraper = new OcciiEventScraper();
      break;
    case 'facebook.com':
    case 'www.facebook.com':
      scraper = new FacebookEventScraper();
      break;
    case 'watt-rotterdam.nl':
    case 'www.watt-rotterdam.nl':
      scraper = new WattEventScraper();
      break;
    }

    if (scraper !== null) {
      scraper.registerCallback('scrape', function scrapeCallBack(event) {
        GM_openInTab(new EventForm(event).getUrl());
      });
      scraper.drawGui();
    }
  }());
}());

