if (!Object.keys) {
  Object.keys = function (obj) {
    var keys = [];
    for (i in obj) keys.push(i);
    return keys;
  }
}
if (!Array.prototype.forEach) {
  Array.prototype.forEach = function (cb) {
    for (var i=0;i<this.length;i++) {
      cb(this[i]);
    }
  }
}

var request = function (options, callback) {
  options.success = function (obj) {
    callback(null, obj);
  }
  options.error = function (err) {
    if (err) callback(err);
    else callback(true);
  }
  if (options.data && typeof options.data == 'object') {
    options.data = JSON.stringify(options.data)
  }
  if (!options.dataType) options.processData = false;
  if (!options.dataType) options.contentType = 'application/json';
  if (!options.dataType) options.dataType = 'json';
  $.ajax(options)
}

function prettyDate(time) {
  if (time.indexOf('.') !== -1) time = time.slice(0, time.indexOf('.'))+'Z'
  var date = new Date((time || "").replace(/-/g,"/").replace(/[TZ]/g," ")),
      date = new Date(date.getTime() - (date.getTimezoneOffset() * 1000 * 60))
      diff = (((new Date()).getTime() - date.getTime()) / 1000),
      day_diff = Math.floor(diff / 86400)
      ;
  
  if (day_diff === -1) return "now"
  if ( day_diff >= 31) return day_diff + ' days ago';
  if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 ) return;
  
  return day_diff == 0 && (
      diff < 60 && "just now" ||
      diff < 120 && "1 minute ago" ||
      diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
      diff < 7200 && "1 hour ago" ||
      diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
    day_diff == 1 && "Yesterday" ||
    day_diff < 7 && day_diff + " days ago" ||
    day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago";
}

function isGithubUrl(url) {
  return url.slice(0, 'http://github.com'.length) === 'http://github.com' ||
         url.slice(0, 'https://github.com'.length) === 'https://github.com' ||
         url.slice(0, 'git://github.com'.length) === 'git://github.com';
}

$.expr[":"].exactly = function(obj, index, meta, stack){ 
  return ($(obj).text() == meta[3])
}

var param = function( a ) {
  // Query param builder from jQuery, had to copy out to remove conversion of spaces to +
  // This is important when converting datastructures to querystrings to send to CouchDB.
  var s = [];
  if ( jQuery.isArray(a) || a.jquery ) {
    jQuery.each( a, function() { add( this.name, this.value ); });    
  } else { 
    for ( var prefix in a ) { buildParams( prefix, a[prefix] ); }
  }
  return s.join("&");
  function buildParams( prefix, obj ) {
    if ( jQuery.isArray(obj) ) {
      jQuery.each( obj, function( i, v ) {
        if (  /\[\]$/.test( prefix ) ) { add( prefix, v );
        } else { buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "") +"]", v )}
      });        
    } else if (  obj != null && typeof obj === "object" ) {
      jQuery.each( obj, function( k, v ) { buildParams( prefix + "[" + k + "]", v ); });        
    } else { add( prefix, obj ); }
  }
  function add( key, value ) {
    value = jQuery.isFunction(value) ? value() : value;
    s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
  }
}

function clearContent () {
  $('div#content').html('')
  $('div#totals').html('')
}

var app = {};
app.index = function () {
  var currentTerms = []
    , searchResults = {}
    , docs = {}
    , currentSearch = ''
    , lastSearchForPage = ''
    , limit = 15
    ;
  clearContent();
  $('div#content').html(
    '<div id="search-box">' +
      '<div id="search-box-title">Find packages...</div>' +
      '<div id="search-box-input">' +
        '<input id="search-input"></input>' +
        '<span class="browse-link">or <a href="/#/_browse/all">browse packages</a>.</span>' +
      '</div>' +
    '</div>' +
    '<div id="main-container">' +
      '<div id="results"></div>' +
      '<div class="spacer"></div>' +
      '<div id="top-packages">' +
        '<div id="latest-packages"><div class="top-title">Latest Updates</div></div>' +
        '<div id="top-dep-packages"><div class="top-title">Most Depended On</div></div>' +
      '</div>' +
      '<div class="spacer"></div>' +
    '</div>'
  )
  
  request({url:'/api/_all_docs?limit=0'}, function (err, resp) {
    $('div#totals').html('<a href="/#/_browse/all">' + (resp.total_rows - 1) +' total packages</a>')
  })
  
  request({url:'/_view/updated?descending=true&limit='+limit+'&include_docs=false'}, function (err, resp) {
    resp.rows.forEach(function (row) {
      $('<div class="top-package"></div>')
      .append('<div class="top-package-title"><a href="#/'+row.id+'">'+row.id+'</a></div>')
      .append('<div class="top-package-updated">'+prettyDate(row.key) +'</div>')
      .append('<div class="spacer"></div>')
      .appendTo('div#latest-packages')
    })
  })
  
  request({url:'/_list/dependencies_limit/dependencies?group=true&descending=true&list_limit='+limit}, function (err, resp) {
    var results = {};
    resp.rows.forEach(function (row) {
        $('<div class="top-package"></div>')
        .append('<div class="top-package-title"><a href="#/'+row.key+'">'+row.key+'</a></div>')
        .append('<div class="top-package-dep">'+row.value+'</div>')
        .append('<div class="spacer"></div>')
        .appendTo('div#top-dep-packages')
    })
  })
    
  var updateResults = function () {
    currentSearch = $('input#search-input').val().toLowerCase();
    currentTerms = $.trim(currentSearch).split(' ');
    if (lastSearchForPage === currentSearch) return;
    if (currentSearch == '') $('div#top-packages').show();
    else $('div#top-packages').hide();
    var docsInPage = {}
      , ranked = {}
      ;
    currentTerms.forEach(function (term) {
      if (searchResults[term] && searchResults[term] !== 'pending') {
        searchResults[term].forEach(function (id) {
          if (docs[id] !== 'pending') docsInPage[id] = docs[id]
        });
      }
    })
    for (i in docsInPage) {
      var doc = docsInPage[i];
      doc.rank = 0
      doc.tagsInSearch = [];
      if (doc.description) {
        doc.htmlDescription = doc.description.split('&').join('&amp;')
                                             .split('"').join('&quot;')
                                             .split('<').join('&lt;')
                                             .split('>').join('&gt;')
      }
      
      if (doc._id.toLowerCase() === currentSearch) doc.rank += 1000      
      
      if (doc['dist-tags'] && doc['dist-tags'].latest) {
        var tags = doc.versions[doc['dist-tags'].latest].keywords || doc.versions[doc['dist-tags'].latest].tags || [];
      } else { 
        var tags = [];
      }
      
      tags = tags.map(function (tag) {
          return tag.split('&').join('&amp;')
                    .split('"').join('&quot;')
                    .split('<').join('&lt;')
                    .split('>').join('&gt;')
      })
      currentTerms.forEach(function (t) {
        t = t.toLowerCase();
        if (doc._id.toLowerCase().indexOf(t.toLowerCase()) !== -1) doc.rank += 750;
        if (tags.indexOf(t) !== -1) {
          doc.rank += 300;
          doc.tagsInSearch.push(t);
        }
        if (doc.description && doc.description.toLowerCase().indexOf(t) !== -1) {
          doc.rank += 100;
          var i = 0;
          while (doc.htmlDescription.toLowerCase().indexOf(t, i) !== -1) {
            var i = doc.htmlDescription.toLowerCase().indexOf(t, i);
            doc.htmlDescription = 
                                ( doc.htmlDescription.slice(0, i) 
                                + '<span class="desc-term">'
                                + doc.htmlDescription.slice(i, i+t.length)
                                + '</span>'
                                + doc.htmlDescription.slice(i + t.length)
                                )
                                ;
            i = i + t.length + '<span class="desc-term"></span>'.length
          }
          
        }
        doc.tags = tags;
      })
      
      if (!ranked[doc.rank]) ranked[doc.rank] = [];
      ranked[doc.rank].push(doc);
    }
    
    $('div#results').html('');
    var keys = Object.keys(ranked);
    for (var i=0;i<keys.length;i++) keys[i] = parseInt(keys[i])
    keys.sort(function(a,b){return a - b;});
    keys.reverse();
    if (keys.length === 0) {
      $('div#results').html('<div>No Results</div>')
    }
    keys.forEach(function (i) { ranked[i].forEach(function (doc) {
      var result = $(
        '<div class="result-container">' +
          '<div class="result">' + 
            '<span class="result-name"><a href="#/'+doc._id+'">'+doc._id+'</a></span>' + 
            '<span class="result-desc">'+(doc.htmlDescription || '') + '</span>' +
            '<div class="result-tags"></div>' +
            '<div class="spacer"></div>' +
          '</div>' +
        '</div>' +
        '<div class="spacer"></div>'
      )
      
      if (doc.tags.length > 0) {
        doc.tags.forEach(function (tag) {
          result.find('div.result-tags').append('<span class="tag">'+tag+'</span>')
        })
      }
      
      result.appendTo('div#results')
      $('span.tag').click(function () {
        $('input#search-input').val($(this).text()).change();
      })
    })})
    
    lastSearchForPage = currentSearch;
  }  
  
  var handleChange = function () {
    currentSearch = $('input#search-input').val().toLowerCase();
    currentTerms = $.trim(currentSearch).split(' ')
    if (currentSearch === '') {
      $('div#results').html('')
      $('div#top-packages').show();
    }
    lastSearchForPage = ''
    var terms = currentTerms
      , c = currentSearch
      , tlength = terms.length
      ;

    terms.forEach(function (term) {
      if (!searchResults[term]) {
        searchResults[term] = 'pending'
        var qs = param(
          { startkey: JSON.stringify(term)
          , endkey: JSON.stringify(term+'ZZZZZZZZZZZZZZZZZZZ')
          , limit:25
          }
        )
        ;
        request({url:'/_list/search/search?'+qs}, function (err, resp) {
          var docids = [];
          searchResults[term] = [];
          resp.rows.forEach(function (row) {
            searchResults[term].push(row.key);
            row.value.name = row.value.name.toLowerCase();
            docs[row.key] = row.value;
            updateResults();
          })
          if (docids.length === 0) {
            lastSearchForPage = '';
            updateResults();
            return 
          }
          
        })
      } else {tlength -= 1}
    })
    if (tlength == 0) {lastSearchForPage = ''; updateResults()}
  }
  
  $('input#search-input').change(handleChange);
  $('input#search-input').keyup(handleChange)
  $("input#search-input").focus();
};

app.showPackage = function () {
  var id = this.params.id;
  clearContent();
  $('div#content').html('<div id="main-container"></div>')
  request({url:'/api/'+id}, function (err, doc) {
    var package = $('div#main-container')
    
    package.append('<div class="package-title">'+doc._id+'</div>')
    // package.append('<div class="package-description">'+doc.description+'</div>')
    
    if (doc['dist-tags'] && doc['dist-tags'].latest) {
      if (doc.versions[doc['dist-tags'].latest].homepage) {
        package.append('<div class="pkg-link"><a href="'+doc.versions[doc['dist-tags'].latest].homepage+'">'+doc.versions[doc['dist-tags'].latest].homepage+'</a>')
      }
    }
    
    if (typeof doc.repository === 'string') {
      repositoryUrl = doc.repository;
      doc.repository = {
        type: (isGithubUrl(repositoryUrl) ? 'git' : 'unknown'),
        url: repositoryUrl
      }
    }
    if (doc.repository && doc.repository.type === 'git' && isGithubUrl(doc.repository.url) ) {
          package.append('<div class="pkg-link"><a class="github" href="' + doc.repository.url.replace('.git', '').replace('git://', 'https://') + '">github</a></div>')
    }
     
    
    package.append('<div class="spacer"></div>')
    if (doc.time && doc.time.modified) {
      package.append('<div class="last-updated">Last updated: '+prettyDate(doc.time.modified)+'</div>')
    }
    if (doc.author && doc.author.name) {
      package.append('<div class="author">by: <a href="/#/_author/'+encodeURIComponent(doc.author.name)+'">'+doc.author.name+'</div>')
    }
    

    // 
    // if (doc.maintainers && doc.maintainers.length > 0) {
    //   var maintainers = $('<div class="package-maintainers"></div>').appendTo(package);
    //   doc.maintainers.forEach(function (m) {
    //     maintainers.append('<div class="package-maintainer">maintainer: '+m.name+'   </div>')
    //   })
    // }
    
    package.append(
      '<div id="versions-container">' + 
        '<div id="version-list"></div>' + 
        '<div id="version-info"></div>' +
        '<div class="spacer"></div>' +
      '</div>'
    )
    
    var showVersion = function (version) {
      var v = doc.versions[version];
      
      if (v.description) {
        v.htmlDescription = v.description.split('&').join('&amp;')
                                             .split('"').join('&quot;')
                                             .split('<').join('&lt;')
                                             .split('>').join('&gt;')
      } else {
        v.htmlDescription = ""
      }
      
      $('div#version-info').html(
        '<div class="version-info-cell">' +
          '<div class="version-info-key">Description</div>' +
          '<div class="version-info-value">'+v.htmlDescription+'</div>' +
        '</div>' + 
        '<div class="spacer"></div>' +
        '<div class="version-info-cell">' +
          '<div class="version-info-key">Version</div>' +
          '<div class="version-info-value">'+v.version+'</div>' +
        '</div>' + 
        '<div class="spacer"></div>'
      );
      
      if (v.tags) {
        var h = '[ ';
        v.tags.forEach(function (tag) {
          if (tag !== v.tags[0]) h += ', '
          h += ('<a href="/#/_tags/'+tag+'">'+tag+'</a>')
        })
        h += ' ]'
        $('div#version-info').append(
          '<div class="version-info-cell">' +
            '<div class="version-info-key">Tags</div>' +
            '<div class="version-info-value">' + h + '</div>' +
          '</div>' +
          '<div class="spacer"></div>' 
        )
      }
      
      if (v.dependencies) {
        var h = ''
        for (i in v.dependencies) {
          h += '<a class="dep-link" href="#/'+i+'">'+i+'</a> '
        }
        $('div#version-info').append('<div class="version-info-cell">' +
            '<div class="version-info-key">Dependencies</div>' +
            '<div class="version-info-value">' + h + '</div>' +
          '</div>' +
          '<div class="spacer"></div>'
        )
      }
      
      if (v.homepage) {
        $('div#version-info').append(
          '<div class="version-info-cell">' +
            '<div class="version-info-key">Homepage</div>' +
            '<div class="version-info-value">' + v.homepage + '</div>' +
          '</div>' +
          '<div class="spacer"></div>'
        )
      }
      if (v.repository) {
        if (typeof v.repository === 'string') {
          repositoryUrl = v.repository;
          v.repository = {
            type: (isGithubUrl(repositoryUrl) ? 'git' : 'unknown'),
            url: repositoryUrl
          };
        }
        $('div#version-info').append(
          '<div class="version-info-cell">' +
            '<div class="version-info-key">Repository</div>' +
            '<div class="version-info-value">' + 
              v.repository.type + ':    <a href="' + v.repository.url + '">'+ v.repository.url + '</a>' +
            '</div>' +
          '</div>' +
          '<div class="spacer"></div>'
        )
      }
      if (v.bugs) {
        var bugs = $(
          '<div class="version-info-cell">' +
            '<div class="version-info-key">Bugs</div>' +
            '<div class="version-info-value"></div>' +
          '</div>' +
          '<div class="spacer"></div>'
        )
        var bugsHtml = ''
        if (v.bugs.email) {
          bugsHtml+= '<div>email:    ' + '<a href="mailto='+v.bugs.email+'">'+v.bugs.email+'</a></div>'
        }
        if (v.bugs.url) {
          bugsHtml += '<div>url:    ' + '<a href="'+v.bugs.url+'">'+v.bugs.url+'</a></div>'
        }
        bugs.find('div.version-info-value').html(bugsHtml)
        $('div#version-info').append(bugs)
      }
      if (v.engines) {
      var eng = [];
        for (i in v.engines) { eng.push( i + ' (' + v.engines[i] + ')' ); }
        $(
          '<div class="version-info-cell">' +
            '<div class="version-info-key">Engines</div>' +
            '<div class="version-info-value">'+eng.join(', ')+'</div>' +
          '</div>' +
          '<div class="spacer"></div>'
        ).appendTo('div#version-info');
      }
      if (v.licenses) {
      h = '';
        for (i in v.licenses) {
          h += '<a href="'+v.licenses[i].url+'">'+v.licenses[i].type+'</a>';
        }
        $(
          '<div class="version-info-cell">' +
            '<div class="version-info-key">Licenses</div>' +
            '<div class="version-info-value">'+h+'</div>' +
          '</div>' +
          '<div class="spacer"></div>'
        ).appendTo('div#version-info');
      }

      
      //  +
      // '<div class="version-info-cell">' +
      //   '<span class="version-info-key">Author</span>' +
      //   '<span class="version-info-value">'+v.htmlDescription+'<span>' +
      // '</div>' +
      // '<div class="version-info-cell">' +
      //   '<span class="version-info-key">Repository</span>' +
      //   '<span class="version-info-value">'+v.htmlDescription+'<span>' +
      // '</div>' +
      
    }
    showVersion(doc['dist-tags'].latest);
    
    if (doc['dist-tags']) {
      for (i in doc['dist-tags']) {
        $('<div class="package-download">' +
            '<div id="'+doc['dist-tags'][i]+'" class="version-link">'+
              '<a href="' + doc.versions[doc['dist-tags'][i]].dist.tarball.replace('jsregistry:5984', 'registry.npmjs.org').replace('packages:5984', 'registry.npmjs.org')+'">'+i+'</a>  ('+doc.versions[doc['dist-tags'][i]].version+')' + 
            '</div>' +
          '</div>')
          .addClass('version-selected')
          .appendTo('div#version-list')
          ;
      }
      package.append('<br/>')
    }
    
    if (doc.versions) {
      var versions = Object.keys(doc.versions);
      versions.reverse();
      versions.forEach(function (i) {
        $('div#version-list').append(
          '<div class="package-download">' +
            '<div id="'+i+'" class="version-link">'+
              '<a href="'+doc.versions[i].dist.tarball.replace('jsregistry:5984', 'registry.npmjs.org').replace('packages:5984', 'registry.npmjs.org')+'">'+i+'</a>' + 
            '</div>' +
          '</div>'
        )
      })
    }
    
    $('div.version-link').mouseover(function () {
      $('div.version-selected').removeClass('version-selected');
      $(this).parent().addClass('version-selected');
      $('div#version-info').css(
        { top: $(this).position().top - $(this).parent().parent().position().top 
        , position:'relative'
        })
      showVersion(this.id)
    })
    
    var usersStr = '<h4>People who starred '+id+'</h4><div class="users"><p>'
    if (doc.users)
      for (var usingUser in doc.users)
        if (doc.users[usingUser])
          usersStr += (usersStr.length?' ':'')+'<span class="user">'+usingUser.replace(/</g, '&lt;').replace(/>/g, '&gt;')+'</span>'
      usersStr += '</p></div>'
      package.append(usersStr)

    request({url:'/_view/dependencies?reduce=false&key="'+id+'"'}, function (e, resp) {
      if (resp.rows.length === 0) return;
      var deps = ''
      deps += '<h4>Packages that depend on '+id+'</h4><div class="dependencies"><p>'
      for (var i=0;i<resp.rows.length;i++) {
        deps += '<span class="dep"><a class="dep" href="/#/' +
                 resp.rows[i].id+'">'+resp.rows[i].id+'</a></span> '
      }
      deps += '</p></div>'
      package.append(deps)
    })
  })
}

app.browse = function () {
  var limit = 100
    ;
  clearContent();
  
  $(
    '<div id="browse-anchors">' +
      '<a href="/#/_browse/all">all</a>' +
      '<a href="/#/_browse/tags">tags</a>' +
      '<a href="/#/_browse/author">author</a>' +
      '<a href="/#/_browse/updated">updated</a>' +
      '<a href="/#/_browse/deps">depended on</a>' +
    '</div>'
  )
  .appendTo('div#content')
  
  var c = $('<div id="main-container"></div>')
    .appendTo('div#content')
    ;
  var fetch = function (url, cb) {
    $('div#more-all').remove();
    request({url:url(limit)}, function (err, resp) {
      cb(resp);
      limit += 100;
      $('<div id="more-all">Load 100 more</div>')
        .click(function () {fetch(url, cb);})
        .appendTo(c)
        ;
    })
  }
  
  var routes = {};
  routes.all = function () {
    fetch( 
      function (limit) {
        return '/api/_all_docs?include_docs=true&limit='+limit+'&skip='+(limit - 100) 
      }
      , function (r) {
        var h = ''
        r.rows.forEach(function (row) {
          if (!row.doc.description) row.doc.description = ""
          row.doc.htmlDescription = row.doc.description
                                    .split('&').join('&amp;')
                                    .split('"').join('&quot;')
                                    .split('<').join('&lt;')
                                    .split('>').join('&gt;')
          if (row.id[0] !== '_') {
            h += (
              '<div class="all-package">' + 
                '<div class="all-package-name"><a href="/#/'+row.id+'">' + row.id + '</a></div>' +
                '<div class="all-package-desc">' + row.doc.htmlDescription + '</div>' +
              '</div>' +
              '<div class="spacer"></div>'
            )
          }
        });
      c.append(h);
      }
    );
    $('a:exactly("all")').css('text-decoration', 'underline');
  }
  routes.tags = function () {
    request({url:'/_view/tags?group=true'}, function (e, resp) {
      resp.rows.forEach(function (row) {
        c.append(
          '<div class="all-package">' + 
            '<div class="all-package-name"><a href="/#/_tag/'+encodeURIComponent(row.key)+'">' + row.key + '</a></div>' +
            '<div class="all-package-desc">' + row.value + '</div>' +
          '</div>' +
          '<div class="spacer"></div>'
        )
      })
      
      request({url:'/_view/tags?reduce=false'}, function (e, resp) {
        resp.rows.forEach(function (row) {
          $('div.all-package-name:exactly("'+row.key+'")').next().append('<a href="/#/'+row.id+'" class="tag-val">'+row.id+'</a>')
        })
        $(self).remove();
      })
    })
    $('a:exactly("tags")').css('text-decoration', 'underline');
  }
  routes.author = function () {
    request({url:'/_view/author?group=true'}, function (e, resp) {
      resp.rows.forEach(function (row) {
        c.append(
          '<div class="all-package">' + 
            '<div class="all-package-author"><a href="/#/_author/'+encodeURIComponent(row.key)+'">' + row.key + '</a></div>' +
            '<div class="all-package-auth-list">' + row.value + '</div>' +
          '</div>' +
          '<div class="spacer"></div>'
        )
      })
      
      request({url:'/_view/author?reduce=false'}, function (e, resp) {
        resp.rows.forEach(function (row) {
          $('div.all-package-author:exactly("'+row.key+'")').next().append('<a href="/#/'+row.id+'" class="tag-val">'+row.id+' </a>')
        })
        $(self).remove();
      })
    })
    $('a:exactly("author")').css('text-decoration', 'underline');
  }
  routes.updated = function () {
    request({url:'/_view/updated'}, function (e, resp) {
      resp.rows.reverse();
      resp.rows.forEach(function (row) {
        c.append(
          '<div class="all-package">' + 
            '<div class="all-package-name">'+ prettyDate(row.key) +'</div>' +
            '<div class="all-package-value"><a href="/#/'+encodeURIComponent(row.id)+'">' + row.id + '</a></div>' +
          '</div>' +
          '<div class="spacer"></div>'
        )
      })
    })
    $('a:exactly("updated")').css('text-decoration', 'underline');
  }
  routes.deps = function () {
    request({url:'/_view/dependencies?group=true'}, function (e, resp) {
      var deps = {};
      resp.rows.forEach(function (row) {
        if (!deps[row.value]) deps[row.value] = []
        deps[row.value].push(row)
      })
      var keys = Object.keys(deps);
      keys.sort(function(a,b){return a - b;});
      keys.reverse();
      keys.forEach(function (k) {
        deps[k].forEach(function (row) {
          c.append(
            '<div class="all-package">' + 
              '<div class="all-package-deps"><a href="/#/'+encodeURIComponent(row.key)+'">' + row.key + '</a></div>' +
              '<div class="all-package-deps-value">'+row.value+'</div>' +
            '</div>' +
            '<div class="spacer"></div>'
          )
        })
      })
    })
    $('a:exactly("depended on")').css('text-decoration', 'underline');
  }
  if (this.params.view) routes[this.params.view]();
}
app.tags = function () {
  var tag = this.params.tag.split('&').join('&amp;')
                           .split('"').join('&quot;')
                           .split('<').join('&lt;')
                           .split('>').join('&gt;')
  clearContent();
  $('div#content')
  .append('<h2 style="text-align:center">tag: '+tag+'</h2>')
  .append('<div id="main-container"></div>');
  request({url:'/_view/tags?reduce=false&include_docs=true&key="'+tag+'"'}, function (e, resp) {
    resp.rows.forEach(function (row) {
      if (row.doc.description) {
        row.doc.htmlDescription = row.doc.description.split('&').join('&amp;')
                                             .split('"').join('&quot;')
                                             .split('<').join('&lt;')
                                             .split('>').join('&gt;')
      } else {
        row.doc.htmlDescription = ''
      }
      $('div#main-container').append(
        '<div class="all-package">' + 
          '<div class="tags-pkg-name"><a href="/#/'+encodeURIComponent(row.key)+'">' + row.id + '</a></div>' +
          '<div class="tags-pkg-desc">'+row.doc.htmlDescription+'</div>' +
        '</div>' +
        '<div class="spacer"></div>'
      );
      
    })
  })
}
app.author = function () {
  var author = this.params.author;
  clearContent();
  $('div#content')
  .append('<h2 style="text-align:center">author: '+author+'</h2>')
  .append('<div id="main-container"></div>');
  request({url:'/_view/author?reduce=false&include_docs=true&key="'+author+'"'}, function (e, resp) {
    resp.rows.forEach(function (row) {
      if (row.doc.description) {
        row.doc.htmlDescription = row.doc.description.split('&').join('&amp;')
                                             .split('"').join('&quot;')
                                             .split('<').join('&lt;')
                                             .split('>').join('&gt;')
      } else {
        row.doc.htmlDescription = ''
      }
      $('div#main-container').append(
        '<div class="all-package">' + 
          '<div class="tags-pkg-name"><a href="/#/'+encodeURIComponent(row.id)+'">' + row.id + '</a></div>' +
          '<div class="tags-pkg-desc">'+row.doc.htmlDescription+'</div>' +
        '</div>' +
        '<div class="spacer"></div>'
      );
      
    })
  })
}
app.analytics = function () {
  clearContent();
  var view = this.params.view || "thisweek";
  $('div#content').html(
    '<div id="browse-anchors">' +
      '<a href="/#/_analytics/thisweek">This Week</a>' +
      '<a href="/#/_analytics/30days">30 Days</a>' +
      '<a href="/#/_analytics/alltime">All Time</a>' +
    '</div>' +
    '<div id="main-container">' +
      '<div id="analytics-created"></div>' +
      '<div id="analytics-latest"></div>' +
      '<div id="analytics-updated"></div>' +
    '</div>'  
  )
  
   $('a:exactly("'+{thisweek:'This Week', '30days':'30 Days', alltime:'All Time'}[view]+'")').css('text-decoration', 'underline');
  
  $.getScript('/highcharts/highcharts.js', function () {
    var dt = new Date();
    if (view == 'thisweek') {
      dt.setDate(dt.getDate() - 7);
    }
    if (view == '30days') {
      dt.setDate(dt.getDate() - 30);
    }
    
    var series = [];
    
    var extract = function (resp, name) {
      var times = {};
      resp.rows.reverse();
      resp.rows.forEach(function (row) {
        if (view === 'thisweek') {
          var t = row.key[1].slice(0, 10);
        }
        if (view === '30days') {
          var t = row.key[1].slice(8, 10);
        }
        if (view === 'alltime') {
          var t = row.key[1].slice(0, 7);
        }
        
        if (!times[t]) times[t] = 0;
        times[t] += 1;
      })
      var x = {name:name, data:[]};
      for (i in times) {
        x.data.push(times[i]);
      }
      series.push(x);
      if (series.length === 3) graph(times);
    }
    
    graphNames = 
      { thisweek: 'This Week'
      , '30days': '30 Days' 
      , alltime: 'All Time'
      }
    
    var graph = function (times) {
      chart = new Highcharts.Chart(
        {
          chart: {
             renderTo: 'analytics-created',
             defaultSeriesType: 'line'
          },
          title: {
             text: graphNames[view]
          },
          xAxis: {
             categories: Object.keys(times)
          },
          tooltip: {
             enabled: false,
             formatter: function() {
                return '<b>'+ this.series.name +'</b><br/>'+
                   this.x +': '+ this.y +'Â°C';
             }
          },
          plotOptions: {
             line: {
                dataLabels: {
                   enabled: true
                },
                enableMouseTracking: false
             }
          },
          series: series
       });
    }
    
    if (view === 'thisweek' || view === '30days') {
      var endkey = dt.toISOString().slice(0, 10);
    }
    if (view === 'alltime') {
      var endkey = null;
    }
    
    request({url:'/_view/analytics?'+param(
      {reduce:'false'
      , descending:'true'
      , endkey:JSON.stringify(['created', endkey])
      , startkey:JSON.stringify(['created', new Date()])
      })}, 
      function (e, resp) {
        extract(resp, 'created')
    })
    request({url:'/_view/analytics?'+param(
      {reduce:'false'
      , descending:'true'
      , endkey:JSON.stringify(['update', endkey])
      , startkey:JSON.stringify(['update', new Date()])
      })}, 
      function (e, resp) {
        
        extract(resp, 'updated')
    })
    request({url:'/_view/analytics?'+param(
      {reduce:'false'
      , descending:'true'
      , endkey:JSON.stringify(['latest', endkey])
      , startkey:JSON.stringify(['latest', new Date()])
      })}, 
      function (e, resp) {
        extract(resp, 'latest')
    })
  })
}

$(function () { 
  app.s = $.sammy(function () {
    // Index of all databases
    this.get('', app.index);
    this.get("#/", app.index);
    this.get("#/_analytics", app.analytics);
    this.get("#/_analytics/:view", app.analytics);
    this.get("#/_browse", app.browse);
    this.get("#/_browse/:view", app.browse);
    this.get("#/_tag/:tag", app.tags);
    this.get("#/_author/:author", app.author);
    this.get("#/_install", function () {
      clearContent();
      request({url:'/install.html', dataType:'html'}, function (e, resp) {
        $('div#content').html('<div id="main-container">'+resp+'</div>');
      })
    });
    this.get("#/_publish", function () {
      clearContent();
      request({url:'/publish.html', dataType:'html'}, function (e, resp) {
        $('div#content').html('<div id="main-container">'+resp+'</div>');
      })
    });
    this.get("#/_more", function () {
      clearContent();
      request({url:'/more.html', dataType:'html'}, function (e, resp) {
        $('div#content').html('<div id="main-container">'+resp+'</div>');
      })
    });
    this.get("#/:id", app.showPackage);
    
    
  })
  app.s.run();
});

