#!/usr/bin/env python
# WURFL 2 Python - Wireless Universal Resource File to Python conversion utility
# Copyright (C) 2004-2008 Armand Lynch
#
# This library is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Armand Lynch <lyncha@users.sourceforge.net>

__doc__ = \
"""
WURFL <wurfl.sourceforge.net> conversion utility

usage: wurfl2python.py [options] WURFL_XML_FILE
"""

import sys
from time import ctime

from pywurfl.wurflprocessor import DeviceHandler, WurflProcessor, op, main


__version__ = "4.3.0a"
__license__ = "LGPL"
__copyright__ = "Copyright 2004-2008, Armand Lynch"
__author__ = "Armand Lynch <lyncha@users.sourceforge.net>"
__contributors__ = "Pau Aliagas <pau@newtral.org>"
__url__ = "http://celljam.net/"
__all__ = ['DeviceSerializer']


class DeviceSerializer(DeviceHandler):

    idstr = "devices.devids['''%s'''] = "
    new_caps = idstr + "devclass(%s, '''%s''', '''%s''', %s, {%s})\n"
    no_caps = idstr + "devclass(%s, '''%s''', '''%s''', %s, None)\n"
    capability_types = {}

    def __str__(self):
        s = []
        c = []

        if self.parent == "root":
            parent = "None"
        else:
            parent = "devices.devids['''%s''']" % self.parent

        for cap in sorted(self.capabilities):
            value = self.capabilities[cap]
            cap_type = self.capability_types.get(cap, None)
            if cap_type == int:
                c.append("'''%s''':%d" % (cap, int(value.strip())))
            elif cap_type == float:
                c.append("'''%s''':%f" % (cap, float(value.strip())))
            elif cap_type == bool:
                if value.lower() == "true":
                    c.append("'''%s''':True" % cap)
                elif value.lower() == "false":
                    c.append("'''%s''':False" % cap)
            else:
                c.append("'''%s''':'''%s'''" % (cap, value))

        if c:
            s.append(self.new_caps % (self.devid, parent, self.devid,
                                      self.devua, self.actual_device_root,
                                      ','.join(c)))
        else:
            s.append(self.no_caps % (self.devid, parent, self.devid, self.devua,
                                     self.actual_device_root))

        return ''.join(s)


class WurflPythonWriter(WurflProcessor):

    def __init__(self, wurflxml, device_handler=None,
                 options={"outfile":"wurfl.py"}):
        WurflProcessor.__init__(self, wurflxml, device_handler=device_handler,
                                options=options)
        self.groups = {}

    def handle_device(self, devobj):
        self.outfile.write(str(devobj))

    def process_options(self):
        if self.logfile != sys.stderr:
            self.logfile = file(self.logfile, "wb")
        if self.outfile is not None:
            self.outfile = file(self.outfile, "wb")
        else:
            self.outfile = file("wurfl.py", "wb")

    def process_capability(self, devobj, group, capability):
        attrs = capability.attrib
        devobj.capabilities[attrs["name"]] = attrs["value"]
        if devobj.devid == 'generic':
            try:
                self.groups[group.get('id')].append(attrs["name"])
            except KeyError:
                self.groups[group.get('id')] = []
                self.groups[group.get('id')].append(attrs["name"])

    def start_process(self):
        self.device_handler.capability_types = get_normalized_types(self.tree)

        version = self.tree.findtext("*/ver").strip()
        self.outfile.write('"""\n%s\n\n' % self.outfile.name)
        self.outfile.write("Generated on: %s\n" % ctime())
        self.outfile.write("Generated by: wurfl2python.py v%s\n" % __version__)
        self.outfile.write('"""\n\n')
        self.outfile.write("__all__ = ['devices', 'wurfl_version']\n")
        self.outfile.write("wurfl_version = '''%s'''\n\n" % version)
        self.outfile.write("from pywurfl import *\n\n")
        self.outfile.write("devices = Devices()\n")

    def end_process(self):
        for group, names in self.groups.iteritems():
            self.outfile.write("devices.devids['''generic'''].groups")
            self.outfile.write("['''%s'''] = ['''%s''']\n" % (group,
                                                           "''','''".join(names)))
        self.outfile.write("\n")
        self.outfile.write("for device in devices.devids.itervalues():\n")
        self.outfile.write("    devices.devuas[device.devua] = device\n")
        self.outfile.write("del device\n")
        self.outfile.write("\n")


def get_normalized_types(tree):
    caps = {}
    for capability in tree.findall("devices/device/group/capability"):
        name = capability.attrib['name']
        value = capability.attrib['value']
        if name not in caps:
            try:
                int(value)
                caps[name] = int
                continue
            except (TypeError, ValueError):
                pass
            try:
                float(value)
                caps[name] = float
                continue
            except (TypeError, ValueError):
                pass

            if value.strip().lower() in ("true", "false"):
                caps[name] = bool
                continue
            else:
                caps[name] = str
        else:
            if caps[name] == str:
                continue
            elif caps[name] == bool:
                if value.strip().lower() in ("true", "false"):
                    continue
                else:
                    caps[name] = str
            elif caps[name] == float:
                try:
                    float(value)
                    continue
                except (TypeError, ValueError):
                    caps[name] = str
            elif caps[name] == int:
                try:
                    int(value)
                    continue
                except (TypeError, ValueError):
                    caps[name] = str
    return caps


if __name__ == "__main__":
    op.add_option("-o", "--output", dest="outfile", default=None,
                  help="The name of the module to produce.")
    main(WurflPythonWriter, DeviceSerializer, op)
