/*
*/

references = new Array() // this list will collect all entries defined
                         // in later bibliograhy files



// standard bibtex fields

address      = 'address'
annote       = 'annote'
author       = 'author'
booktitle    = 'booktitle'
chapter      = 'chapter'
conference   = 'conference' // extension to bibtex entries
crossref     = 'crossref'
edition      = 'edition'
editor       = 'editor'
howpublished = 'howpublished'
institution  = 'institution'
journal      = 'journal'
key          = 'key'
month        = 'month'
note         = 'note'
number       = 'number'
organization = 'organization'
pages        = 'pages'
publisher    = 'publisher'
school       = 'school'
series       = 'series'
title        = 'title'
topic        = 'topic' // extension to bibtex entries
type         = 'type'
url          = 'url' // extension to bibtex entries
volume       = 'volume'
year         = 'year'



// standard bibtex entries

function Article(fields)
{
    this.type = 'article'
    populate_fields(
        this,
        fields,
        [author, title, journal, year],
        [volume, number, pages, month, note, key, crossref,url,topic]
    )
    references.push(this)
}
Article.prototype = {
    format : function() {
        var fields = new Array()
        fields.push(
            '<span class="author">'+this.author.join(', ')+'</span>'
        )
        if (this.url)
            fields.push(
                '<span class="title"><a href="'+this.url+'">'
                +this.title+'</a></span>'
            )
        else
            fields.push('<span class="title">'+this.title+'</span>')
        fields.push('<span class="journal">'+this.journal+'</span>')
        volnumpages = ''
        if (this.volume)
            volnumpages += '<span class="volume">'+this.volume+'</span>'
        if (this.number)
            volnumpages += '<span class="number">'+this.number+'</span>'
        if (this.pages)
            volnumpages += '<span class="pages">'+this.pages+'</span>'
        if (volnumpages)
            fields.push(volnumpages)
        if (this.month)
            fields.push('<span class="month">'+this.month+'</span>')
        fields.push('<span class="year">'+this.year+'</span>')
        if (this.note) 
            fields.push('<span class="note">'+this.note+'</span>')
        return fields.join(', ')
    }
}

function Book(fields)
{
    this.type = 'book'
    populate_fields(
        this,
        fields,
        [author, editor, title, publisher, year],
        [
            volume, number, series, address, edition, month, note, key, 
            crossref,topic
        ] 
    )
    references.push(this)
}
Book.prototype = {
    format : function() {
        var fields = new Array()
        if (this.author)
            fields.push(
                '<span class="author">'+this.author.join(', ')+'</span>'
            )
        else
            fields.push(
                '<span class="editor">'+this.editor.join(', ')+'</span>'
            )
        fields.push('<span class="title">'+this.title+'</span>')
        if (this.series)
            fields.push('<span class="series">'+this.series+'</span>')
        if (this.volume)
            fields.push('<span class="volume">'+this.volume+'</span>')
        else if (this.number)
            fields.push('<span class="number">'+this.number+'</span>')
        if (this.edition)
            fields.push('<span class="edition">'+this.edition+'</span>')
        fields.push('<span class="publisher">'+this.publisher+'</span>')
        if (this.month)
            fields.push('<span class="month">'+this.month+'</span>')
        fields.push('<span class="year">'+this.year+'</span>')
        if (this.note) 
            fields.push('<span class="note">'+this.note+'</span>')
        return fields.join(', ')
    }
}

function Inbook(fields)
{
    this.type = 'inbook'
    populate_fields(
        this,
        fields,
        [author, title, booktitle, publisher, year], // required
        [
            editor, volume, number, series, type, chapter, pages, 
            address, edition, month, note, key, crossref,topic
        ] // optional
    )
    references.push(this)
}
Inbook.prototype = {
    format : function() {
        // XXX series address month organization, publisher
        var fields = new Array()
        fields.push(
            '<span class="author">'+this.author.join(', ')+'</span>'
        )
        fields.push('<span class="title">'+this.title+'</span>')
        if (this.editor)
        {
            fields.push(
                'In: <span class="editor">'+this.editor.join(', ')+'</span>'
            )
            fields.push('<span class="booktitle">'+this.booktitle+'</span>')
        }
        else
        {
            fields.push(
                'In: <span class="booktitle">'+this.booktitle+'</span>'
            )
        }
        volnumpages = ''
        if (this.volume)
            volnumpages += '<span class="volume">'+this.volume+'</span>'
        if (this.number)
            volnumpages += '<span class="number">'+this.number+'</span>'
        if (this.pages)
            volnumpages += '<span class="pages">'+this.pages+'</span>'
        if (volnumpages) fields.push(volnumpages)
        fields.push('<span class="year">'+this.year+'</span>')
        if (this.note) 
            fields.push('<span class="note">'+this.note+'</span>')
        return fields.join(', ')
    }
}

function Inproceedings(fields)
{
    this.type = 'inproceedings'
    populate_fields(
        this,
        fields,
        [author, title, booktitle, year], // required
        [
            editor, volume, number, series, pages, address, month, 
            organization, publisher, note, key, crossref,topic
        ] // optional
    )
    references.push(this)
}
Inproceedings.prototype = {
    format : function() {
        // XXX series address month organization, publisher
        var fields = new Array()
        fields.push(
            '<span class="author">'+this.author.join(', ')+'</span>'
        )
        fields.push('<span class="title">'+this.title+'</span>')
        if (this.editor)
        {
            fields.push(
                'In: <span class="editor">'+this.editor.join(', ')+'</span>'
            )
            fields.push('<span class="booktitle">'+this.booktitle+'</span>')
        }
        else
        {
            fields.push(
                'In: <span class="booktitle">'+this.booktitle+'</span>'
            )
        }
        volnumpages = ''
        if (this.volume)
            volnumpages += '<span class="volume">'+this.volume+'</span>'
        if (this.number)
            volnumpages += '<span class="number">'+this.number+'</span>'
        if (this.pages)
            volnumpages += '<span class="pages">'+this.pages+'</span>'
        if (volnumpages) fields.push(volnumpages)
        fields.push('<span class="year">'+this.year+'</span>')
        if (this.note) 
            fields.push('<span class="note">'+this.note+'</span>')
        return fields.join(', ')
    }
}

// special entries not defined by bibtex

function Oral(fields) {
    this.type = 'oral'
    populate_fields(
        this,
        fields,
        [author,title,year], // required
        [conference,month,note,key,crossref,topic] // optional
    )
    references.push(this)
}
Oral.prototype = {
    format : function() {
        var fields = new Array()
        fields.push(
            '<span class="author">'+this.author.join(', ')+'</span>'
        )
        fields.push('<span class="title">'+this.title+'</span>')
        if (this.conference)
            fields.push(
                '<span class="conference">'+this.conference+'</span>'
            )
        if (this.month)
            fields.push('<span class="month">'+this.month+'</span>')
        fields.push('<span class="year">'+this.year+'</span>')
        if (this.note) 
            fields.push('<span class="note">'+this.note+'</span>')
        return fields.join(', ')
    }
}

function Poster(fields) {
    this.type = 'poster'
    populate_fields(
        this,
        fields,
        [author,title,year], // required
        [conference,month,note,key,crossref,topic] // optional
    )
    references.push(this)
}
Poster.prototype = {
    format : function() {
        var fields = new Array()
        fields.push(
            '<span class="author">'+this.author.join(', ')+'</span>'
        )
        fields.push('<span class="title">'+this.title+'</span>')
        if (this.conference)
            fields.push(
                '<span class="conference">'+this.conference+'</span>'
            )
        if (this.month)
            fields.push('<span class="month">'+this.month+'</span>')
        fields.push('<span class="year">'+this.year+'</span>')
        if (this.note) 
            fields.push('<span class="note">'+this.note+'</span>')
        return fields.join(', ')
    }
}

/* utility function to populate fields in the above entries */
function populate_fields(entry,fields,required,optional)
{
    for (var i=0; f=required[i]; i++)
    {
        // XXX what if field is not given??
        // XXX be careful with and/or requirements
        entry[f] = fields[f]
    }
    for (var i=0; f=optional[i]; i++)
    {
        if (fields[f])
            entry[f] = fields[f]
    }
}


//--------------------------------------------------------------------------
// sort functions
//--------------------------------------------------------------------------

function sort_type(a,b) {
    var order = {
        'article': 0,
        'book': 1,
        'inbook': 0,
        'inproceedings': 0,
        'oral': 3,
        'poster': 4
    }
    return order[a.type] - order[b.type];
}

function sort_topic(a,b) {
    var order = {
        'Theory': 0,
        'Experimental': 1,
        'Simulation': 2
    }
    return order[a.topic] - order[b.topic];
}

function sort_author(a,b) {
    if (a.author[0] < b.author[0]) return -1
    else if (a.author[0] > b.author[0]) return 1
    else return 0
}

function sort_year(a,b) {
    if (!a.year || !b.year) return 0;
    else return b.year - a.year;
}

function sort_month(a,b) {
    var month = {
        'January': 1,
        'February': 2,
        'March': 3,
        'April': 4,
        'May': 5,
        'June': 6,
        'July': 7,
        'August': 8,
        'September': 9,
        'October': 10,
        'November': 11,
        'December': 12
    }
    if (!a.month && b.month) return -1
    else if (a.month && !b.month) return 1
    else if (!a.month && !b.month) return 0
    a_month = a.month.split(' ')[0];
    b_month = b.month.split(' ')[0];

    return month[b_month] - month[a_month];
    // XXX compare days if months match :-(
}

function sort_note(a,b) {
    var order = {
        'in press': -1,
        'accepted': -2,
        'submitted': -3,
        'in preparation': -4
    }
    return (order[a.note] || 0) - (order[b.note] || 0)
}

function sort_all(a,b) {
    var cmp
    for (var i=0; i<sort_functs.length; i++)
    {
        if (cmp = sort_functs[i](a,b)) return cmp
    }
    return 0
}

sorting = {
    'type' : [sort_type, sort_note, sort_year, sort_month, sort_author] ,
    'author' : [sort_author, sort_type, sort_note, sort_year, sort_month],
    'topic' : [
        sort_topic, sort_note, sort_year, sort_month, sort_type, 
        sort_author
    ],
    'year' : [sort_year, sort_month, sort_type, sort_note, sort_author]
}


//--------------------------------------------------------------------------
// filter functions
//--------------------------------------------------------------------------



//--------------------------------------------------------------------------
// main function to render bibliography
//--------------------------------------------------------------------------
function jsbib_display()
{
    var typenames = {
        'article': "Peer-Reviewed Papers",
        'book': "Books",
        'inbook': "Peer-Reviewed Papers",
        'inproceedings': "Peer-Reviewed Papers",
        'oral': "Oral Presentations",
        'poster': "Poster Presentations"
    }

    var options = {
        'sort' : 'type'
    }

    // get display options from query string
    var qstring = document.location.search
    qstring = qstring.substring(1,qstring.length)
    if (qstring)
    {
        var items = qstring.split("&")
        for (var i=0; i<items.length; i++)
        {
            var item = items[i].split("=")
            options[item[0]] = item[1]
        }
    }

    sortkey = options['sort']

    // XXX cross-ref references!

    // XXX filter
    if (options['author'])
        {
        function check_author(ref)
        {
            for (var i=0; i<ref.author.length; i++)
                if (ref.author[i].indexOf(options['author']) != -1) 
                    return true
            return false
        }
        
        references = references.filter(check_author)
    }

    // sort
    sort_functs = sorting[sortkey]
    references.sort(sort_all)

    // group break publication list into sub-blocks
    var block = new Array();
    var split = new Array();

    var last = references[0];
    for (var i=1; i<references.length; i++) {
        pub = references[i];
        block.push(last);
        if (sortkey=='type' && typenames[last.type]==typenames[pub.type]) ;
        else if (sortkey!='author' && last[sortkey]!=pub[sortkey]) {
            split.push(block);
            block = new Array();
        }
        last = pub;
    }
    block.push(last);
    split.push(block);

    // generate list of headlines
    var headline = new Array()
    for (var i=0; i<split.length; i++) {
        if (sortkey == "author") {
            headline.push("Publications by first author");
        } else if (sortkey == "type") {
            type = split[i][0]['type'];
            headline.push(typenames[type]);
        } else {
            headline.push(split[i][0][sortkey]);
        }
    }

    // render
    var URL = String(document.location).split('?')[0]
    var sorting_div = document.getElementsByName('jsbib_sorting')[0]
    var anchors_div = document.getElementsByName('jsbib_anchors')[0]
    var content_div = document.getElementsByName('jsbib_content')[0]

    // --- sorting
    var attributes = new Array()
    delete options['sort']
    for (key in options)
        attributes.push(key+"="+options[key])
    qstring = attributes.join('&')
    sorting_div.innerHTML =
        '<a href="'+URL+'?'+qstring+'&sort=type">by kind</a>, '
        + '<a href="'+URL+'?'+qstring+'&sort=topic">by topic</a>, '
        + '<a href="'+URL+'?'+qstring+'&sort=author">by first author</a>, '
        + '<a href="'+URL+'?'+qstring+'&sort=year">by year</a>'

    // --- anchors
    var anchors = new Array
    for (var i=0; i<headline.length; i++)
        anchors[i] = '<a href="#'+headline[i]+'">'+headline[i]+'</a>'
    if (sortkey != 'author')
        anchors_div.innerHTML = anchors.join(', ')

    // --- content
    var content = ''
    for (var i=0; i<split.length; i++)
    {
        content += '<a name="'+headline[i]+'"></a>'
        content += '<h3>'+headline[i]+'</h3>\n<ul>'
        for (var j=0; j<split[i].length; j++)
        {
            ref = split[i][j]
            content += '<li class="'+ref.type+'">'+ref.format()+'\n'
        }
        content += '</ul>\n'
    }
    content_div.innerHTML = content
}
