function Beer(Parent, Uri) {
    var tags = {};
    var bv;
    var beer;
    var brewery;
    var submitter;

    var fillMergeChoices = function(uri) {
        $.getJSON('/api/'+uri, [],
                  function(data) {
                      $('div.mergechoices', bv).show()
                          .find('span.beerid').text(data.id).end()
                          .find('span.beername').text(data.name).end()
                          .find('span.brewery').text(data.brewery).end()
                          .find('span.submitter').text(data.user).end()
                          .find('span.date').text(format_datetime(make_date(data.date.datetime))).end()
                          .find('span.thistags').text(beer.tags.length).end()
                          .find('span.othertags').text(data.tags.length).end()
                          .find('span.thiscomments').text(beer.comments.length).end()
                          .find('span.othercomments').text(data.comments.length);
                  });
    };

    var mergeCancel = function() {
        $('.beermerge', bv).hide();
        return false;
    };

    var merge = function() {
        var mdiv = $('div.mergechoices', bv);
        var props = {};
        var fields = mdiv.find('input[type=checkbox]');
        for (var i = fields.length-1; i >= 0; i--) {
            props[fields.eq(i).attr('name')] = !!fields.eq(i).attr('checked');
        }

        var postbeer = beer.id;

        if (props.beerid) {
            for (k in props) { props[k] = !props[k]; }

            var temp = props.thiscomments;
            props.thiscomments = !props.othercomments;
            props.othercomments = !temp;

            temp = props.thistags;
            props.thistags = !props.othertags;
            props.othertags = !temp;

            props.beerid = beer.id;
            postbeer = mdiv.find('span.beerid').text();
        } else {
            props.beerid = mdiv.find('span.beerid').text();
        }

        props.cmd = 'merge';

        $.ajax({url:'/api/beer/'+postbeer,
                type:'POST',
                data:props,
                success:function(newb) { window.location = '/beer/'+newb.id; },
                dataType:'json'});
        return false;
    };

    var showMerge = function() {
        $('.beermerge', bv).show();
        return false;
    };

    var cancel = function() {
        $('.beeredit', bv).hide();
        return false;
    };

    var save = function() {
        var name = $('.beeredit .beername', bv).val();
        if (name.length <= 0) { alert('Enter a new name for the beer.'); return false; }

        var brewery_id = parseInt($('.beeredit .brewery', bv).val());
        if (!brewery_id) { alert('Enter a brewery id for the beer.'); return false; }

        var tagstr = [];
        var remtags = $('.beeredit ul.tags li.remove', bv).find('a');
        remtags.each(function(x) {tagstr[x] = $(remtags[x]).attr('href');});
        tagstr = tagstr.map(function(u) { return u.substr(u.lastIndexOf('/')+1); }).join(',');

        $.post('/api/beer/'+beer.id,
               {cmd:'edit',
                name:name,
                brewery:brewery_id,
                rem_tags:tagstr},
               function(beer) { window.location = '/beer/'+beer.id; },
               'json');
        return false;
    };

    var edit = function() {
        $('.beeredit .beername', bv).val(beer.name);
        $('.beeredit .brewery', bv).val(beer.brewery);

        var taglist = $('.beeredit ul.tags', bv).empty();

        for (var i = beer.tags.length-1; i >= 0; i--) {
            $('<li><span></span><a href="/tag/'+beer.tags[i]+'" class="tag button">remove</a>')
            .find('span').text(tags[beer.tags[i]].text).end()
            .find('a').click(function(o) { $(o.target).parent().addClass('remove').end().hide(); return false; }).end()
            .appendTo(taglist);
        }

        $('.beeredit', bv).show();
        return false;
    };

    var tagCancel = function() {
        $('.addtagform', bv).hide();
        $('.addtag .show', bv).show();
        return false;
    };

    var submitTags = function() {
        var tags = $('.addtag input', bv).val();

        if (!tags || tags.length == 0) return false;

        $.post('/api/beer/'+beer.id,
               {cmd:'add_tags',
                tags:tags},
               function(data) {
                   for (var i = 0; i < data.tags.length; i++) {
                       if (!tags[data.tags[i]]) {
                           fetch('tag', data.tags[i], loadTag);
                       }
                   }
                   $('.addtag input', bv).val('');
                   $('.addtagform', bv).hide();
                   $('.addtag .show', bv).show();
               },
               'json');
        return false;
    };

    var addTag = function() {
        $('.addtagform', bv).show();
        $('.addtag .show', bv).hide();

        $('.addtag input', bv).focus();
        return false;
    };

    var setSession = function() {
        if (GSession === null) { return; }

        var vote = find_vote(beer.id);
        if (vote) { $('.vote a.'+vote, bv).addClass('picked'); }

        var score = find_score(beer.id);
        if (score) {
            $('.scorevote .score', bv).text((5*score).toFixed(1));
        }

        if (GSession.id) {
            ReportForm(data_uri, $('div.report', bv));

            $('div.addtag', bv).show()
            .find('a').attr('href', '/beer/'+beer.id).click(addTag).end()
            .find('.submit').attr('href', '/beer/'+beer.id).click(submitTags).end()
            .find('.cancel').attr('href', '#').click(tagCancel).end()
            .find('input.tagnames').autocomplete('/api/autocomplete/tag',
                                                 {dataType:'json',
                                                  parse:function(data) {
                                                      var res = [];
                                                      for (var i = 0; i < data.results.length; i++) {
                                                          res[i] = {data:data.results[i],
                                                                    value:data.results[i].title,
                                                                    result:data.results[i].title};
                                                      }
                                                      return res;
                                                  },
                                                  formatItem: function(row) { return row.title; },
                                                  multiple:true
                                                 });
        }

        if (GSession.admin) {
            add_edit_button('/beer/'+beer.id, 'edit', edit);

            $('div.admin', bv).show()
            .find('.save').attr('href', '/beer/'+beer.id).click(save).end()
            .find('.cancel').attr('href', '#').click(cancel);

            add_edit_button('/beer/'+beer.id, 'merge', showMerge, 'merge');

            $('div.merge', bv).show()
            .find('.merge').attr('href', '/beer/'+beer.id).click(merge).end()
            .find('.cancel').attr('href', '#').click(mergeCancel).end()
            .find('.othername').autocomplete('/api/autocomplete/beer',
                                             {dataType:'json',
                                              parse:function(data) {
                                                  var res = [];
                                                  for (var i = 0; i < data.results.length; i++) {
                                                      res[i] = {data:data.results[i],
                                                                value:data.results[i].title,
                                                                result:data.results[i].title};
                                                  }
                                                  return res;
                                              },
                                              formatItem: function(row) { return row.title; }
                                             })
                .result(function(ev, row) {
                            fillMergeChoices(row.uri);
                            return row.title;
                        });
        }
    };

    var markVote = function(link, val) {
        var votediv = link.parents('div.vote').eq(0);
        $('a', votediv).removeClass('picked');

        if(val != 'unvote') { link.addClass('picked'); }
    };

    var loadTag = function(data) {
        tags[data.id] = data;
        $('<a href="/tag/'+data.id+'">'+data.text+'</a>').appendTo($('.tags', bv));
    };

    var loadSubmitter = function(data) {
        submitter = data;
        $('.beerdetails .brusername', bv).attr('href', '/user/'+data.id).text(data.name);
    };

    var loadBrewery = function(data) {
        brewery = data;
        $('h3 a.brewery', bv).attr('href', '/brewery/'+data.id).text(data.name);
    };

    var loadBeer = function(data) {
        beer = data;

        $('div.vote a', bv).attr('href', '/beer/'+data.id)
        .click(vote_fun(markVote));

        $('h2.beername', bv).text(data.name);

        fetch('brewery', beer.brewery, loadBrewery);
        fetch('user', beer.user, loadSubmitter);

        $('.submitdate', bv).text(format_date(make_date(data.date.datetime)));

        for (var i = 0; i < data.tags.length; i++) {
            fetch('tag', data.tags[i], loadTag);
        }

        ViewTabber($('.commplace', bv),
                   [{name:'comments',
                     label:'comments',
                     createView:function(viewdiv) {
                         CommentTable(viewdiv, data.comments);
                     }},
                    {name:'places',
                     label:'places',
                     createView:function(viewdiv) {
                         var adderdiv = $('<div/>').appendTo(viewdiv);
                         var pt = PlaceTable(viewdiv, data.places);
                         get_user('placeadder', function() { PlaceAdder(adderdiv, data.id, pt); });
                     }}]);

        get_session('beer', setSession);
    };

    var loadTemplate = function(data) {
        bv = $(data).appendTo(Parent);
        $.getJSON(Uri, [], loadBeer);
    };

    $.get('/'+stv+'/html/beer.html', [], loadTemplate);
};

function PlaceAdder(Parent, BeerId, Table) {
    var pa;

    var hide = function() {
        $('div.form', pa).hide();
        $('a.show', pa).show();
        return false;
    };

    var submit = function() {
        var id = $('input[name=placeid]', pa).val();
        
        if (id.length > 0) {
            $.post('/api/beer/'+BeerId,
                   {cmd:'add_place', place:id},
                   function(data) {
                       pa.hide();
                       Table.loadPage(null, null, 0, data.places);
                   },
                   'json');
        }
        return false;
    };


    var loadTemplate = function(data) {
        pa = $(data).appendTo(Parent);

        $('a.show', pa).click(
            function() { $('a.show', pa).hide();
                         $('div.form', pa).show();
                         $('input', pa).focus();
                         return false;});

        $('a.cancel', pa).click(hide);

        $('a.submit', pa).attr('href', '/beer/'+BeerId).click(submit);

        $('input[name=name]', pa).autocomplete(
            '/api/autocomplete/place',
            {dataType:'json',
             parse:function(data) {
                 var res = [];
                 for (var i = 0; i < data.results.length; i++) {
                     res[i] = {data:data.results[i],
                               value:data.results[i].title,
                               result:data.results[i].title};
                 }
                 return res;
             },
             formatItem: function(row) {
                 return row.title;
             },
             mustMatch: true,
             selectFirst: true
            })
        .result(function(ev, row) {
            $('input[name=placeid]', pa).val(row.uri.substring(7));
            return row.title;
        });
    };

    $.get('/'+stv+'/html/placeadder.html', [], loadTemplate);
};

$(function() { Beer($('#view'), data_uri); });

