#!/usr/bin/env python

import logging

from collections import defaultdict
from collections import OrderedDict
from errno import ENOENT
from stat import S_IFDIR, S_IFLNK, S_IFREG
from sys import argv, exit
from time import time

from fuse import FUSE, FuseOSError, Operations, LoggingMixIn, fuse_get_context

import re
from lxml import html
from urllib2 import urlopen

if not hasattr(__builtins__, 'bytes'):
	bytes = str

class Memory(LoggingMixIn, Operations):
	'WHDLoad slave filesystem'

	def __init__(self):
		self.files = OrderedDict()
		self.data = defaultdict(bytes)
		self.fd = 0
		self.now = time()
		self.maindirs = OrderedDict(
			apps = "apps/alla.html",
			demos = "demos/allv.html",
			games = "games/all.html",
			mags = "mags/alla.html",
			ctros = "ctros/alla.html")
        
		self.files['/'] = self.createDir()

		self.slaveBaseUrl = "http://whdload.de/"

		for directory, urlPart in self.maindirs.items():
			tree = html.parse(self.slaveBaseUrl + urlPart)
	
			for infoRow in tree.xpath("body/center/table/tr")[1::]:
				title = infoRow.getchildren()[0].getchildren()[0].text
				filename = infoRow.getchildren()[0].getchildren()[0].values()[0]
				readme = infoRow.getchildren()[1].getchildren()[0].values()[0]
				size = infoRow.getchildren()[2].text
				date = infoRow.getchildren()[3].text
				self.files['/' + directory + '/' + filename] = self.createFile(int(size))
				self.files['/' + directory + '/' + readme.rsplit(".", 1)[0] + ".readme"] = self.createFile(4096)
				self.files['/' + directory] = self.createDir()

	def createDir(self, timestamp = time()):
		uid, gid, pid = fuse_get_context()
		return dict(st_mode=(S_IFDIR | 0755),
			st_ctime = timestamp,
			st_mtime = timestamp,
			st_atime = timestamp,
			st_nlink = 2,
			st_uid = uid,
			st_gid = gid)

	def createFile(self, size = 0, timestamp = time(), permissions = 0644):
		uid, gid, pid = fuse_get_context()
		return dict(st_mode=(S_IFREG | permissions),
			st_ctime = timestamp,
			st_mtime = timestamp,
			st_atime = timestamp,
			st_nlink = 1,
			st_size = size,
			st_uid = uid,
			st_gid = gid,
			data = '')

	def getFile(self, path):
		return self.files.get(path)

	def chown(self, path, uid, gid):
		print "chown: " + path
		self.files[path]['st_uid'] = uid
		self.files[path]['st_gid'] = gid

	def create(self, path, mode):
		print "create: " + path
		self.files[path] = dict(st_mode=(S_IFREG | mode), st_nlink=1,
								st_size=0, st_ctime=time(), st_mtime=time(),
								st_atime=time())

		self.fd += 1
		print self.files
		print self.fd
		return self.fd

	def getattr(self, path, fh=None):
		stats = self.getFile(path)
		if stats:
			return stats
		else:
			raise FuseOSError(ENOENT)

	def getxattr(self, path, name, position=0):
		return ''

	def listxattr(srlf, path):
		print "listxattr: " + path
		attrs = self.files[path].get('attrs', {})
		return attrs.keys()

	def mkdir(self, path, mode):
		self.files[path] = dict(st_mode=(S_IFDIR | mode), st_nlink=2,
								st_size=0, st_ctime=time(), st_mtime=time(),
								st_atime=time())

		self.files['/']['st_nlink'] += 1

	def open(self, path, flags):
		self.fd += 1
		return self.fd

	def read(self, path, size, offset, fh):
		stats = self.getFile(path)
		data = stats['data']
		if not data:
			if path.endswith('.readme'):
				data = ""
				readmeTree = html.parse(self.slaveBaseUrl + path.rsplit(".", 1)[0] + ".html")
				for text in readmeTree.xpath("body/center/table/tr/td/pre")[0].itertext():
					data = data + text.encode('UTF-8')
				data = data + "\n"
			else:
				response = urlopen(self.slaveBaseUrl + path)
				data = response.read()
			
			stats['data'] = data

		return data[offset:offset + size]

	def readdir(self, path, fh):
		theList = []
		for filename in self.files:
			if not filename.endswith(".readme") and not path == filename and filename.startswith(path):
				splitString = path
				if not path == '/':
					splitString = path + '/'
				filenameRest = filename.split(splitString, 1)[-1]
				if not "/" in filenameRest:
					theList.append(filenameRest)

		return ['.', '..'] + theList


	def readlink(self, path):
		print "readlink: " + path
		return self.data[path]

	def removexattr(self, path, name):
		print "removexattr: " + path
		attrs = self.files[path].get('attrs', {})

		try:
			del attrs[name]
		except KeyError:
			pass		# Should return ENOATTR

	def rename(self, old, new):
		print "rename: " + path
		self.files[new] = self.files.pop(old)

	def rmdir(self, path):
		print "rmdir: " + path
		self.files.pop(path)
		self.files['/']['st_nlink'] -= 1

	def setxattr(self, path, name, value, options, position=0):
		print "setxattr: " + path
		# Ignore options
		attrs = self.files[path].setdefault('attrs', {})
		attrs[name] = value

	def statfs(self, path):
		print "statfs: " + path
		return dict(f_bsize=512, f_blocks=4096, f_bavail=2048)

	def symlink(self, target, source):
		print "symlink: " + path
		self.files[target] = dict(st_mode=(S_IFLNK | 0777), st_nlink=1,
								  st_size=len(source))

		self.data[target] = source

	def truncate(self, path, length, fh=None):
		print "truncate: " + path
		self.data[path] = self.data[path][:length]
		self.files[path]['st_size'] = length

	def unlink(self, path):
		print "unlink: " + path
		self.files.pop(path)

	def utimens(self, path, times=None):
		print "utimens: " + path
		now = time()
		atime, mtime = times if times else (now, now)
		self.files[path]['st_atime'] = atime
		self.files[path]['st_mtime'] = mtime

	def write(self, path, data, offset, fh):
		print "write: " + path
		self.data[path] = self.data[path][:offset] + data
		self.files[path]['st_size'] = len(self.data[path])
		return len(data)


if __name__ == '__main__':
	if len(argv) != 2:
		print('usage: %s <mountpoint>' % argv[0])
		exit(1)

	logging.getLogger().setLevel(logging.DEBUG)
	fuse = FUSE(Memory(), argv[1], foreground=True)
