#!/usr/bin/env ruby

# vim:syn=ruby
#
# Copyright (c) 2006 Tilman Sauerbeck (tilman at code-monkey de)
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

require "gtk2"
require "xmmsclient"
require "xmmsclient_glib"
require "singleton"
require "pp"

PKG_NAME = "snett"
DATADIR = "/usr/local/share/#{PKG_NAME}/"
SIZE = 64

class Gtk::MenuItem
	def set_callback(meth, args = [])
		args.unshift(meth)

		signal_connect("activate") do
			Snett::Snett.instance.xmms.send(*args)
			false
		end
	end
end

class Xmms::Client
	def playback_next
		playlist_set_next_rel(1).notifier { playback_tickle }
	end

	def playback_prev
		playlist_set_next_rel(-1).notifier { playback_tickle }
	end
end

module Snett
	VERSION = "0.0.2"

	class Snett < Gtk::Window
		attr_reader :icon, :xmms

		include Singleton

		def initialize
			super(Gtk::Window::TOPLEVEL)

			@menu = nil
			@tooltips = Gtk::Tooltips.new

			@xmms = Xmms::Client.new(PKG_NAME)
			@xmms.connect(ENV["XMMS_PATH"])
			@xmms.add_to_glib_mainloop
			@xmms.on_disconnect { destroy }

			@broadcasts = []

			self.set_title(PKG_NAME)

			signal_connect("destroy") do
				@broadcasts.each { |bc| bc.disconnect }

				Gtk.main_quit
			end

			self.resizable = false
			self.decorated = false

			@icon = Gdk::Pixbuf.new(DATADIR + "logo#{SIZE}.png")

			self.resize(@icon.width, @icon.height)

			#self.colormap = self.screen.rgba_colormap

			pixmap, mask = @icon.render_pixmap_and_mask(self.colormap, 255)
			self.shape_combine_mask(mask, 0, 0)

			# load icon and put it in an eventbox
			event_box = Gtk::EventBox.new.add(Gtk::Image.new(@icon))
			event_box.events = Gdk::Event::BUTTON_PRESS_MASK |
			                   Gdk::Event::BUTTON_RELEASE_MASK

			event_box.signal_connect("button_press_event") do |_, event|
				if event.button == 1
					x, y = Gdk::Display.default.pointer[1, 2]
					self.begin_move_drag(event.button, x, y, event.time)
				elsif event.button == 3
					menu.popup(event)
				end

				false
			end

			@broadcasts << @xmms.broadcast_playback_current_id
			@broadcasts.last.notifier(&method(:on_playback_current_id))

			@xmms.playback_current_id.
			      notifier(&method(:on_playback_current_id))

			add(event_box)
		end

		private
		def menu
			@menu ||= Menu.new
		end

		def on_playback_current_id(res)
			return if res.value.zero?

			@xmms.medialib_get_info(res.value).
			      notifier(&method(:on_mlib_get_info))
		end

		def on_mlib_get_info(res)
			info = res.value[:server]

			s = "%s - %s" % [info[:artist], info[:title]]
			@tooltips.set_tip(self, s, nil)
		end
	end

	class Menu < Gtk::Menu
		def initialize
			super

			[
				[Gtk::Stock::MEDIA_PLAY, :playback_start],
				[Gtk::Stock::MEDIA_PAUSE, :playback_pause],
				[Gtk::Stock::MEDIA_STOP, :playback_stop]
			].each do |(stock, meth)|
				item = Gtk::ImageMenuItem.new(stock)
				item.set_callback(meth)

				append(item)
			end

			append(Gtk::SeparatorMenuItem.new)

			[
				[Gtk::Stock::MEDIA_NEXT, :playback_next],
				[Gtk::Stock::MEDIA_PREVIOUS, :playback_prev]
			].each do |(stock, meth)|
				item = Gtk::ImageMenuItem.new(stock)
				item.set_callback(meth)

				append(item)
			end

			append(Gtk::SeparatorMenuItem.new)

			[
				[Gtk::Stock::OPEN, "Load playlist...", :load],
				[Gtk::Stock::ADD, "Append playlist...", :append]
			].each do |(stock, text, sym)|
				item = Gtk::ImageMenuItem.new(text)
				item.image = Gtk::Image.new(stock, Gtk::IconSize::MENU)

				item.signal_connect("activate") do
					PlaylistDialog.new(sym).show_all
					false
				end

				append(item)
			end

			item = Gtk::ImageMenuItem.new(Gtk::Stock::CLEAR)
			item.set_callback(:playlist_clear)

			append(item)

			append(Gtk::SeparatorMenuItem.new)

			item = Gtk::ImageMenuItem.new(Gtk::Stock::ABOUT)
			item.signal_connect("activate") do
				props = {
					"name" => PKG_NAME,
					"version" => VERSION,
					"copyright" => "(c) 2006 Tilman Sauerbeck",
					"logo" => Gdk::Pixbuf.new(DATADIR + "logo128.png")
				}

				Gtk::AboutDialog.show(Snett.instance, props)
				false
			end

			append(item)

			item = Gtk::ImageMenuItem.new(Gtk::Stock::QUIT)
			item.signal_connect("activate") do
				Snett.instance.signal_emit("destroy")
				false
			end

			append(item)

			show_all
		end

		def popup(event)
			super(nil, nil, event.button, event.time)
		end
	end

	class PlaylistDialog < Gtk::Dialog
		def initialize(mode)
			super("Playlists", Snett.instance,
			      Gtk::Dialog::DESTROY_WITH_PARENT | Gtk::Dialog::MODAL,
			      [Gtk::Stock::OK, Gtk::Dialog::RESPONSE_ACCEPT],
				  [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_REJECT])

			@mode = mode

			signal_connect("response") do |_, id|
				on_ok if id == Gtk::Dialog::RESPONSE_ACCEPT
				destroy
			end

			@store = Gtk::ListStore.new(String)

			@view = Gtk::TreeView.new(@store)
			renderer = Gtk::CellRendererText.new

			col = Gtk::TreeViewColumn.new("Name", renderer, :text => 0)
			@view.append_column(col)

			scrolled = Gtk::ScrolledWindow.new
			scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
			scrolled.add(@view)

			vbox.add(scrolled)

			resize(350, 400)

			Snett.instance.xmms.medialib_playlists_list.
			                    notifier(&method(:on_playlists_list))
		end

		private
		def on_playlists_list(res)
			res.value.sort.each do |list|
				next if list[0, 1] == "_"

				@store.append[0] = list
			end
		end

		def on_ok
			selection = @view.selection
			iter = selection.selected
			return if iter.nil?

			Snett.instance.xmms.playlist_clear if @mode == :load
			Snett.instance.xmms.medialib_playlist_load(iter[0])
		end
	end
end

Gtk.init
Snett::Snett.instance.show_all
Gtk.main
