#format python
# -*- coding: iso-8859-1 -*-
'''
    MoinMoin - VotingStars Macro
    Author: Travis Bailey
    Date: February 2006
  
    Purpose:
        This macro allows ratings of items using stars (based on Vote macro)
    Usage:
        [[VotingStars(UniqueName)]]
        e.g. 1. NiceShop [[VotingStars(shop1)]]
             1. EvenNicerShop [[VotingStars(shop2)]]
    Tested:
        Firefox 1.5 MoinMoin 1.5.1 Python 2.3

    I basically just slapped this together from the Vote1_3.py script and the
    RatingStars.py script.  I wanted to get the benefits of both.  I wanted a
    Utility to only allow Registered users to submit, allow them to change
    their vote, and to average the results.

    So basically it uses the Vote1_3.py code to track one vote per user.
    It averages the total stars given and then displays the number of average
    number of rated stars.

    You can have multiple VotingStars on one page (so long as the UniqueNames are unique)
    Changing the UniqueName creates a new vote.
    Make sure not to conflict with any Vote names you are using

    VotingStars data is stored in data_dir/pages/pagename/votes 
    (i.e. alongside the attachments directory for a page).

    You can customise the appearance by defining the following CSS styles:
        table.votestars
    
'''
import os, pickle
from MoinMoin import wikiutil
from MoinMoin.util import filesys

def makeFilename(thisPage, voteName):
    votesDir = thisPage.getPagePath("votes")
    if not os.path.exists(votesDir):
        filesys.makeDirs(votesDir)
    voteName = wikiutil.quoteWikinameFS(voteName) + '.pik'
    return os.path.join(votesDir, voteName)

def loadVotes(thisPage, voteName):
    votesFile = makeFilename(thisPage, voteName)
    try:
        f = open(votesFile, 'r')
        return pickle.load(f)
    except: # XXX
        return {}

def saveVotes(thisPage, voteName, votes):
    votesFile = makeFilename(thisPage, voteName)
    f = open(votesFile, 'w')
    pickle.dump(votes, f)

def countVotes(votes):
    results = {}
    for v in votes.values():
        results.setdefault(v, 0)
        results[v] += 1
    return results

def execute(macro, args):
    args = args.split(",")
    args = map(unicode.strip, args)

    if len(args) < 1:
        return macro.formatter.rawHTML('<pre>[[Vote: Insufficient macro arguments]]</pre>')

    pageName = args[0]
    voteName = pageName
    candidates = ['1','2','3','4','5']
    src_litstar = '/wiki/modern/img/star_on.png'
    src_unlitstar = '/wiki/modern/img/star_off.png'
    
    form = macro.form
    request = macro.request
    if request.user.valid:
        voter = request.user.name
    else:
        voter = ''
    thisPage = macro.formatter.page
    votes = loadVotes(thisPage, voteName)

    # votes are stored in a dictionary as {user: candidate} to avoid duplicate votes
    # (a voter could switch their vote but this UI doesn't expose that facility)
    if form.has_key('vote') and form.has_key('voteName') and voter:
        if form['voteName'][0] == voteName:
            votes[voter] = form['vote'][0]
            try:
               saveVotes(thisPage, voteName, votes)
            except: # XXX
               return macro.formatter.rawHTML('<a id="voteform"><pre>[[Vote: failed to store vote]]</pre>')

    # generate dictionary {candidate: numvotes}
    results = countVotes(votes)
    onestar = results.setdefault(candidates[0],0)
    twostar = results.setdefault(candidates[1],0)
    threestar = results.setdefault(candidates[2],0)
    fourstar = results.setdefault(candidates[3],0)
    fivestar = results.setdefault(candidates[4],0)
    counts = (onestar+twostar+threestar+fourstar+fivestar)

    if counts == 0:
        average = 0
    else:
        average = (onestar*1+twostar*2+threestar*3+fourstar*4+fivestar*5)/counts

    hasVoted = voter in votes

    # spit out votes table (as part of a form if the user hasn't voted yet)
    html = '<a id="voteform"><table class="votestars"><tr><td>'

    if voter:
        html += '''
            <form method="get" name="%(formname)s" action="%(url)s#voteform">\n
            <input type="hidden" name="voteName" value="%(voteName)s">\n
            <input type="hidden" name="vote" value="0">
            ''' % {
                'formname': voteName,
                'url': thisPage.url(request),
                'voteName': voteName,
            }
        btnstar = '<input type="image" src="%(isrc)s" OnClick="document.%(form)s.vote.value=%(value)s">\n'  
        for i in range(1,6):
            if i <= average:
                html += btnstar % {'isrc':src_litstar, 'form':voteName, 'value': i}
            if i > average:
                html += btnstar % {'isrc':src_unlitstar, 'form':voteName, 'value': i}
        if average == 0:
            html += ' No Rating'
        #else:
        #    html += ' %(avg)s ' % { 'avg': average }
        html += '</form></td></tr></table></a>'
    else:
        html += 'You must be logged in to Rate.</td></tr></table></a>'

    return macro.formatter.rawHTML(html)
    
