--- voting/voting.module	2006-07-10 20:23:32.000000000 -0400
+++ voting.module	2006-08-04 00:43:44.000000000 -0400
@@ -1,572 +1,576 @@
-<?php
-
-/**
- * Implementation of hook_help().
- */
-function voting_help($section) {
-  switch ($section) {
-    case 'admin/modules#description':
-      return t("Enables content to be voted on by the community.");
-    case 'admin/settings/voting':
-      return t("Voting provides a way for your users to vote on submitted content.");
-  }
-}
-
-/**
- * Implementation of hook_perm().
- */
-function voting_perm() {
-  return array('vote on content', 'show average without voting');
-}
-
-/**
- * Implementation of hook_menu().
- */
-function voting_menu($type) {
-  $items = array();
-  $items[] = array(
-    'path' => 'voting/flash',
-    'title' => t('voting'),
-    'callback' => 'voting_flash',
-    'access' => user_access('access content'),
-    'type' => MENU_CALLBACK);
-  
-  return $items;
-}
-
-/**
- * Implementation of hook_settings()
- */
-function voting_settings() {
-	if (!function_exists('votingapi_set_vote')) {
-		drupal_set_message('The voting module depends on the voting API module.  Please install the voting API module before attempting to use this module.', 'error');
-	}
-	
-	// General options
-	$form['general'] = array(
-		'#type' => 'fieldset',
-		'#title' => t('General options'),
-		'#collapsible' => true,
-		'#collapsed' => false,
-	);
-	$form['general']['voting_location'] = array(
-		'#type' => 'radios',
-		'#title' => t('Voting controls on nodes'),
-		'#default_value' => variable_get('voting_location', 1),
-		'#options' => array(t('Display above the node'), t('Display below the node'), t('Do not display')),
-		'#description' => t('Position of the voting control.  Select "Do not display" if you are calling the voting module function directly from your theme and/or module code.'),
-	);
-	$form['general']['voting_location'] = array(
-		'#type' => 'radios',
-		'#title' => t('Show voting in teaser'),
-		'#default_value' => variable_get('voting_show_in_teaser', 0),
-		'#options' => array(1 => t('yes'), 0 => t('no')),
-	);
-	$form['general']['voting_ip_timeout'] = array(
-		'#type' => 'textfield',
-		'#title' => t("Voting IP timeout (in seconds)"),
-		'#default_value' => variable_get('voting_ip_timeout', 3600),
-		'#size' => 8,
-		'#maxlength' => 8,
-		'#description' => t('Controls if and how often users with the same IP address can vote for the same thing.  Set it to 0 to disable this feature.'),
-	);
-	
-	// Colors
-	$form['colors'] = array(
-		'#type' => 'fieldset',
-		'#title' => t('Colors'),
-		'#collapsible' => true,
-		'#collapsed' => true,
-	);
-	$form['colors']['voting_bgcolor'] = array(
-		'#type' => 'textfield',
-		'#title' => t('Background color for voting control'),
-		'#default_value' => variable_get('voting_bgcolor', '0xffffff'),
-		'#size' => 8,
-		'#maxlength' => 8,
-	);
-	$form['colors']['voting_on_fill'] = array(
-		'#type' => 'textfield',
-		'#title' => t("Star 'on' fill color"),
-		'#default_value' => variable_get('voting_on_fill', '0x990000'),
-		'#size' => 8,
-		'#maxlength' => 8,
-	);
-	$form['colors']['voting_on_border'] = array(
-		'#type' => 'textfield',
-		'#title' => t("Star 'on' border color"),
-		'#default_value' => variable_get('voting_on_border', '0x330000'),
-		'#size' => 8,
-		'#maxlength' => 8,
-	);
-	$form['colors']['voting_off_fill'] = array(
-		'#type' => 'textfield',
-		'#title' => t("Star 'off' fill color"),
-		'#default_value' => variable_get('voting_off_fill', '0xcccccc'),
-		'#size' => 8,
-		'#maxlength' => 8,
-	);
-	$form['colors']['voting_off_border'] = array(
-		'#type' => 'textfield',
-		'#title' => t("Star 'off' border color"),
-		'#default_value' => variable_get('voting_off_border', '0x333333'),
-		'#size' => 8,
-		'#maxlength' => 8,
-	);
-	$form['colors']['voting_txt_color'] = array(
-		'#type' => 'textfield',
-		'#title' => t("Text color"),
-		'#default_value' => variable_get('voting_txt_color', '0x000000'),
-		'#size' => 8,
-		'#maxlength' => 8,
-	);
-	
-	// Text strings
-	$form['text'] = array(
-		'#type' => 'fieldset',
-		'#title' => t('Text Strings'),
-		'#collapsible' => true,
-		'#collapsed' => true,
-	);
-	$form['text']['voting_txt_vote1'] = array(
-		'#type' => 'textfield',
-		'#title' => t('Star 1'),
-		'#default_value' => variable_get('voting_txt_vote1', 'Awful'),
-		'#size' => 20,
-		'#maxlength' => 20,
-	);
-	$form['text']['voting_txt_vote2'] = array(
-		'#type' => 'textfield',
-		'#title' => t('Star 2'),
-		'#default_value' => variable_get('voting_txt_vote2', 'Poor'),
-		'#size' => 20,
-		'#maxlength' => 20,
-	);
-	$form['text']['voting_txt_vote3'] = array(
-		'#type' => 'textfield',
-		'#title' => t('Star 3'),
-		'#default_value' => variable_get('voting_txt_vote3', 'Average'),
-		'#size' => 20,
-		'#maxlength' => 20,
-	);
-	$form['text']['voting_txt_vote4'] = array(
-		'#type' => 'textfield',
-		'#title' => t('Star 4'),
-		'#default_value' => variable_get('voting_txt_vote4', 'Good'),
-		'#size' => 20,
-		'#maxlength' => 20,
-	);
-	$form['text']['voting_txt_vote5'] = array(
-		'#type' => 'textfield',
-		'#title' => t('Star 5'),
-		'#default_value' => variable_get('voting_txt_vote5', 'Excellent'),
-		'#size' => 20,
-		'#maxlength' => 20,
-	);
-	$form['text']['voting_txt_before_vote'] = array(
-		'#type' => 'textfield',
-		'#title' => t('Message shown BEFORE a user votes'),
-		'#default_value' => variable_get('voting_txt_before_vote', 'Rate This:'),
-		'#size' => 20,
-		'#maxlength' => 20,
-	);
-	$form['text']['voting_txt_after_vote'] = array(
-		'#type' => 'textfield',
-		'#title' => t('Message shown AFTER a user votes'),
-		'#default_value' => variable_get('voting_txt_after_vote', 'My Vote:'),
-		'#size' => 20,
-		'#maxlength' => 20,
-	);
-	$form['text']['voting_txt_login'] = array(
-		'#type' => 'textfield',
-		'#title' => t('No permission to vote message'),
-		'#default_value' => variable_get('voting_txt_login', 'Please login or register to vote.'),
-		'#size' => 40,
-		'#maxlength' => 40,
-	);
-  return $form;
-}
-
-/**
- * Return a vote object (containing the user's vote, average vote, and number of votes)
- */
-function voting_get_vote($content_type, $content_id) {
-  global $user;
-  
-	// my vote
-  if ($_COOKIE["vote_{$content_type}_{$content_id}"]) { // get user's vote from a cookie on their computer
-    $voting_id = $_COOKIE["vote_{$content_type}_{$content_id}"];
-    $result = db_query("SELECT * FROM {votes} WHERE voting_id=%d", $voting_id);
-    $vote = db_fetch_object($result);
-  } elseif ($user->uid) { // get the user's vote by using their user_id
-    $result = db_query("SELECT * FROM {votes} WHERE content_type='%s' AND content_id=%d AND uid=%d", $content_type, $content_id, $user->uid);
-    $vote = db_fetch_object($result);
-  } else { // get the user's vote from their IP address (only within one hour, or whatever the voting_ip_timeout variable is set to)
-    $result = db_query("SELECT * FROM {votes} WHERE content_type='%s' AND content_id=%d AND hostname='%s' AND timestamp > %d", $content_type, $content_id, $_SERVER['REMOTE_ADDR'], time() - variable_get("voting_ip_timeout", 60 * 60));
-    $vote = db_fetch_object($result);
-  }
-  
-	// average vote
-	$result = db_query("SELECT SUM(vote)/COUNT(vote) AS avg_vote FROM {votes} WHERE content_type='%s' AND content_id=%d", $content_type, $content_id);
-	$vote->avg_vote = $result ? db_result($result, "avg_vote") : 0;
-	$vote->avg_vote = round($vote->avg_vote / 0.5) * 0.5; // rounds to nearest half
-	$vote->avg_vote = number_format($vote->avg_vote, 1); // fixes to 1 decimal place
-	
-	// number of votes
-	$result = db_query("SELECT COUNT(vote) FROM {votes} WHERE content_type='%s' AND content_id=%d", $content_type, $content_id);
-	$vote->num_votes = $result ? db_result($result, 0) : 0;
-	
-  return $vote;
-}
-
-function voting_convert_to_percent($vote) {
-	// round to nearest integer
-	$vote = round($vote);
-	// set limits
-	$vote = ($vote < 1) ? 1 : $vote;
-	$vote = ($vote > 5) ? 5 : $vote;
-	// convert to percentage
-	switch($vote) {
-		case 5: return 90; 
-		case 4: return 70; 
-		case 3: return 50; 
-		case 2: return 30; 
-		case 1: return 10; 
-		default: return 0;
-	}
-}
-
-function voting_convert_from_percent($vote) {
-	// round to nearest ten
-	$vote = 10 * round($vote / 10);
-	// set limits
-	$vote = ($vote < 0) ? 0 : $vote;
-	$vote = ($vote > 100) ? 100 : $vote;
-	// convert to scale from 1.0 to 5.0
-	switch($vote) {
-		case 100:
-		case 90: return 5.0; 
-		case 80: return 4.5; 
-		case 70: return 4.0; 
-		case 60: return 3.5; 
-		case 50: return 3.0; 
-		case 40: return 2.5; 
-		case 30: return 2.0; 
-		case 20: return 1.5; 
-		case 10: return 1.0;
-		default: return 0;
-	}
-}
-
-/**
- * This function is used with a Macromedia Flash based voting control to send and receive data in 
- * one step.  First, Flash is passed the content_type and content_id from the page where it is used.
- * Then, Flash calls /voting/flash and sends the content_type and content_id using POST.  A vote is 
- * not passed, so this function will not insert a vote, but it will return the current voting information.
- * If a user votes (or changes their vote), this function is called again from Flash, this time with 
- * a vote.
- */
-function voting_flash() {
-  global $user;
-  
-  $content_type = $_POST['content_type'];
-  $content_id = $_POST['content_id'];
-  $user_vote = $_POST['vote'];
-	
-	if ($user_vote) { // if a new vote is sent...
-		$vote->value = voting_convert_to_percent($user_vote);
-    $vote->value_type = 'percent';
-    $vote->tag = 'vote';
-		votingapi_set_vote($content_type, $content_id, $vote);
-	} else {
-		$vote = votingapi_get_user_votes($content_type, $content_id);
-		$user_vote = voting_convert_from_percent($vote[0]->value);
-	}
-	
-	// get average and count
-	$average = votingapi_get_voting_result($content_type, $content_id, 'percent', 'vote', 'average');
-	$avg_vote = voting_convert_from_percent($average->value);
-	$count = votingapi_get_voting_result($content_type, $content_id, 'percent', 'vote', 'count');
-	
-  // return the current vote info to flash
-  $user_vote = ($user_vote) ? $user_vote : 0;
-  $avg_vote = ($avg_vote) ? $avg_vote : 0;
-  $num_votes = ($count->value) ? $count->value : 0;
-  echo "vote=$user_vote&avg_vote=$avg_vote&num_votes=$num_votes";
-}
-
-/**
- * Call this from a node to display a voting control
- */
-function voting_control_node(&$node, $teaser = false, $page = false) { // called by node-based modules (or the nodeapi's view function in this file)
-  if (user_access('vote on content') || user_access('show average without voting')) {
-    if (($node->voting) && ($page)) {
-      return theme('voting_control_flash', 'node', $node->nid);
-    }
-  }
-}
-
-/**
- * Call this from anywhere to display a voting control
- */
-function voting_control_generic($content_type, $content_id, $attributes = array()) {  // called by non-node types of content
-  if (user_access('vote on content') || user_access('show average without voting')) {
-    return theme('voting_control_flash', $content_type, $content_id, $attributes);
-  }
-}
-
-/**
- * Display a voting control in Flash
- */
-function theme_voting_control_flash($content_type, $content_id, $attributes = array()) {
-  global $user;
-  
-  // optional user_access() dependent variables
-  if (user_access('vote on content') && user_access('show average without voting')) {
-    $mode = 'show_avg_first';
-  } elseif (user_access('show average without voting')) {
-    $mode = 'show_avg_only';
-  }
-	
-	// optional variables set from administer/settings/voting
-  $star_on_fill = variable_get('voting_on_fill', '0x990000');
-  $star_on_border = variable_get('voting_on_border', '0x330000');
-  $star_off_fill = variable_get('voting_off_fill', '0xcccccc');
-  $star_off_border = variable_get('voting_off_border', '0x333333');
-  $txt_color = variable_get('voting_txt_color', '0x000000');
-  $txt_vote1 = variable_get('voting_txt_vote1', 'Awful');
-  $txt_vote2 = variable_get('voting_txt_vote2', 'Poor');
-  $txt_vote3 = variable_get('voting_txt_vote3', 'Average');
-  $txt_vote4 = variable_get('voting_txt_vote4', 'Good');
-  $txt_vote5 = variable_get('voting_txt_vote5', 'Excellent');
-  $txt_login = urlencode(variable_get('voting_txt_login', 'Please login or register to vote.'));
-	
-	// optional: certain variables can be overridden on individual voting controls
-	//   ex: $output .= voting_control_generic('pagevote', $node->nid, array('prompt' => 'Do you like it?', 'confirmation' => 'Vote saved!', 'bgcolor' => '0xffffff'));
-  $txt_before_vote = urlencode(($attributes['prompt']) ? $attributes['prompt'] : variable_get('voting_txt_before_vote', 'Rate This:'));
-  $txt_after_vote = urlencode(($attributes['confirmation']) ? $attributes['confirmation'] : variable_get('voting_txt_after_vote', 'My Vote:'));
-	$bgcolor = ($attributes['bgcolor']) ? $attributes['bgcolor'] : variable_get('voting_bgcolor', '0xffffff');
-	
-  // make optional variables into a really long querystring
-  $optional_vars = "&mode=$mode&bgcolor=$bgcolor&star_on_fill=$star_on_fill&star_on_border=$star_on_border";
-  $optional_vars .= "&star_off_fill=$star_off_fill&star_off_border=$star_off_border&txt_color=$txt_color";
-  $optional_vars .= "&txt_vote1=$txt_vote1&txt_vote2=$txt_vote2&txt_vote3=$txt_vote3&txt_vote4=$txt_vote4&txt_vote5=$txt_vote5";
-  $optional_vars .= "&txt_login=$txt_login&txt_before_vote=$txt_before_vote&txt_after_vote=$txt_after_vote";
-  
-	// create the Flash filename, including the required variables and optional querystring
-	$filename = base_path() . drupal_get_path('module', 'voting') . "/voting.swf?content_type=$content_type&content_id=$content_id&base_url=" . base_path() . $optional_vars;
-  
-	// create the HTML to put the Flash object on the page
-	//
-	// NOTE: The object is nested in a table for CSS styling.  It does 
-	// not seem to work correctly in Firefox when a DIV is used instead.
-  $output .= "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"voting\"><tr><td>\n";
-  $output .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
-   codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
-   width="210" height="35" id="voting" align="">' . "\n";
-  $output .= '<param name=movie value="' . $filename . '">' . "\n";
-  $output .= '<param name=quality value=high>' . "\n";
-  $output .= '<embed src="' . $filename . '" quality="high" width="210" height="35" name="voting" align=""
-   type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>' . "\n";
-  $output .= "</object>\n";
-  $output .= "</td></tr></table>\n";
-  
-  return $output;
-}
-
-/**
- * Implementation of hook_nodeapi()
- */
-function voting_nodeapi(&$node, $op, $teaser, $page) {
-  switch ($op) {
-    case 'view':
-      if ($node->voting) { // if voting is enabled for this node and this view (votes don't show on teasers)
-				switch (variable_get('voting_location', 1)) {
-					case 0: // display above the node
-						$node->body = voting_control_node($node, $teaser, $page) . $node->body;
-						break;
-					case 1: // display below the node
-						$node->body .= voting_control_node($node, $teaser, $page);
-						break;
-					case 2: // do not display
-				}
-      }
-      break;
-    case 'load':
-      $result = db_query("SELECT voting FROM {node_voting} WHERE nid = %d", $node->nid);
-      if ($voting = db_fetch_object($result)) {
-        $node->voting = $voting->voting;
-      } else {
-        $node->voting = variable_get("voting_nodeapi_{$node->type}", 'never');
-      }
-      if ($teaser && !variable_get('voting_show_in_teaser', 0)) {
-        $node->voting = 0;
-      }
-      break;
-    case 'validate':
-      if (!user_access('administer nodes')) {
-        // Force default (for this content type) for normal users:
-        $node->voting = variable_get('voting_' . $node->type, 0);
-      }
-			voting_filter_validate($node);
-      break; 
-    case 'update':
-      $result = db_query("SELECT * FROM {node_voting} WHERE nid = %d", $node->nid);
-      if ($row = db_fetch_object($result)) { // if the voting on/off setting is already in the database
-        db_query("UPDATE {node_voting} SET voting=%d WHERE nid = %d", $node->voting, $node->nid);
-      } else { // or else add this setting to the database
-        db_query("INSERT INTO {node_voting} (nid, voting) VALUES (%d, %d)", $node->nid, $node->voting);
-      }
-      break;
-    case 'insert':
-      db_query("INSERT INTO {node_voting} (nid, voting) VALUES (%d, %d)", $node->nid, $node->voting);
-      break;
-    case 'delete':
-      db_query('DELETE FROM {node_voting} WHERE nid = %d', $node->nid);
-      //db_query("DELETE FROM {votes} WHERE content_type='node' AND content_id = %d", $node->nid);
-      break;
-  }
-}
-
-
-/**
- * @defgroup event_nodeapi Functions for nodeapi integration
- */
-function voting_form_alter($form_id, &$form) {
-  global $user;
-  $type = (isset($form['type']) && isset($form['type']['#value'])) ? $form['type']['#value'] : NULL;
-  $node = isset($form['#node']) ? $form['#node'] : NULL;
-
-  switch ($form_id) {
-    // node settings form
-    case $type .'_node_settings':
-      $form['workflow']['voting_nodeapi_'. $type] = array(
-        '#type' => 'radios',
-        '#title' => t('Show voting control'),
-        '#default_value' => variable_get('voting_nodeapi_'. $type, 'never'),
-        '#options' => array('always' => t('Always'), 'usually' => t('Usually'), 'sometimes' => 'Sometimes', 'never' => t('Never')),
-        '#description' => t('<strong>Always: </strong>A voting control will be displayed with all nodes of this types (including existing nodes).<br />
-					<strong>Usually: </strong>Voting controls will usually be shown with this node type, but a setting in the node edit form will allow voting administrators to disable some voting controls.<br />
-					<strong>Sometimes: </strong>Voting control will be disabed by default, but a setting in the node edit form will allow voting administrators to enable some voting controls.<br />
-					<strong>Never: </strong>Voting controls will never be shown with this node type.')
-      );
-      break;
-			
-    // node edit form
-    case $type .'_node_form':
-			switch (variable_get('voting_nodeapi_' . $type, 'never')) {
-				case 'always':
-					break; // don't display an option if voting is set to 'always' for this content type
-				case 'never':
-					break; // don't display an option if voting is set to 'never' for this content type
-				case 'usually':
-					$default = 1;
-				case 'sometimes':
-					$default = 0;
-					
-					$selected = isset($node->voting) ? $node->voting : $default;
-					$form['voting'] = array(
-						'#type' => 'fieldset',
-						'#title' => t('Voting'),
-						'#collapsible' => true,
-						'#collapsed' => true,
-						);
-					$form['voting']['voting'] = array(
-						'#type' => 'radios',
-						'#title' => 'Voting',
-						'#default_value' => $selected,
-						'#options' => array(0 => t('Disabled'), 1 => t('Enabled')),
-					);
-			}
-   	break;
-  }
-}
-
-
-/** ---------------------------------------------------------------------------------------------------
- * Voting Filter
- *
- * This section implements the hook_filter() and hook_filter_tips() to allow uses to add voting controls 
- * to their posts.  The format is [voting|type=artwork|prompt=Rate my artwork:|confirmation=Thanks for voting!] 
- * The voting filter works great with the tinyMCE WYSIWYG editor and the drupalvoting plugin.
- * ---------------------------------------------------------------------------------------------------- */
- 
-/**
- * Implementation of hook_filter().
- */
-function voting_filter($op, $delta = 0, $format = -1, $text = '') {
-  switch ($op) {
-    case 'list':
-      return array(0 => t('Inline voting'));
-
-    case 'description':
-      return t('Add voting to your posts.');
-
-    case 'process':
-			// get all instances of the filter and send each one to the voting_filter_process() function
-			$regex_tags = "/\[voting\|([^\]]+)\]/";
-			$text = preg_replace_callback($regex_tags, "voting_filter_process", $text);
-      return $text;
-
-    default:
-      return $text;
-  }
-}
-
-/**
- * Implementation of hook_filter_tips().
- */
-function voting_filter_tips($delta, $format, $long = false) {
-	switch ($long) {
-		case 0:
-			return t('Voting controls can be added to this post.');
-		case 1:
-			return t('
-				<h4>Adding Voting Controls</h4>
-				<p>You can let people vote on your post, or things in your post, just by adding a carefully formatted tag in your post.
-				The tag should look like this: <br />[voting|type=artwork|prompt=Rate my artwork:|confirmation=Thanks for voting!] 
-				The prompt and confirmation are optional.</p>');
-	}
-}
-
-/**
- * Called by voting_filter for each instance of the voting filter on a page
- * $match[0] is the full filter tag, to be replaced with the voting control
- * $match[1] is the attributes in the form "type=node|id=123|prompt=Rate This:|confirmation=My Vote:"
- */
-function voting_filter_process($match) {
-	$regex_attributes = "/([a-zA-Z]*)=([^\|]+)/";
-	preg_match_all($regex_attributes, $match[1], $attributes, PREG_SET_ORDER);
-	foreach ($attributes as $attribute) {
-		$atts[$attribute[1]] = $attribute[2];
-	}
-	return voting_control_generic($atts['type'], $atts['id'], $atts);
-}
-
-/**
- * Called by voting_nodeapi, this function adds an ID (the nid) to the voting filter if it has been left off
- */
-function voting_filter_validate(&$node) {
-	// get all instances of the voting filter
-	$regex_tags = "/\[voting\|([^\]]+)\]/";
-	preg_match_all($regex_tags, $node->body, $matches, PREG_SET_ORDER);
-		
-	foreach ($matches as $match) {
-		$orig_filter_str = $match[0];
-		if (!preg_match("/id=[0-9]+/", $orig_filter_str)) {
-			if ($node->nid) {
-				$voting_nid = $node->nid;
-			} else {
-				// on a new post the NID hasn't been assigned yet and we can't call
-			  // db_next_id() yet becuase it will mess up the sequence for the node_save().
-				// my current solution is to use two modified lines from db_next_id() to get the 
-				// next nid without incrementing it.
-				$name = db_prefix_tables('{node}_nid');
-				$voting_nid = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s'", $name)) + 1;
-			}
-			$new_filter_str = str_replace('[voting', '[voting|id=' . $voting_nid, $orig_filter_str);
-			$node->body = str_replace($orig_filter_str, $new_filter_str, $node->body);
-		}
-	}
-}
+<?php
+
+/**
+ * Implementation of hook_help().
+ */
+function voting_help($section) {
+  switch ($section) {
+    case 'admin/modules#description':
+      return t("Enables content to be voted on by the community.");
+    case 'admin/settings/voting':
+      return t("Voting provides a way for your users to vote on submitted content.");
+  }
+}
+
+/**
+ * Implementation of hook_perm().
+ */
+function voting_perm() {
+  return array('vote on content', 'show average without voting');
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function voting_menu($type) {
+  $items = array();
+  $items[] = array(
+    'path' => 'voting/flash',
+    'title' => t('voting'),
+    'callback' => 'voting_flash',
+    'access' => user_access('access content'),
+    'type' => MENU_CALLBACK);
+  
+  return $items;
+}
+
+/**
+ * Implementation of hook_settings()
+ */
+function voting_settings() {
+	if (!function_exists('votingapi_set_vote')) {
+		drupal_set_message('The voting module depends on the voting API module.  Please install the voting API module before attempting to use this module.', 'error');
+	}
+	
+	// General options
+	$form['general'] = array(
+		'#type' => 'fieldset',
+		'#title' => t('General options'),
+		'#collapsible' => true,
+		'#collapsed' => false,
+	);
+	$form['general']['voting_location'] = array(
+		'#type' => 'radios',
+		'#title' => t('Voting controls on nodes'),
+		'#default_value' => variable_get('voting_location', 1),
+		'#options' => array(t('Display above the node'), t('Display below the node'), t('Do not display')),
+		'#description' => t('Position of the voting control.  Select "Do not display" if you are calling the voting module function directly from your theme and/or module code.'),
+	);
+	$form['general']['voting_show_in_teaser'] = array(
+		'#type' => 'radios',
+		'#title' => t('Show voting in teaser'),
+		'#default_value' => variable_get('voting_show_in_teaser', 0),
+		'#options' => array(1 => t('yes'), 0 => t('no')),
+	);
+	$form['general']['voting_ip_timeout'] = array(
+		'#type' => 'textfield',
+		'#title' => t("Voting IP timeout (in seconds)"),
+		'#default_value' => variable_get('voting_ip_timeout', 3600),
+		'#size' => 8,
+		'#maxlength' => 8,
+		'#description' => t('Controls if and how often users with the same IP address can vote for the same thing.  Set it to 0 to disable this feature.'),
+	);
+	
+	// Colors
+	$form['colors'] = array(
+		'#type' => 'fieldset',
+		'#title' => t('Colors'),
+		'#collapsible' => true,
+		'#collapsed' => true,
+	);
+	$form['colors']['voting_bgcolor'] = array(
+		'#type' => 'textfield',
+		'#title' => t('Background color for voting control'),
+		'#default_value' => variable_get('voting_bgcolor', '0xffffff'),
+		'#size' => 8,
+		'#maxlength' => 8,
+	);
+	$form['colors']['voting_on_fill'] = array(
+		'#type' => 'textfield',
+		'#title' => t("Star 'on' fill color"),
+		'#default_value' => variable_get('voting_on_fill', '0x990000'),
+		'#size' => 8,
+		'#maxlength' => 8,
+	);
+	$form['colors']['voting_on_border'] = array(
+		'#type' => 'textfield',
+		'#title' => t("Star 'on' border color"),
+		'#default_value' => variable_get('voting_on_border', '0x330000'),
+		'#size' => 8,
+		'#maxlength' => 8,
+	);
+	$form['colors']['voting_off_fill'] = array(
+		'#type' => 'textfield',
+		'#title' => t("Star 'off' fill color"),
+		'#default_value' => variable_get('voting_off_fill', '0xcccccc'),
+		'#size' => 8,
+		'#maxlength' => 8,
+	);
+	$form['colors']['voting_off_border'] = array(
+		'#type' => 'textfield',
+		'#title' => t("Star 'off' border color"),
+		'#default_value' => variable_get('voting_off_border', '0x333333'),
+		'#size' => 8,
+		'#maxlength' => 8,
+	);
+	$form['colors']['voting_txt_color'] = array(
+		'#type' => 'textfield',
+		'#title' => t("Text color"),
+		'#default_value' => variable_get('voting_txt_color', '0x000000'),
+		'#size' => 8,
+		'#maxlength' => 8,
+	);
+	
+	// Text strings
+	$form['text'] = array(
+		'#type' => 'fieldset',
+		'#title' => t('Text Strings'),
+		'#collapsible' => true,
+		'#collapsed' => true,
+	);
+	$form['text']['voting_txt_vote1'] = array(
+		'#type' => 'textfield',
+		'#title' => t('Star 1'),
+		'#default_value' => variable_get('voting_txt_vote1', 'Awful'),
+		'#size' => 20,
+		'#maxlength' => 20,
+	);
+	$form['text']['voting_txt_vote2'] = array(
+		'#type' => 'textfield',
+		'#title' => t('Star 2'),
+		'#default_value' => variable_get('voting_txt_vote2', 'Poor'),
+		'#size' => 20,
+		'#maxlength' => 20,
+	);
+	$form['text']['voting_txt_vote3'] = array(
+		'#type' => 'textfield',
+		'#title' => t('Star 3'),
+		'#default_value' => variable_get('voting_txt_vote3', 'Average'),
+		'#size' => 20,
+		'#maxlength' => 20,
+	);
+	$form['text']['voting_txt_vote4'] = array(
+		'#type' => 'textfield',
+		'#title' => t('Star 4'),
+		'#default_value' => variable_get('voting_txt_vote4', 'Good'),
+		'#size' => 20,
+		'#maxlength' => 20,
+	);
+	$form['text']['voting_txt_vote5'] = array(
+		'#type' => 'textfield',
+		'#title' => t('Star 5'),
+		'#default_value' => variable_get('voting_txt_vote5', 'Excellent'),
+		'#size' => 20,
+		'#maxlength' => 20,
+	);
+	$form['text']['voting_txt_before_vote'] = array(
+		'#type' => 'textfield',
+		'#title' => t('Message shown BEFORE a user votes'),
+		'#default_value' => variable_get('voting_txt_before_vote', 'Rate This:'),
+		'#size' => 20,
+		'#maxlength' => 20,
+	);
+	$form['text']['voting_txt_after_vote'] = array(
+		'#type' => 'textfield',
+		'#title' => t('Message shown AFTER a user votes'),
+		'#default_value' => variable_get('voting_txt_after_vote', 'My Vote:'),
+		'#size' => 20,
+		'#maxlength' => 20,
+	);
+	$form['text']['voting_txt_login'] = array(
+		'#type' => 'textfield',
+		'#title' => t('No permission to vote message'),
+		'#default_value' => variable_get('voting_txt_login', 'Please login or register to vote.'),
+		'#size' => 40,
+		'#maxlength' => 40,
+	);
+  return $form;
+}
+
+/**
+ * Return a vote object (containing the user's vote, average vote, and number of votes)
+ */
+function voting_get_vote($content_type, $content_id) {
+  global $user;
+  
+	// my vote
+  if ($_COOKIE["vote_{$content_type}_{$content_id}"]) { // get user's vote from a cookie on their computer
+    $voting_id = $_COOKIE["vote_{$content_type}_{$content_id}"];
+    $result = db_query("SELECT * FROM {votes} WHERE voting_id=%d", $voting_id);
+    $vote = db_fetch_object($result);
+  } elseif ($user->uid) { // get the user's vote by using their user_id
+    $result = db_query("SELECT * FROM {votes} WHERE content_type='%s' AND content_id=%d AND uid=%d", $content_type, $content_id, $user->uid);
+    $vote = db_fetch_object($result);
+  } else { // get the user's vote from their IP address (only within one hour, or whatever the voting_ip_timeout variable is set to)
+    $result = db_query("SELECT * FROM {votes} WHERE content_type='%s' AND content_id=%d AND hostname='%s' AND timestamp > %d", $content_type, $content_id, $_SERVER['REMOTE_ADDR'], time() - variable_get("voting_ip_timeout", 60 * 60));
+    $vote = db_fetch_object($result);
+  }
+  
+	// average vote
+	$result = db_query("SELECT SUM(vote)/COUNT(vote) AS avg_vote FROM {votes} WHERE content_type='%s' AND content_id=%d", $content_type, $content_id);
+	$vote->avg_vote = $result ? db_result($result, "avg_vote") : 0;
+	$vote->avg_vote = round($vote->avg_vote / 0.5) * 0.5; // rounds to nearest half
+	$vote->avg_vote = number_format($vote->avg_vote, 1); // fixes to 1 decimal place
+	
+	// number of votes
+	$result = db_query("SELECT COUNT(vote) FROM {votes} WHERE content_type='%s' AND content_id=%d", $content_type, $content_id);
+	$vote->num_votes = $result ? db_result($result, 0) : 0;
+	
+  return $vote;
+}
+
+function voting_convert_to_percent($vote) {
+	// round to nearest integer
+	$vote = round($vote);
+	// set limits
+	$vote = ($vote < 1) ? 1 : $vote;
+	$vote = ($vote > 5) ? 5 : $vote;
+	// convert to percentage
+	switch($vote) {
+		case 5: return 90; 
+		case 4: return 70; 
+		case 3: return 50; 
+		case 2: return 30; 
+		case 1: return 10; 
+		default: return 0;
+	}
+}
+
+function voting_convert_from_percent($vote) {
+	// round to nearest ten
+	$vote = 10 * round($vote / 10);
+	// set limits
+	$vote = ($vote < 0) ? 0 : $vote;
+	$vote = ($vote > 100) ? 100 : $vote;
+	// convert to scale from 1.0 to 5.0
+	switch($vote) {
+		case 100:
+		case 90: return 5.0; 
+		case 80: return 4.5; 
+		case 70: return 4.0; 
+		case 60: return 3.5; 
+		case 50: return 3.0; 
+		case 40: return 2.5; 
+		case 30: return 2.0; 
+		case 20: return 1.5; 
+		case 10: return 1.0;
+		default: return 0;
+	}
+}
+
+/**
+ * This function is used with a Macromedia Flash based voting control to send and receive data in 
+ * one step.  First, Flash is passed the content_type and content_id from the page where it is used.
+ * Then, Flash calls /voting/flash and sends the content_type and content_id using POST.  A vote is 
+ * not passed, so this function will not insert a vote, but it will return the current voting information.
+ * If a user votes (or changes their vote), this function is called again from Flash, this time with 
+ * a vote.
+ */
+function voting_flash() {
+  global $user;
+  
+  $content_type = $_POST['content_type'];
+  $content_id = $_POST['content_id'];
+  $user_vote = $_POST['vote'];
+	
+	if ($user_vote) { // if a new vote is sent...
+		$vote->value = voting_convert_to_percent($user_vote);
+    $vote->value_type = 'percent';
+    $vote->tag = 'vote';
+		votingapi_set_vote($content_type, $content_id, $vote);
+	} else {
+		$vote = votingapi_get_user_votes($content_type, $content_id);
+		$user_vote = voting_convert_from_percent($vote[0]->value);
+	}
+	
+	// get average and count
+	$average = votingapi_get_voting_result($content_type, $content_id, 'percent', 'vote', 'average');
+	$avg_vote = voting_convert_from_percent($average->value);
+	$count = votingapi_get_voting_result($content_type, $content_id, 'percent', 'vote', 'count');
+	
+  // return the current vote info to flash
+  $user_vote = ($user_vote) ? $user_vote : 0;
+  $avg_vote = ($avg_vote) ? $avg_vote : 0;
+  $num_votes = ($count->value) ? $count->value : 0;
+  echo "vote=$user_vote&avg_vote=$avg_vote&num_votes=$num_votes";
+}
+
+/**
+ * Call this from a node to display a voting control
+ */
+function voting_control_node(&$node, $teaser = false, $page = false) { // called by node-based modules (or the nodeapi's view function in this file)
+ if (user_access('vote on content') || user_access('show average without voting')) {
+    if (($node->voting)) {
+      return theme('voting_control_flash', 'node', $node->nid);
+    }
+ }
+}
+
+/**
+ * Call this from anywhere to display a voting control
+ */
+function voting_control_generic($content_type, $content_id, $attributes = array()) {  // called by non-node types of content
+  if (user_access('vote on content') || user_access('show average without voting')) {
+    return theme('voting_control_flash', $content_type, $content_id, $attributes);
+  }
+}
+
+/**
+ * Display a voting control in Flash
+ */
+function theme_voting_control_flash($content_type, $content_id, $attributes = array()) {
+  global $user;
+  
+  // optional user_access() dependent variables
+  if (user_access('vote on content') && user_access('show average without voting')) {
+    $mode = 'show_avg_first';
+  } elseif (user_access('show average without voting')) {
+    $mode = 'show_avg_only';
+  }
+	
+	// optional variables set from administer/settings/voting
+  $star_on_fill = variable_get('voting_on_fill', '0x990000');
+  $star_on_border = variable_get('voting_on_border', '0x330000');
+  $star_off_fill = variable_get('voting_off_fill', '0xcccccc');
+  $star_off_border = variable_get('voting_off_border', '0x333333');
+  $txt_color = variable_get('voting_txt_color', '0x000000');
+  $txt_vote1 = variable_get('voting_txt_vote1', 'Awful');
+  $txt_vote2 = variable_get('voting_txt_vote2', 'Poor');
+  $txt_vote3 = variable_get('voting_txt_vote3', 'Average');
+  $txt_vote4 = variable_get('voting_txt_vote4', 'Good');
+  $txt_vote5 = variable_get('voting_txt_vote5', 'Excellent');
+  $txt_login = urlencode(variable_get('voting_txt_login', 'Please login or register to vote.'));
+	
+	// optional: certain variables can be overridden on individual voting controls
+	//   ex: $output .= voting_control_generic('pagevote', $node->nid, array('prompt' => 'Do you like it?', 'confirmation' => 'Vote saved!', 'bgcolor' => '0xffffff'));
+  $txt_before_vote = urlencode(($attributes['prompt']) ? $attributes['prompt'] : variable_get('voting_txt_before_vote', 'Rate This:'));
+  $txt_after_vote = urlencode(($attributes['confirmation']) ? $attributes['confirmation'] : variable_get('voting_txt_after_vote', 'My Vote:'));
+	$bgcolor = ($attributes['bgcolor']) ? $attributes['bgcolor'] : variable_get('voting_bgcolor', '0xffffff');
+	
+  // make optional variables into a really long querystring
+  $optional_vars = "&mode=$mode&bgcolor=$bgcolor&star_on_fill=$star_on_fill&star_on_border=$star_on_border";
+  $optional_vars .= "&star_off_fill=$star_off_fill&star_off_border=$star_off_border&txt_color=$txt_color";
+  $optional_vars .= "&txt_vote1=$txt_vote1&txt_vote2=$txt_vote2&txt_vote3=$txt_vote3&txt_vote4=$txt_vote4&txt_vote5=$txt_vote5";
+  $optional_vars .= "&txt_login=$txt_login&txt_before_vote=$txt_before_vote&txt_after_vote=$txt_after_vote";
+  
+	// create the Flash filename, including the required variables and optional querystring
+	$filename = base_path() . drupal_get_path('module', 'voting') . "/voting.swf?content_type=$content_type&content_id=$content_id&base_url=" . base_path() . $optional_vars;
+  
+	// create the HTML to put the Flash object on the page
+	//
+	// NOTE: The object is nested in a table for CSS styling.  It does 
+	// not seem to work correctly in Firefox when a DIV is used instead.
+  $output .= "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"voting\"><tr><td>\n";
+  $output .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+   codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
+   width="210" height="35" id="voting" align="">' . "\n";
+  $output .= '<param name=movie value="' . $filename . '">' . "\n";
+  $output .= '<param name=quality value=high>' . "\n";
+  $output .= '<embed src="' . $filename . '" quality="high" width="210" height="35" name="voting" align=""
+   type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>' . "\n";
+  $output .= "</object>\n";
+  $output .= "</td></tr></table>\n";
+  
+  return $output;
+}
+
+/**
+ * Implementation of hook_nodeapi()
+ */
+function voting_nodeapi(&$node, $op, $teaser, $page) {
+  switch ($op) {
+    case 'view':
+      if ($node->voting) { // if voting is enabled for this node and this view (votes don't show on teasers)
+				switch (variable_get('voting_location', 1)) {
+					case 0: // display above the node
+						if ($teaser && variable_get('voting_show_in_teaser', 0)) {
+							$node->teaser = voting_control_node($node, $teaser, $page) . $node->teaser;
+						}
+						$node->body = voting_control_node($node, $teaser, $page) . $node->body;
+						
+						break;
+					case 1: // display below the node
+						if ($teaser && variable_get('voting_show_in_teaser', 0)) {
+							$node->teaser .= voting_control_node($node, $teaser, $page);
+						}
+						$node->body .= voting_control_node($node, $teaser, $page);
+											
+						break;
+					case 2: // do not display
+				}
+      }
+      break;
+    case 'load':
+		$result = db_query("SELECT voting FROM {node_voting} WHERE nid = %d", $node->nid);
+		if ($row = db_fetch_object($result)) {
+			$node->voting = $row->voting;
+ 		} 
+		else {
+			$node->voting = variable_get("voting_nodeapi_{$node->type}", 'never') == 'never' ? 0:1;
+		}
+    break;
+    case 'validate':
+		voting_filter_validate($node);
+		break; 
+	case 'submit':
+		$node->voting = variable_get('voting_nodeapi_' . $node->type, 'never') == 'never' ? 0:1;
+	    break;
+    case 'update':
+      $result = db_query("SELECT * FROM {node_voting} WHERE nid = %d", $node->nid);
+      if ($row = db_fetch_object($result)) { // if the voting on/off setting is already in the database
+        db_query("UPDATE {node_voting} SET voting=%d WHERE nid = %d", $node->voting, $node->nid);
+      } else { // or else add this setting to the database
+        db_query("INSERT INTO {node_voting} (nid, voting) VALUES (%d, %d)", $node->nid, $node->voting);
+      }
+      break;
+    case 'insert':
+		db_query("INSERT INTO {node_voting} (nid, voting) VALUES (%d, %d)", $node->nid, $node->voting);
+		break;
+    case 'delete':
+      db_query('DELETE FROM {node_voting} WHERE nid = %d', $node->nid);
+      //db_query("DELETE FROM {votes} WHERE content_type='node' AND content_id = %d", $node->nid);
+  }
+}
+
+
+/**
+ * @defgroup event_nodeapi Functions for nodeapi integration
+ */
+function voting_form_alter($form_id, &$form) {
+  global $user;
+  $type = (isset($form['type']) && isset($form['type']['#value'])) ? $form['type']['#value'] : NULL;
+  $node = isset($form['#node']) ? $form['#node'] : NULL;
+
+  switch ($form_id) {
+    // node settings form
+    case $type .'_node_settings':
+      $form['workflow']['voting_nodeapi_'. $type] = array(
+        '#type' => 'radios',
+        '#title' => t('Show voting control'),
+        '#default_value' => variable_get('voting_nodeapi_'. $type, 'never'),
+        '#options' => array('always' => t('Always'), 'usually' => t('Usually'), 'sometimes' => 'Sometimes', 'never' => t('Never')),
+        '#description' => t('<strong>Always: </strong>A voting control will be displayed with all nodes of this types (including existing nodes).<br />
+					<strong>Usually: </strong>Voting controls will usually be shown with this node type, but a setting in the node edit form will allow voting administrators to disable some voting controls.<br />
+					<strong>Sometimes: </strong>Voting control will be disabed by default, but a setting in the node edit form will allow voting administrators to enable some voting controls.<br />
+					<strong>Never: </strong>Voting controls will never be shown with this node type.')
+      );
+      break;
+			
+    // node edit form
+    case $type .'_node_form':
+			switch (variable_get('voting_nodeapi_' . $type, 'never')) {
+				case 'always':
+					break; // don't display an option if voting is set to 'always' for this content type
+				case 'never':
+					break; // don't display an option if voting is set to 'never' for this content type
+				case 'usually':
+					$default = 1;
+				case 'sometimes':
+					$default = 0;
+					
+					$selected = isset($node->voting) ? $node->voting : $default;
+					$form['voting'] = array(
+						'#type' => 'fieldset',
+						'#title' => t('Voting'),
+						'#collapsible' => true,
+						'#collapsed' => true,
+						);
+					$form['voting']['voting'] = array(
+						'#type' => 'radios',
+						'#title' => 'Voting',
+						'#default_value' => $selected,
+						'#options' => array(0 => t('Disabled'), 1 => t('Enabled')),
+					);
+			}
+   	break;
+  }
+}
+
+
+/** ---------------------------------------------------------------------------------------------------
+ * Voting Filter
+ *
+ * This section implements the hook_filter() and hook_filter_tips() to allow uses to add voting controls 
+ * to their posts.  The format is [voting|type=artwork|prompt=Rate my artwork:|confirmation=Thanks for voting!] 
+ * The voting filter works great with the tinyMCE WYSIWYG editor and the drupalvoting plugin.
+ * ---------------------------------------------------------------------------------------------------- */
+ 
+/**
+ * Implementation of hook_filter().
+ */
+function voting_filter($op, $delta = 0, $format = -1, $text = '') {
+  switch ($op) {
+    case 'list':
+      return array(0 => t('Inline voting'));
+
+    case 'description':
+      return t('Add voting to your posts.');
+
+    case 'process':
+			// get all instances of the filter and send each one to the voting_filter_process() function
+			$regex_tags = "/\[voting\|([^\]]+)\]/";
+			$text = preg_replace_callback($regex_tags, "voting_filter_process", $text);
+      return $text;
+
+    default:
+      return $text;
+  }
+}
+
+/**
+ * Implementation of hook_filter_tips().
+ */
+function voting_filter_tips($delta, $format, $long = false) {
+	switch ($long) {
+		case 0:
+			return t('Voting controls can be added to this post.');
+		case 1:
+			return t('
+				<h4>Adding Voting Controls</h4>
+				<p>You can let people vote on your post, or things in your post, just by adding a carefully formatted tag in your post.
+				The tag should look like this: <br />[voting|type=artwork|prompt=Rate my artwork:|confirmation=Thanks for voting!] 
+				The prompt and confirmation are optional.</p>');
+	}
+}
+
+/**
+ * Called by voting_filter for each instance of the voting filter on a page
+ * $match[0] is the full filter tag, to be replaced with the voting control
+ * $match[1] is the attributes in the form "type=node|id=123|prompt=Rate This:|confirmation=My Vote:"
+ */
+function voting_filter_process($match) {
+	$regex_attributes = "/([a-zA-Z]*)=([^\|]+)/";
+	preg_match_all($regex_attributes, $match[1], $attributes, PREG_SET_ORDER);
+	foreach ($attributes as $attribute) {
+		$atts[$attribute[1]] = $attribute[2];
+	}
+	return voting_control_generic($atts['type'], $atts['id'], $atts);
+}
+
+/**
+ * Called by voting_nodeapi, this function adds an ID (the nid) to the voting filter if it has been left off
+ */
+function voting_filter_validate(&$node) {
+	// get all instances of the voting filter
+	$regex_tags = "/\[voting\|([^\]]+)\]/";
+	preg_match_all($regex_tags, $node->body, $matches, PREG_SET_ORDER);
+		
+	foreach ($matches as $match) {
+		$orig_filter_str = $match[0];
+		if (!preg_match("/id=[0-9]+/", $orig_filter_str)) {
+			if ($node->nid) {
+				$voting_nid = $node->nid;
+			} else {
+				// on a new post the NID hasn't been assigned yet and we can't call
+			  // db_next_id() yet becuase it will mess up the sequence for the node_save().
+				// my current solution is to use two modified lines from db_next_id() to get the 
+				// next nid without incrementing it.
+				$name = db_prefix_tables('{node}_nid');
+				$voting_nid = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s'", $name)) + 1;
+			}
+			$new_filter_str = str_replace('[voting', '[voting|id=' . $voting_nid, $orig_filter_str);
+			$node->body = str_replace($orig_filter_str, $new_filter_str, $node->body);
+		}
+	}
+}
 ?>
\ No newline at end of file
