# -*- coding: utf-8 -*-

""" MapList -- ListWidget controller classes that display information

    Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
"""

import os

from urllib import urlopen

from PyQt4 import Qt
from PyQt4 import QtGui


class MapListItem( QtGui.QListWidgetItem ):
	""" Base class for an Item in a map list widget. """
	
	def __init__( self, parent, map_name, map_exts ):
		QtGui.QListWidgetItem.__init__( self, map_name, parent )
		
		self.map_name = map_name
		self.map_exts = map_exts
		self.setFlags( Qt.Qt.ItemIsSelectable | Qt.Qt.ItemIsUserCheckable | Qt.Qt.ItemIsEnabled )
		self.uncheck()
	
	checked = property(
		lambda self: self.checkState() == Qt.Qt.Checked,
		doc="True if this item has been selected by the user."
		)
	
	def check( self ):
		""" Set the check state of this item to Checked. """
		self.setCheckState( Qt.Qt.Checked )
	
	def uncheck( self ):
		""" Set the check state of this item to Unchecked. """
		self.setCheckState( Qt.Qt.Unchecked )


class BaseMapList( object ):
	""" Base class for a Map list widget controller. """
	
	def __init__( self, widget ):
		object.__init__( self )
		self.widget = widget
		self.widget.setSortingEnabled( True )
	
	def get_map_item( self, mapname ):
		""" Get the map item for the map with the given name. """
		items = self.widget.findItems( mapname, Qt.Qt.MatchExactly )
		if not items:
			return None
		if len(items) == 1:
			return items[0]
		else:
			raise ValueError( "Found multiple maps." )
	
	def mark_missing( self, other_list ):
		""" Mark entries for maps that are missing in other_list by setting the
		    background color to light gray.
		"""
		for i in range( self.widget.count() ):
			item = self.widget.item(i)
			if not other_list.has_map( item.text() ):
				item.setBackgroundColor( Qt.Qt.lightGray )
	
	def has_map( self, map_name ):
		""" Check if the given map exists in my list. """
		for i in range( self.widget.count() ):
			item = self.widget.item(i)
			if item and item.map_name == map_name:
				return True
		
		return False
	
	def choose_missing( self, other_list ):
		""" Set CheckState for entries for maps that are missing in other_list to Checked. """
		for i in range( self.widget.count() ):
			item = self.widget.item(i)
			if not other_list.has_map( item.text() ):
				item.check()


class ClientMapList( BaseMapList ):
	""" Map list widget controller that operates on the local file system. """
	
	def fetch( self, basedir ):
		""" Populate the list by finding map files in the given directory. """
		
		while self.widget.takeItem( 0 ):
			pass
		
		fileslist = dict()
		
		for thisfile in os.listdir( basedir ):
			if not os.path.isfile( "%s/%s" % ( basedir, thisfile ) ):
				continue
			
			base, ext = thisfile.split( '.', 1 )
			
			if base not in fileslist:
				fileslist[base] = [ext]
			else:
				fileslist[base].append( ext )
		
		for mapname in fileslist:
			if "bsp" in fileslist[mapname]:
				self.widget.addItem( MapListItem( self.widget, mapname, fileslist[mapname] ) )


class ServerMapList( BaseMapList ):
	""" Map list widget controller that queries the server. """
	
	def fetch( self, baseurl ):
		""" Populate the list by querying the server for existing maps. """
		
		while self.widget.takeItem( 0 ):
			pass
		
		# Fetch the baseURL - it returns somthing like this:
		# dm_lockdown: bsp
		# dm_underpass: bsp bsp.bz2
		# dm_resistance: bsp
		
		index = urlopen( baseurl ).fp
		
		while True:
			line = index.readline()
			if not line:
				break
			
			map_name, map_exts_string = line.strip().split( ':', 1 )
			map_exts = map_exts_string.strip().split( ' ' )
			
			self.widget.addItem( MapListItem( self.widget, map_name, map_exts ) )


