#!/usr/bin/env python
# I, Danny Milosavljevic, hereby release this file into the public domain.    

import errno
import time
import os
import socket
import ssl
import zlib
import struct
import getpass
import hashlib
import exceptions
import base64
import webserver
import sys

class FileMetadata(object):
	def __init__(self, ID, is_directory, name, parent_inode, size, time, description, dummy_2, dummy_3, CRC, dummy_4, file_type, *args):
		self.ID = int(ID)
		self.B_directory = is_directory != "0"
		self.name = name
		self.parent_inode_ID = int(parent_inode)
		self.size = int(size)
		self.time = int(time)
		self.description = base64.decodestring(description) if description != "" else ""
		self.dummy_2 = int(dummy_2)
		self.dummy_3 = int(dummy_3) if dummy_3 != "" else None
		self.CRC = CRC
		self.dummy_4 = dummy_4
		self.file_type = file_type # "png"|"unknown".
		self.parent = None
		self.children = []

		#for name in dir(self):
		#	print name, getattr(self, name)

	def __repr__(self):
		d = self.__dict__.copy()
		del d["parent"]
		return "FileMetadata(%r)" % d

username = os.environ["USER"]
password_hash = hashlib.sha1()
password_hash.update(getpass.getpass("Password for user %r: " % username))

command_prefix = "%s\n%s\n" % (username, password_hash.hexdigest())

connection = None

def reconnect():
	global connection
	connection = socket.socket()
	connection.connect(("whiskey.megashares.com", 2939))
	connection = ssl.wrap_socket(connection)
	#connection.send(command_prefix + "refresh\n")
	return connection

file_list = None # global public

def receive_file_list():
	global file_list
	prefix = connection.recv(1)
	if prefix == "e": # error.
		print >>sys.stderr, "OOPS", "e" + connection.recv(1000) # FIXME.
		return

	data = connection.recv(100000)
	data = prefix + data
	assert(data.startswith("filelist\n"))
	#ilelist
	#2113	52
	command_response, number_response, data_response = data.split("\n", 2)
	expected_size = struct.unpack(">I", data_response[0 : 4])[0]
	file_list = zlib.decompress(data_response[4 : ])
	assert(len(file_list) == expected_size)
	file_list = [FileMetadata(*line.split("\t")) for line in file_list.split("\n") if line != ""]
	file_list = dict([(item.ID, item) for item in file_list])

	# root node:
	file_list[0] = FileMetadata("0", "1", "", "0", "0", "0", "", "0", "0", "CRC", "0", "unknown")

	for item in file_list.values():
		item.parent = file_list[item.parent_inode_ID]
		file_list[item.parent_inode_ID].children.append(item)

	file_list[0].parent = None
	file_list[0].children.remove(file_list[0])
	return file_list


def execute(command_args):
	s = "%s%s\n\n\n" % (command_prefix, "\n".join(command_args))
	#print s
	reconnect()
	global connection
	connection.send(s)

def update_file_list():
	global file_list
	execute(["refresh"])
	receive_file_list()

update_file_list()


#execute("ready")

def check_status():
	while True:
		status = connection.recv(4)
		if status != "":
			break

	if status == "done" or status == "read": # "done"|"ready"
		return status + connection.recv(1000)

	raise exceptions.Exception("bad bad status %r" % status) # FIXME

def makedir(parent_ID, name):
	execute(["makedir", "%d\t%s" % (parent_ID, name)])
	check_status()

def movedir(ID, new_parent_ID, new_name):
	execute(["movedir", "%d\t%d\t%s" % (ID, new_parent_ID, new_name)])
	check_status()

def movefile(ID, new_parent_ID, new_name):
	execute(["movefile", "%d\t%d\t%s" % (ID, new_parent_ID, new_name)])
	check_status()

def deldir(ID):
	execute(["deldir", "%d" % ID])
	check_status()

def delfile(ID):
	execute(["delfile", "%d" % ID])
	check_status()

def downloadfile(ID):
	execute(["downloadfile", "%d" % ID])
	response = check_status().split("\n")
	assert(response[0] == "ready")
	URL = response[1]
	return URL
	#port = int(response[1]) # port
	#return ("38.107.110.54", port) # FIXME

def uploadurl(parent_ID, URLs):
	execute(["uploadurl", "\t".join(["%d" % parent_ID] + URLs)])
	response = check_status().split("\n")
	print response

def uploadfile(input_file, name, mime_type, parent_path):
	# mime_type = "unknown" is OK.
	# parent_path = "foo/bar"
	checksum = hashlib.md5()
	old_position = input_file.tell()
	while True:
		data = input_file.read(16384)
		if data == "": # EOF
			break
		checksum.update(data)
	size = input_file.tell() - old_position
	input_file.seek(old_position)
	# TODO web server with that file on a port.
	#port = 7 # FIXME
	#MD5\t<name>\t<type>\t<dummy>\t<zero>\t<dummy>\t<size>\t<dummy>\n\n\n", len=133) at ssl/qsslso
	# FIXME: is parent_ID position OK?
	dummy_1 = ""
	dummy_2 = ""
	zero_1 = "0"
	execute(["uploadfile", "\t".join([checksum.hexdigest(), name, mime_type, dummy_1, zero_1, dummy_2, str(size), parent_path])])
	"""ready
	46576
	218
	None"""
	# whiskey.megashares.com

	response = check_status().split("\n")
	assert(response[0] == "ready")
	port = int(response[1])

	socket_1 = socket.socket()
	socket_1.connect(("whiskey.megashares.com", port))
	server = webserver.OneFileServer(input_file, socket_1)

	#, "ready", port])
	MD5_prefix = checksum.hexdigest()[ : 7]
	not_CRC = "0" # 2e125f0 # FIXME
	ID = 0 # ???
	# 2438490
	# 2438820 d41d8cd
	#connection.send("done\n%d %d" % (ID, MD5_prefix))

#f = File(2212885)
#print f.read(100, 0)

#host, port = downloadfile(2212885)
#import socket
#c = socket.socket()
#c.connect((host, port))
#c.send("GET file HTTP/1.1\x0D\x0AHost: %s:%d\x0D\x0AContent-Range: 0-*\x0D\x0Acontent-length: 0\x0D\x0A\x0D\x0A" % (host, port))
##c.send("GET file HTTP/1.1\x0D\x0AHost: whiskey.megashares.com\x0D\x0AContent-Range: 0-*\x0D\x0Acontent-length: 0\x0D\x0A\x0D\x0A")
#print c.recv(1000)

#uploadurl(0, ["http://www.scratchpost.org/patch/22-meta-mime.patch"])

#print file_list[0].children[0]

if __name__ == "__main__":
	import StringIO
	print uploadfile(StringIO.StringIO("foo"), "foo", "text/plain", "manga")