#!/usr/bin/env python

# -*- coding: UTF-8 -*-

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#                                                                         #
#  Copyright (C) 2015-2016 Simon Stuerz <simon.stuerz@guh.guru>           #
#  Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net>           #
#                                                                         #
#  This file is part of guh.                                              #
#                                                                         #
#  guh is free software: you can redistribute it and/or modify            #
#  it under the terms of the GNU General Public License as published by   #
#  the Free Software Foundation, version 2 of the License.                #
#                                                                         #
#  guh 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 General Public License for more details.                           #
#                                                                         #
#  You should have received a copy of the GNU General Public License      #
#  along with guh. If not, see <http://www.gnu.org/licenses/>.            #
#                                                                         #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

import argparse
import traceback
import json
import os
import subprocess 

__version__="1.0.0"

# Argument parser
parser = argparse.ArgumentParser(description='The guh-generateplugininfo is a precompiler for building plugins. This precompiler will create a plugininfo.h containing the uuid definitions from the plugin json file and creates the translations for the plugin.')
parser.add_argument('-j', '--jsonfile', help='The JSON input file name with the plugin description', metavar='jsonfile')
parser.add_argument('-b', '--builddir', help='The path to the build directory of the plugin where the plugininfo.h file can be found.', metavar='buildpath')
parser.add_argument('-o', '--output', help='The plugininfo.h outputFile with the uuid declarations', metavar='output')
parser.add_argument('-t', '--translations', help='The translation files for the plugin.', nargs='*', type=str, metavar='*.ts')
parser.add_argument('-v', '--version', action='version', version=__version__)
args = parser.parse_args()

# Get the source directors
sourceDir = os.path.dirname(os.path.abspath(args.jsonfile))

print "Json file: %s" % args.jsonfile
print "Output: %s/%s" % (args.builddir, args.output)
print "Build directory: %s" % args.builddir
print "Source directory: %s" % sourceDir
print "Translations: %s" % args.translations

# Tuple ('string to translate', 'comment for translater')
translationStrings = []

variableNames = []
externDefinitions = []


# Open files
inputFile = open(args.jsonfile, "r")
outputFile = open(args.builddir + "/" + args.output, "w")
outputFileExtern = open(args.builddir + "/" + "extern-" + args.output, "w")

# Read json file 
try:
    pluginMap = json.loads(inputFile.read())
    inputFile.close()
except ValueError as error:
    print " --> Error loading input file \"%s\"" % (args.input)
    print "     %s" % (error)
    inputFile.close()
    exit -1

##################################################################################################################
# Methods

def writePluginInfo(line):
    outputFile.write("%s\n" % line)

def writeExternPluginInfo(line):
    outputFileExtern.write("%s\n" % line)

def extractVendors(pluginMap):
    for vendor in pluginMap['vendors']:
        try:
            print("define VendorId %sVendorId = %s" % (pluginMap["idName"], vendor["id"]))
            writePluginInfo("VendorId %sVendorId = VendorId(\"%s\");" % (vendor["idName"], vendor["id"]))
            addTranslationString(vendor['name'], 'The name of the vendor (%s)' % vendor['id'])
            createExternDefinition("VendorId", "%sVendorId" % (vendor["idName"]))
        except:
            pass
        extractDeviceClasses(vendor)


def extractDeviceClasses(vendorMap):
    for deviceClass in vendorMap["deviceClasses"]:
        try:
            variableName = "%sDeviceClassId" % (deviceClass['idName'])
            addTranslationString(deviceClass['name'], 'The name of the deviceClass')
            if 'pairingInfo' in deviceClass:
                addTranslationString(deviceClass['pairingInfo'], 'The pairing info of deviceClass %s' % deviceClass['name'])
            
            if not variableName in variableNames:
                variableNames.append(variableName)
                print('define DeviceClassId %s = %s' % (variableName, deviceClass['deviceClassId']))
                writePluginInfo('DeviceClassId %s = DeviceClassId(\"%s\");' % (variableName, deviceClass['deviceClassId']))
                createExternDefinition('DeviceClassId', variableName)
            else:
                print("duplicated variable name \"%s\" for DeviceClassId %s -> skipping") % (variableName, deviceClass['deviceClassId'])
        except:
            pass
        extractActionTypes(deviceClass)
        extractStateTypes(deviceClass)
        extractEventTypes(deviceClass)


def extractStateTypes(deviceClassMap):
    try:
        for stateType in deviceClassMap['stateTypes']:
            try:
                variableName = "%sStateTypeId" % (stateType["idName"])
                addTranslationString(stateType['name'], 'The name of the stateType (%s) of deviceClass %s' % (stateType["id"], deviceClassMap['name']))
                if not variableName in variableNames:
                    variableNames.append(variableName)
                    print("define StateTypeId %s = %s" % (variableName, stateType["id"]))
                    writePluginInfo("StateTypeId %s = StateTypeId(\"%s\");" % (variableName, stateType["id"]))
                    createExternDefinition("StateTypeId", variableName)
                else:
                    print("duplicated variable name \"%s\" for StateTypeId %s -> skipping") % (variableName, stateType["id"])
                
                # create ActionTypeId if the state is writable
                if 'writable' in stateType:
                    if stateType['writable']:
                        vName = "%sActionTypeId" % (stateType["idName"]) 
                        if not vName in variableNames:
                            variableNames.append(vName)
                            print("define ActionTypeId %s for writable StateType %s = %s" % (vName, variableName, stateType["id"]))
                            writePluginInfo("ActionTypeId %s = ActionTypeId(\"%s\");" % (vName, stateType["id"]))
                            createExternDefinition("ActionTypeId", vName)
                        else:
                            print("duplicated variable name \"%s\" for ActionTypeId %s -> skipping") % (variableName, stateType["id"])
            except:
                pass
    except:
        pass


def extractActionTypes(deviceClassMap):
    try:
        for actionType in deviceClassMap["actionTypes"]:
            try:
                variableName = "%sActionTypeId" % (actionType["idName"])
                addTranslationString(actionType["name"], 'The name of the ActionType %s of deviceClass %s' % (actionType["id"], deviceClassMap['name']))
                if not variableName in variableNames:
                    variableNames.append(variableName)
                    writePluginInfo("ActionTypeId %s = ActionTypeId(\"%s\");" % (variableName, actionType["id"]))
                    createExternDefinition("ActionTypeId", variableName)
                else:
                    print("duplicated variable name \"%s\" for ActionTypeId %s -> skipping") % (variableName, actionType["id"])
            except:
                pass
    except:
        pass


def extractEventTypes(deviceClassMap):
    try:
        for eventType in deviceClassMap["eventTypes"]:
            try:
                variableName = "%sEventTypeId" % (eventType["idName"])
                addTranslationString(eventType["name"], 'The name of the EventType %s of deviceClass %s' % (eventType["id"], deviceClassMap['name']))
                if not variableName in variableNames:
                    variableNames.append(variableName)
                    writePluginInfo("EventTypeId %s = EventTypeId(\"%s\");" % (variableName, eventType["id"]))
                    createExternDefinition("EventTypeId", variableName)                    
                else:
                    print("duplicated variable name \"%s\" for EventTypeId %s -> skipping") % (variableName, eventType["id"])
            except:
                pass
    except:
        pass


def createExternDefinition(type, name):
    definition = {}
    definition['type'] = type
    definition['variable'] = name
    externDefinitions.append(definition)


def addTranslationString(string, comment):
    translationStrings.append([string, comment])
    #translationStrings.append([unicode(string, "utf-8"), unicode(comment, "utf-8")])

def writeTranslationStrings():
    if len(args.translations) is 0:
        return

    if len(translationStrings) is not 0:
        writePluginInfo("// Translation strings")
        writePluginInfo("const QString translations[] {")

        for index, value in enumerate(translationStrings):
            writePluginInfo("    //: %s" % value[1])
            if index != len(translationStrings) - 1:
                writePluginInfo("    QT_TRANSLATE_NOOP(\"%s\", \"%s\"), \n" % (pluginMap["idName"], value[0]))
            else:
                writePluginInfo("    QT_TRANSLATE_NOOP(\"%s\", \"%s\")" % (pluginMap["idName"], value[0]))

        writePluginInfo("};")
    

def createTranslationFiles():
    for translation in args.translations:
        translationFile = (sourceDir + "/" + translation)
        path, fileName = os.path.split(translationFile)
        translationOutput = (path + "/" + pluginMap['id'] + '-' + os.path.splitext(fileName)[0] + '.qm')
        print(" --> Translation update %s" % translationFile)
        print(subprocess.check_output(['lupdate', '-recursive', '-no-obsolete', sourceDir, (args.builddir + "/" + args.output), '-ts', translationFile]))
        print(" --> Translation release %s" % translationOutput)
        print(subprocess.check_output(['lrelease', translationFile, '-qm', translationOutput]))
        print(" --> Copy translation files to build dir %s" % args.builddir + '/translations/')
        subprocess.check_output(['rsync', '-a', translationOutput, args.builddir + '/translations/'])


##################################################################################################################
# write plugininfo.h

print " --> generate plugininfo.h for plugin \"%s\" = %s" % (pluginMap['name'], pluginMap['id'])
    
writePluginInfo("/* This file is generated by the guh build system. Any changes to this file will")
writePluginInfo(" * be lost.")
writePluginInfo(" *")
writePluginInfo(" * If you want to change this file, edit the plugin's json file.")
writePluginInfo(" */")
writePluginInfo("")
writePluginInfo("#ifndef PLUGININFO_H")
writePluginInfo("#define PLUGININFO_H")
writePluginInfo("")
writePluginInfo("#include <QLoggingCategory>")
writePluginInfo("#include <QObject>")
writePluginInfo("")
writePluginInfo("#include \"typeutils.h\"")
writePluginInfo("")
writePluginInfo("// Id definitions")
writePluginInfo("PluginId pluginId = PluginId(\"%s\");" % pluginMap['id'])

extractVendors(pluginMap)

writePluginInfo("")
writePluginInfo("// Logging category")

if 'idName' in pluginMap:
    writePluginInfo('Q_DECLARE_LOGGING_CATEGORY(dc%s)' % pluginMap['idName'])
    writePluginInfo('Q_LOGGING_CATEGORY(dc%s, \"%s\")' % (pluginMap['idName'], pluginMap['idName']))
    print 'define logging category: \"dc%s\"' % pluginMap['idName']
    
writePluginInfo("")

# Write translation strings
writeTranslationStrings()

writePluginInfo("")
writePluginInfo("#endif // PLUGININFO_H")
outputFile.close()
print " --> generated successfully \"%s\"" % (args.output)

##################################################################################################################
# Write extern-plugininfo.h 

print " --> generate extern-plugininfo.h for plugin \"%s\" = %s" % (pluginMap['name'], pluginMap['id'])

writeExternPluginInfo("/* This file is generated by the guh build system. Any changes to this file will")
writeExternPluginInfo(" * be lost.")
writeExternPluginInfo(" *")
writeExternPluginInfo(" * If you want to change this file, edit the plugin's json file and add")
writeExternPluginInfo(" * idName tags where appropriate.")
writeExternPluginInfo(" */")
writeExternPluginInfo("")
writeExternPluginInfo("#ifndef EXTERNPLUGININFO_H")
writeExternPluginInfo("#define EXTERNPLUGININFO_H")
writeExternPluginInfo("#include \"typeutils.h\"")
writeExternPluginInfo("#include <QLoggingCategory>")
writeExternPluginInfo("")
writeExternPluginInfo("// Id definitions")

for externDefinition in externDefinitions:
    writeExternPluginInfo("extern %s %s;" % (externDefinition['type'], externDefinition['variable']))

writeExternPluginInfo("")
writeExternPluginInfo("// Logging category definition")

if 'idName' in pluginMap:
    writeExternPluginInfo("Q_DECLARE_LOGGING_CATEGORY(dc%s)" % pluginMap['idName'])
    
writeExternPluginInfo("")
writeExternPluginInfo("#endif // EXTERNPLUGININFO_H")
outputFileExtern.close()
print " --> generated successfully \"extern-%s\"" % (args.output)

##################################################################################################################
# Translate
if len(translationStrings) is not 0:
    createTranslationFiles()



