property plPending : "@@current song@@"
property plRecent : "@@recently played@@"
property nrUp : 20
property nrDown : -20

global iTunesRunning, iTunesRunning, existsCurrent, ok_to_Idle

on run
    delay 10
	set ok_to_Idle to false
	set iTunesRunning to false
	set e to my running_apps()
	if e contains "iTunes" then
		set iTunesRunning to true
		tell me to poll_itunes()
	else
		if button returned of (display dialog "iTunes is not running at the moment. Stay running anyway?" buttons {"No - Quit Now", "OK - Stay Running"} default button 2 with icon 2) contains "Quit" then quit
	end if
	set ok_to_Idle to true
	return 10
end run

-- refresh by tapping in the Dock
on reopen
	tell me to run
end reopen

on idle
	if ok_to_Idle then
		set e to my running_apps()
		if e contains "iTunes" then
			set iTunesRunning to true
			tell me to poll_itunes()
		else if e does not contain "iTunes" then
			set iTunesRunning to false
		end if
		return 10
	end if
end idle


on poll_itunes()
	set ok_to_Idle to false
	set alreadyPending to false
	set existsCurrent to false
	try
		
		tell application "System Events"
			set iTunesRunning to (exists process "iTunes")
		end tell
		
		if iTunesRunning then
			tell application "iTunes"
				
				--delay 5
				
				if not (exists playlist plPending) then
					make new playlist with properties {name:plPending}
				end if
				
				set playlistPending to playlist plPending
				
				-- do we have a track in there?
				if exists (the last track of playlistPending) then
					set thisPending to the last track of playlistPending
				else
					set thisPending to null
				end if
				
				set playlistRecent to playlist plRecent
				
				set thisRecent to the first track of playlistRecent
				
				if exists current track then
					set thisTrack to the current track
					set isCurrent to true
				end if
				
				if thisPending is not null then
					--Was the song played completely?
					if thisPending's database ID is thisRecent's database ID then
						--Raise the rating
						set thisPending's rating to my newRating(thisPending's rating, nrUp)
						delete thisPending
					else
						if isCurrent then
							--Is it the same song we saw last time we checked?
							if thisPending's database ID is thisTrack's database ID then
								-- yes, then do nothing
								set alreadyPending to true
							else
								-- nope, the last song was skipped
								-- lower its rating
								set thisPending's rating to my newRating(thisPending's rating, nrDown)
								delete thisPending
							end if
						else
							--  no song is currently being played or paused, 
							-- and the last song wasn't completed
							-- time do lower the rating on the last song
							set thisPending's rating to my newRating(thisPending's rating, nrDown)
							delete thisPending
						end if
					end if
				end if
				
				-- put the currently playing song into our work playlist
				if isCurrent and not alreadyPending then
					duplicate thisTrack to playlistPending
				end if
				
			end tell
		end if
		
	end try
	set ok_to_Idle to true
end poll_itunes

-- rate those songs
on newRating(old, direction)
	-- if there's no matching rule, we just return the old rating
	set new to old
	-- upgrading the rating
	if direction is nrUp then
		-- unrated songs go directly to 2 stars
		if old < 20 then set new to 40
		-- It takes two plays to go from 1 to 2 stars
		if old > 19 and old < 29 then set new to 29
		if old > 28 and old < 40 then set new to 40
		-- It takes 3 plays to go from 2 to 3 stars
		if old > 39 and old < 43 then set new to 43
		if old > 42 and old < 49 then set new to 49
		if old > 48 and old < 60 then set new to 60
		-- It takes 4 plays to go from 3 to 4 stars
		if old > 59 and old < 62 then set new to 62
		if old > 61 and old < 64 then set new to 64
		if old > 63 and old < 69 then set new to 69
		if old > 68 and old < 80 then set new to 80
		-- It takes 5 plays to go from 4 to 5 stars
		if old > 79 and old < 82 then set new to 82
		if old > 81 and old < 84 then set new to 84
		if old > 83 and old < 86 then set new to 86
		if old > 85 and old < 89 then set new to 89
		if old > 88 and old < 100 then set new to 100
	else
		-- downgrading a song
		
		-- If we hate an unrated song, it still gets one point
		-- That removes it from "@@0 Stars@@", freeing up
		-- space for a new song. If we downgrade it again, 
		-- it'll be out of sight.
		if old < 20 then set new to 20
		-- It takes one skip to go from 1 to 0 stars
		-- for all other ratings, it takes 2 skips to go
		-- down one star.
		if old > 19 and old < 29 then set new to 0
		if old > 28 and old < 40 then set new to 20
		if old > 39 and old < 49 then set new to 29
		if old > 48 and old < 60 then set new to 40
		if old > 59 and old < 69 then set new to 49
		if old > 68 and old < 80 then set new to 60
		if old > 79 and old < 89 then set new to 69
		if old > 88 and old < 100 then set new to 80
		if old is 100 then set new to 89
		
	end if
	return new
end newRating

on running_apps()
	tell application "System Events"
		return (get name of every process)
	end tell
end running_apps

on quit
	set ok_to_Idle to false
	continue quit
end quit