#!/usr/bin/env python

import cmd
import os
import pipes
import posixpath
import fnmatch
import urllib2
from datetime import datetime
from gzip import GzipFile
import logging
import re
from lxml import html
import urllib
from fnmatch import fnmatch
import time
logging.basicConfig(level=logging.INFO)

from collections import defaultdict

class FileInfo(object):
    def __init__(self, data):
        tmp = data.strip().split('@')

    def __init__(self, title, filename, readme, size, date):
        self.title = title
        self.filename = filename
        self.readme = readme
        self.size = int(size)
        self.date = date
        self.desc = ""
    
    def pretty_size(self):
        if   self.size > 99000000:
            tmp = "%.0fM" % (self.size / 1000000.0)
        elif self.size > 999999:
            tmp = "%.1fM" % (self.size / 1000000.0)
        elif self.size > 99000:
            tmp = "%.0fK" % (self.size / 1000.0)
        elif self.size > 999:
            tmp = "%.1fK" % (self.size / 1000.0)
        else:
            tmp = "%dB" % (self.size)
        return tmp.rjust(5, ' ')

    def pretty_filename(self, pad):
        return self.filename.ljust(min(pad,len(self.filename)+1), ' ').ljust(pad, '.')

    def info(self, pad=16):
        return ' '.join([
            self.pretty_filename(pad),
            self.pretty_size(),
            self.date,
            self.desc
        ])



class WHD(cmd.Cmd):
    intro = 'Welcome to Python WHDLoad Slave Download Tool.\n'

    cached = os.path.expanduser("~")+'/.pywhd/'
    slaveBaseUrl = "http://whdload.de/games/"

    def __init__(self):
        if not os.path.exists(WHD.cached):
            logging.debug('Make directory: ' + WHD.cached)
            os.makedirs(WHD.cached)
        self.db = defaultdict(lambda: defaultdict(lambda: defaultdict(FileInfo)))
        self.load_db()
        cmd.Cmd.__init__(self)
        self.cwd = ''
        self.update_prompt()
        ttyname = os.ttyname(0)
        if 'ttyUSB' in ttyname or 'ttyS' in ttyname or 'ttyAMA' in ttyname:
            self.sz = True
            print 'Detected serial terminal. Will transfer downloaded files using zmodem.'
        else:
            self.sz = False

    def update_prompt(self):
        self.prompt = 'WHDLoad:' + self.cwd + '> '

    def get_file(self, filename, force=False):
        if force or not os.path.exists(WHD.cached+filename):
            if not os.path.exists(WHD.cached+os.path.dirname(filename)):
                logging.debug('Make directory: ' + WHD.cached+os.path.dirname(filename))
                os.makedirs(WHD.cached+os.path.dirname(filename))
            logging.debug('Download file: ' + WHD.slaveBaseUrl+filename)
            response = urllib2.urlopen(WHD.slaveBaseUrl+filename)
            file(WHD.cached+filename, 'wb').write(response.read())

    def load_db(self, force=False):
        self.get_file('all.html', force)
        local = open(WHD.cached+'all.html')
        tree = html.parse(local)

        for gameRow in tree.xpath("body/center/table/tr")[1::]:
            title = gameRow.getchildren()[0].getchildren()[0].text
            filename = gameRow.getchildren()[0].getchildren()[0].values()[0]
            readme = gameRow.getchildren()[1].getchildren()[0].values()[0]
            size = gameRow.getchildren()[2].text
            date = gameRow.getchildren()[3].text
            f = FileInfo(title, filename, readme, size, date)
            self.db[f.filename] = f

        print ('Database loaded.')

    def file_exists(self, filename):
        return filename in self.db

    # Commands

    def do_exit(self, s):
        'Exit Python WHDLoad Slave Download Tool.'
        return True

    do_quit = do_exit
    do_EOF = do_exit

    def emptyline(self):
        pass

    def do_update(self, arg):
        'Update WHDLoad Slave database.'
        self.load_db(force=True)

    def do_ls(self, arg):
        pattern = arg
        if arg == "":
            pattern = "*"

        for filename in sorted(self.db.keys()):
            if fnmatch(filename, pattern):
                print self.db[filename].info(28)

        
    def do_get(self, arg):
        'Download file(s).'
        if arg == '':
            return
        pattern = arg
        match = False
        for filename in sorted(self.db.keys()):
            if fnmatch(filename, pattern):
                match = True
                self.get_file(filename)
                if self.sz:
                    os.system('sz '+pipes.quote(WHD.cached+filename))
                    time.sleep(2)

        if match and self.sz:
            print
        if not match:
            print ('No such file.')

    def do_search(self, arg):
        'Search using case insensitive regexp'
        pattern = re.compile(arg, re.IGNORECASE)
        for fileInfo in self.db.itervalues():
            if pattern.search(fileInfo.title) or pattern.search(fileInfo.filename):
                print fileInfo.info(28)

    def do_readme(self, arg):
        if arg in self.db:
            fileInfo = self.db[arg]
            self.get_file(fileInfo.readme)
            local = open(WHD.cached + fileInfo.readme)
            readmeTree = html.parse(local)
        
            for text in readmeTree.xpath("body/center/table/tr/td/pre")[0].itertext(): 
                print text,
            print
        else:
            print ('No such file.')

if __name__=='__main__':
    WHD().cmdloop()
