/* Sets up form and/or video on static main page. */

(function() {
  'use strict';

  var shorteners, expanders, expander_regex, full_url_regex,
      current_video_url = null;

  shorteners = [
    [new RegExp('^https?://a\\.pomf\\.se/([0-9A-Za-z/]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'pf'],
    [new RegExp('^https?://(?:2\\.)?kastden\\.org/loopvid/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'kd'],
    [new RegExp('^https?://lv\\.kastden\\.org/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'lv'],
    [new RegExp('^https?://(?:docs|drive)\\.google\\.com/file/d/([0-9A-Za-z_-]+)'), 'gd'],
    [new RegExp('^https?://(?:docs|drive)\\.google\\.com/uc\\?export=download&id=([0-9A-Za-z_-]+)'), 'gd'],
    [new RegExp('^https?://googledrive\\.com/host/([0-9A-Za-z_-]+/[0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'gh'],
    [new RegExp('^https?://dl\\.dropboxusercontent\\.com/u/(\\d+/[0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'db'],
    [new RegExp('^https?://dl\\.dropboxusercontent\\.com/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'dx'],
    [new RegExp('^https?://i\\.4cdn\\.org/([^/]+)/(\\d+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'fc'],
    [new RegExp('^https?://copy\\.com/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'cp'],
    [new RegExp('^https?://[^.]+\\.gfycat\\.com/([A-Za-z]+)\\.(?:webm|mp4|ogg|mp3)'), 'gc'],
    [new RegExp('^https?://webmup\\.com/([0-9A-Za-z._-]+)/vid.webm'), 'wu'],
    [new RegExp('^https?://i\\.imgur\\.com/([0-9A-Za-z._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'ig'],
    [new RegExp('^https?://b\\.1339\\.cf/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), '1c'],
    [new RegExp('^https?://a\\.pomf\\.cat/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'pc'],
    [new RegExp('^https?://u\\.pomf\\.is/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'pi'],
    [new RegExp('^https?://u\\.nya\\.is/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'ni'],
    [new RegExp('^https?://webm\\.land/media/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'wl'],
    [new RegExp('^https?://kordy\\.kastden\\.org/loopvid/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'ko'],
    [new RegExp('^https?://media\\.8ch\\.net/file_store/([0-9a-f]{64})(?:\\.(?:webm|mp4|ogg|mp3))'), 'ic'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/pf/([0-9A-Za-z/]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'pf'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/gc/([0-9A-Za-z/]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'gc'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/nn/([0-9A-Za-z/]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'nn'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/ky/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'ky'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/mf/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'mf'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/m2/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'm2'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/pc/([0-9A-Za-z/._-]+)(?:\\.(?:webm|mp4|ogg|mp3))'), 'pc'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/pi/([0-9A-Za-z/]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'pi'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/ni/([0-9A-Za-z/]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'ni'],
    [new RegExp('^https?://kastden\\.org/_loopvid_media/mm/([0-9A-Za-z/]+)(?:\\.(?:webm|mp4|ogg|mp3))$'), 'mm']
  ];

  function shorten_url(url) {
    var regex, host, match, i, j,
        shortened_url = null;

    for (i = 0; i<shorteners.length; i++) {
      regex = shorteners[i][0];
      host = shorteners[i][1];

      // if the url matches the regex, build and return shortened url
      match = regex.exec(url);
      if (match) {
        // the format is host/group1/group2/...
        shortened_url = host;
        /* notice the first group is match[1], not match[0] (which is the whole
         * matched string); also notice there will always be at least one group */
        for (j=1; j<match.length; j++) {
          shortened_url += '/'+match[j];
        }
        break;
      }
    }

    if (shortened_url) {
      return shortened_url;
    }
    else {
      // no shortener matched, return original
      return url;
    }
  }

  expanders = {
    'kd': {
      'url_parts': ['https://kastden.org/loopvid/'],
      'has_extension': true,
    },
    'lv': {
      'url_parts': ['https://lv.kastden.org/'],
      'has_extension': true,
    },
    'gd': {
      'url_parts': ['https://docs.google.com/uc?export=download&id='],
      'has_extension': false,
    },
    'gh': {
      'url_parts': ['https://googledrive.com/host/'],
      'has_extension': true,
    },
    'db': {
      'url_parts': ['https://dl.dropboxusercontent.com/u/'],
      'has_extension': true,
    },
    'dx': {
      'url_parts': ['https://dl.dropboxusercontent.com/'],
      'has_extension': true,
    },
    'fc': {
      'url_parts': ['https://i.4cdn.org/', '/', '.webm'],
      'has_extension': false,
    },
    'nn': {
      'url_parts': ['https://kastden.org/_loopvid_media/nn/'],
      'has_extension': true,
    },
    'cp': {
      'url_parts': ['https://copy.com/'],
      'has_extension': true,
    },
    'wu': {
      'url_parts': ['http://webmup.com/', '/vid.webm'],
      'has_extension': false,
    },
    'ig': {
      'url_parts': ['https://i.imgur.com/'],
      'has_extension': true,
    },
    'ky': {
      'url_parts': ['https://kastden.org/_loopvid_media/ky/'],
      'has_extension': true,
    },
    'mf': {
      'url_parts': ['https://kastden.org/_loopvid_media/mf/'],
      'has_extension': true,
    },
    'm2': {
      'url_parts': ['https://kastden.org/_loopvid_media/m2/'],
      'has_extension': true,
    },
    '1c': {
      'url_parts': ['http://b.1339.cf/'],
      'has_extension': true,
    },
    'pc': {
      'url_parts': ['https://kastden.org/_loopvid_media/pc/'],
      'has_extension': true,
    },
    'pi': {
      'url_parts': ['https://kastden.org/_loopvid_media/pi/'],
      'has_extension': true,
    },
    'ni': {
      'url_parts': ['https://kastden.org/_loopvid_media/ni/'],
      'has_extension': true,
    },
    'wl': {
      'url_parts': ['http://webm.land/media/'],
      'has_extension': true,
    },
    'ko': {
      'url_parts': ['https://kordy.kastden.org/loopvid/'],
      'has_extension': true,
    },
    'mm': {
      'url_parts': ['https://kastden.org/_loopvid_media/mm/'],
      'has_extension': true,
    },
    'ic': {
      'url_parts': ['https://media.8ch.net/file_store/'],
      'has_extension': true,
    },
    // custom expanders
    'pf': {
      'custom_expander' : function(groups) {
        var i, urls = ['https://kastden.org/_loopvid_media/pf/', 'http://a.pomf.se/'],
            links = [], base = groups[0];

        for (i=0; i<urls.length; i++) {
          links.push(urls[i]+base+'.webm');
          links.push(urls[i]+base+'.mp4');
        }
        return links;
      }
    },
    'gc': {
      'custom_expander' : function(groups) {
        /* gc/base -> https://(giant|fat|zippy).gfycat.com/base.(webm|mp4) */
        var i, prefix = ['giant', 'fat', 'zippy'],
            links = [], base = groups[0];

        for (i=0; i<prefix.length; i++) {
          links.push('https://'+prefix[i]+'.gfycat.com/'+base+'.webm');
          links.push('https://'+prefix[i]+'.gfycat.com/'+base+'.mp4');
        }
        return links;
      }
    }
  };

  expander_regex  = new RegExp('^/?(?:[a-z]{2}/)?('+ Object.keys(expanders).join('|') + ')/([0-9A-Za-z/.,_-]+)(?:&.*)?$');
  full_url_regex = new RegExp('^[a-z]+://[^.]+\\.[^.]+.+/.+');

  function build_full_urls(acronym, groups) {
    /* Put together full urls based on the components of the shortened url.
     *
     * acronym is one of the acronyms listed in expanders
     * groups is a list of groups matched in the original shortener regex */
    var i, max_length, parts, url;

    // if host has a custom expander, use it
    if ('custom_expander' in expanders[acronym]) {
      return expanders[acronym].custom_expander(groups);
    }

    parts = expanders[acronym].url_parts;
    url = '';

    // interleave url parts and groups to get back the original url
    max_length = Math.max(parts.length, groups.length);
    for (i=0; i<max_length; i++) {
      if (i < parts.length) {
        url += parts[i];
      }
      else {
        // for urls containing subdirs, we must add back the slashes we removed
        url += '/';
      }

      if (i < groups.length) {
        url += groups[i];
      }
    }

    if (expanders[acronym].has_extension) {
      return [url+'.webm', url+'.mp4'];
    }
    else {
      return [url];
    }
  }

  function expand_urls(url, fix_url) {
    /* expand shortened url into a list of full urls */
    var match, acronym, groups_str, groups, group_delim, list_delim, groups_list, urls, i, correct_url;

    group_delim = '/';
    list_delim = ',';

    match = full_url_regex.exec(url);
    if (match) {
      // already expanded; nothing to do
      return [url];
    }

    match = expander_regex.exec(url);
    if (match) {
      acronym = match[1];
      groups_str = match[2].replace(/\.(webm|mp4)$/, '');
      groups_list = groups_str.split(list_delim);

      // fix current_video_url if necessary
      correct_url = acronym+'/'+groups_str;
      if (current_video_url !== correct_url) {
        current_video_url = correct_url;
        if (fix_url) {
          update_location(true);
        }
      }

      // build full urls
      urls = [];
      for (i=0; i<groups_list.length; i++) {
        groups = groups_list[i].split(group_delim);
        urls = urls.concat(build_full_urls(acronym, groups));
      }
      return urls;
    }

    // neither full url nor shortened url
    return null;
  }

  function setup_video(fix_url) {
    var sources, i, video, sources_list, elem, elem2;

    sources = expand_urls(current_video_url, fix_url);

    // handle broken url
    if (!sources) {
      current_video_url = null;
      // navigate back to the form
      cleanup_form_video();
      setup_form();
      update_location(true);
      return false;
    }

    // create new video
    /* note that we'll delay firing the newVideoCreated event until the sources
     * are in place */
    video = new_video();

    // hide form and unhide video
    document.getElementById('form_wrapper').classList.add('hidden');
    document.getElementById('video_wrapper').classList.remove('hidden');
    document.body.classList.add('play_body');
    document.getElementById('footer').classList.remove('hidden');

    // unhide footer
    document.getElementById('footer').classList.remove('hidden');
    document.getElementById('footer_expander').parentNode.classList.add('hidden');

    // mark video container as waiting for video to load
    document.getElementById('video_container0').classList.add('waiting_for_video');

    // add sources to video and to list in failed to load div
    sources_list = document.getElementById('failed_to_load_sources');

    for (i=0; i<sources.length; i++) {
      elem = document.createElement('SOURCE');
      elem.src = sources[i];
      video.appendChild(elem);

      elem2 = document.createElement('LI');
      elem = document.createElement('A');
      elem.rel = "noreferrer";
      elem.href = sources[i];
      elem.appendChild(document.createTextNode(sources[i]));
      elem2.appendChild(elem);
      sources_list.appendChild(elem2);
    }
    video.appendChild(document.createTextNode('Your browser does not support the video tag.'));

    // fire custom event for other scripts to operate on the new video
    window.dispatchEvent(new window.Event('newVideoCreated'));

    return true;
  }

  function update_location(replace) {
    /* updates the current location based on current_video_url */
    var new_url;

    new_url = window.location.href.replace(window.location.hash, '');
    if (current_video_url) {
      new_url += '#' + current_video_url;
      document.title = current_video_url+' - loopvid';
    }
    else {
      document.title = 'loopvid';
    }

    if (!replace) {
      history.pushState({'title': document.title}, document.title, new_url);
    }
    else {
      history.replaceState({'title': document.title}, document.title, new_url);
    }
  }

  function submit_handler(event) {
    /* checks if video url is valid and if so, sets up the video */
    var url, shortened_url, message_area;

    event.preventDefault();

    url = document.getElementById('form_video_url').value;
    shortened_url = shorten_url(url);

    // test if url is valid by expanding it, which will return null if it is not
    if (!expand_urls(shortened_url)) {
      message_area = document.getElementById('messages');
      message_area.innerHTML = '';
      message_area.appendChild(document.createTextNode('Invalid url: '+url));
    }
    else {
      current_video_url = shortened_url;
      /* don't let setup_video() update the url in case of mistakes, since
       * we'll be updating it again in any case (also, so that the form's url
       * doesn't get replaced in history) */
      if (setup_video(false)) {
        update_location();
      }
    }
  }

  function setup_form() {
    var submit;

    document.getElementById('form_wrapper').classList.remove('hidden');

    document.getElementById('form').addEventListener('submit', submit_handler);

    submit = document.getElementById('submit_button');
    submit.addEventListener('click', submit_handler);
    submit.removeAttribute('disabled');
  }

  function new_video() {
    var video;
    video = document.createElement('VIDEO');
    video.className = 'scaled_video';
    video.loop = 'loop';
    video.controls = 'controls';
    video.preload = 'auto';
    video.autoplay = 'autoplay';
    video.id = 'video0';

    document.getElementById('video_container0').appendChild(video);

    return video;
  }

  function clear_videos() {
    /* make sure all videos are removed (there seems to be a firefox bug where
     * they'll remain playing in the background if you time a video change just
     * as the video loops) */
    var found, video;
    found = document.getElementsByTagName('video');
    while (found.length > 0) {
      video = found[0];
      // pause video
      video.pause();
      // remove sources
      while (video.firstChild) {
        video.removeChild(video.firstChild);
      }
      // remove video
      video.parentNode.removeChild(video);
    }
  }

  function cleanup_form_video(state) {
    /* put the page page at a clean state so that the setup_*() functions can
     * do their job properly */

    current_video_url = null;
    document.body.classList.remove('play_body');
    document.title = 'loopvid';
    if (state && 'title' in state) {
      document.title = state.title;
    }

    // delete video if it exists
    clear_videos();

    // hide form and video page
    document.getElementById('form_wrapper').classList.add('hidden');
    document.getElementById('video_wrapper').classList.add('hidden');


    // undo displaying failed to load info
    document.getElementById('failed_to_load_info').classList.add('hidden');
    document.getElementById('video_container0').classList.remove('hidden');

    // remove old sources
    document.getElementById('failed_to_load_sources').innerHTML = '';

    // remove old messages
    document.getElementById('messages').innerHTML = '';
  }

  function toggle_footer(event) {
    /* hides or unhides footer */
    var footer, expander;

    event.preventDefault();

    footer = document.getElementById('footer');
    expander = document.getElementById('footer_expander');

    if (footer.classList.contains('hidden')) {
      footer.classList.remove('hidden');
      expander.parentNode.classList.add('hidden');
    }
    else {
      footer.classList.add('hidden');
      expander.parentNode.classList.remove('hidden');
    }
  }

  function resetup_video_form(event) {
    /* Sets up either the video or the form, depending on whether a video was
     * specified or not. */
    var new_video_url;

    new_video_url = null;
    if (window.location.hash) {
      new_video_url = window.location.hash.replace('#', '');
    }

    /* check if there was a change in the video, otherwise, there's nothing to
     * do here */
    if (current_video_url !== new_video_url) {
      // clean up if we're coming back from a previous state
      if (event && event.type !== 'DOMContentLoaded') {
        cleanup_form_video(event.state);
      }

      current_video_url = new_video_url;
      if (current_video_url) {
        document.title = current_video_url+' - loopvid';
        /* since we won't update the location, we must have setup_video()
         * update it if the video url has mistakes */
        setup_video(true);
      }
      else {
        setup_form();
      }
    }
  }

  function get_parameter(name) {
    /* Extracts parameter from query string. Adapted from
     * http://stackoverflow.com/a/901144
     * Note that name should be regex safe. */
    var regex, results;
    regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
    results = regex.exec(window.location.search);
    return results === null ? null : decodeURIComponent(results[1].replace(/\+/g, ' '));
  }

  function fix_hash() {
    /* Looks for video, shortens it if necessary and replaces it at
     * location.hash */
    var current_url, shortened_url, new_url;

    // try old style /?url=
    current_url = get_parameter('url');

    // if hash is also present, use that
    if (window.location.hash) {
      current_url = window.location.hash.replace('#', '');
    }

    /* try to shorten and replace hash (even if we end up replacing it with the
     * same thing) */
    if (current_url) {
      shortened_url = shorten_url(current_url);
      new_url = '/#' + shortened_url;

      document.title = shorten_url+' - loopvid';
      history.replaceState({'title': document.title}, document.title, new_url);
    }
  }

  function setup(event) {
    /* initial setup */
    document.getElementById('footer_expander').addEventListener('click', toggle_footer);
    document.getElementById('footer_collapser').addEventListener('click', toggle_footer);

    fix_hash();

    current_video_url = null;
    /* if a video was specified, resetup_video_form() will take care of it,
     * otherwise we have to set up the form */
    if (window.location.hash) {
      resetup_video_form(event);
    }
    else {
      setup_form();
    }
  }

  document.addEventListener('DOMContentLoaded', setup);
  window.addEventListener('popstate', resetup_video_form);
  /* remove possible leftover video before unloading the page */
  window.addEventListener('unload', clear_videos);
}());
