#! /usr/bin/env python3
# -*- Mode: python; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#

import argparse
import os
import os.path
import shutil
import re
import sys
import uuid
import json
import xml.etree.ElementTree as ET
import xml.dom.minidom as minidom
import traceback
import collections
import subprocess



class GbuildParser:
    def __init__(self, makecmd):
        self.makecmd = makecmd
        self.binpath = os.path.dirname(os.environ['GPERF']) # woha, this is quite a hack
        (self.srcdir, self.builddir, self.instdir, self.workdir) = (os.environ['SRCDIR'], os.environ['BUILDDIR'],
                                                                    os.environ['INSTDIR'], os.environ['WORKDIR'])
        self.modules = collections.OrderedDict()


    _includepattern = re.compile('-I(\S+)')
    _isystempattern = re.compile('-isystem\s*(\S+)')
    _warningpattern = re.compile('-W\S+')
    _buildpattern = {'Library': re.compile('Library_(.*)\.mk'),
                     'Executable': re.compile('Executable_(.*)\.mk'),
                     'CppunitTest': re.compile('CppunitTest_(.*)\.mk')}
    _allheaders=[]
    _jsonsrcdir=''
    def get_json_srcdir(self):
        return self._jsonsrcdir
    def __split_includes(json_srcdir,includes):
        foundisystem = GbuildParser._isystempattern.findall(includes)
        foundincludes=[]
        for includeswitch in GbuildParser._includepattern.findall(includes):
            if len(includeswitch) > 2:
                if includeswitch.strip()[:len(json_srcdir)] == json_srcdir:
                    foundincludes.append(includeswitch.strip()[len(json_srcdir)+1:])
                else:
                    foundincludes.append(includeswitch.strip())
        return (foundincludes, foundisystem)

    def __split_objs(module,objsline, ext):
        retObj = []
        for obj in objsline.strip().split(' '):
            if module in obj:
                obj = obj[len(module)+1:]
            if len(obj) > 0 and obj != 'CXXOBJECTS' and obj != '+=':
                retObj.append(obj + ext)
        return sorted(retObj)

    def __split_defs(defsline):
        defs = {}
        alldefs = [defswitch.strip() for defswitch in defsline.strip().lstrip('-D').split(' -D') if len(defswitch) > 2]
        for d in alldefs:
            defparts = d.split('=')
            if len(defparts) == 1:
                defparts.append(None)
            defs[defparts[0]] = defparts[1]
        defs["LIBO_INTERNAL_ONLY"] = None
        return defs

    def __split_flags(flagsline, flagslineappend):
        return [cxxflag.strip() for cxxflag in GbuildParser._warningpattern.sub('', '%s %s' % (flagsline, flagslineappend)).split(' ') if len(cxxflag) > 1]


    def parse(self):
        # current json blacklist, this is just for reference:
        #      bridges
        #      connectivity compilerplugins cli_ure cppu cppuhelper cpputools
        #      dictionaries
        #      extensions external
        #      helpcompiler helpcontent2
        #      i18npool icon-themes
        #      javaunohelper jurt
        #      lingucomponent
        #      odk
        #      sal scaddins shell solenv stoc
        #      tools translations
        #      udkapi unoid
        # Add handling of BLACKLIST

        # Relation between json object and file extension
        jsonSrc = {
                    'CXXOBJECTS': '.cxx', 'OBJCOBJECTS': '.m', 'OBJCXXOBJECTS': '.mm', 'COBJECTS': '.c',
                    'LEXOBJECTS': '.l',   'YACCOBJECTS': '.y',

                    'GENCXXOBJECTS': '.cxx', # remark is in workdir/GenCxxObject
                    'ASMOBJECTS': '.s',      #not in json, due to Blacklist ?
                    'GENCOBJECTS': '.c',     #not in json, due to Blacklist ?
                    'JAVAOBJECTS': '.java',  #not in json, due to Blacklist ?
                    'PYTHONOBJECTS': '.py'   #not in json, due to Blacklist ?
                  }


        moduleDict = {}
        self.find_all_headers()

        for jsontype in ['Library', 'Executable', 'CppunitTest']:
            for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', jsontype)):
                with open(os.path.join(self.workdir, 'GbuildToJson', jsontype, jsonfilename), 'r') as f:
                    jsondata = json.load(f)
                    match = GbuildParser._buildpattern[jsontype].match(os.path.basename(jsondata['MAKEFILE'])).group(1)
                    jsondata['location'] = os.path.dirname(jsondata['MAKEFILE'])
                    module = jsondata['location'].split('/')[-1]
                    json_srcdir=jsondata['location'][:-(len(module)+1)]
                    jsondata['MAKEFILE']=jsondata['MAKEFILE'][len(jsondata['location'])+1:]
                    jsondata['ILIBTARGET']='../' + jsondata['ILIBTARGET'][len(json_srcdir)+1:]

                    (jsondata['include'], jsondata['include_sys']) = GbuildParser.__split_includes(json_srcdir, jsondata['INCLUDE'])
                    jsondata['name'] = match
                    jsondata['build_type'] = jsontype
                    jsondata['target_name'] = module + '_' + jsontype + '_' + match
                    jsondata['DEFS'] = GbuildParser.__split_defs(jsondata['DEFS'])
                    jsondata['LINKED_LIBS'] = jsondata['LINKED_LIBS'].strip().split(' ')
                    jsondata['CXXFLAGS'] += ' -DLIBO_INTERNAL_ONLY'
                    for i in ['CXXFLAGS', 'CFLAGS', 'OBJCFLAGS', 'OBJCXXFLAGS']:
                        jsondata[i] = GbuildParser.__split_flags(jsondata[i], jsondata[i+'APPEND'])
                    for i in jsonSrc:
                        if not i in jsondata:
                            jsondata[i] = ''
                        jsondata[i] = GbuildParser.__split_objs(module, jsondata[i], jsonSrc[i])

                    if not module in moduleDict:
                        moduleDict[module] = {'targets': [],'headers':{}}
                    moduleDict[module]['targets'].append(jsondata)
                    moduleDict[module]['headers'] =self.headers_of(module)
        self._jsonsrcdir=json_srcdir
        moduleDict['include']={ 'targets': [], 'headers':self.headers_of('include')}

        for i in sorted(moduleDict):
            module = moduleDict[i]
            src = []
            for target in module['targets']:
                target['module'] = i
                for ext in jsonSrc:
                    src.extend(target[ext])
            module['sources'] = sorted(src)
            self.modules[i] = module
        return self



    def find_all_headers(self):

        cmdResult=subprocess.check_output(['git', 'ls-files','--','*.h','*.hxx', '*.hpp'], cwd=self.srcdir, stderr=subprocess.PIPE,)


        allfiles={}
        for file in cmdResult.splitlines():
            strfile=file.decode()
            modulename=strfile.split('/')[0]
            if not modulename in allfiles:
                allfiles[modulename]=[]
            modulename_len=len(modulename)
            allfiles[modulename].append(strfile[modulename_len + 1:])

        self._allheaders = allfiles

    def headers_of(self,modulename):
        if modulename in self._allheaders: #for the modules that not have headers
            headersof = self._allheaders[modulename]
        else:
            headersof=[]
        return headersof



class IdeIntegrationGenerator:

    def __init__(self, gbuildparser, ide):
        (self.gbuildparser, self.ide) = (gbuildparser, ide)

    def emit(self):
        pass



class testVS2013Ide(IdeIntegrationGenerator):

    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
        self.toolset = self.retrieve_toolset()
        self.solution_directory = './windows'
        self.configurations = {
            'Release': {
                'build': self.module_make_command('%(target)s'),
                'clean': self.module_make_command('%(target)s.clean'),
                'rebuild': self.module_make_command('%(target)s.clean %(target)s')
            },
            'Debug': {
                'build': self.module_make_command('unitcheck'),
                'clean': self.module_make_command('clean'),
                'rebuild': self.module_make_command('clean unitcheck'),
            }
        }
        srcdir=self.gbuildparser.get_json_srcdir()
        self.env_variables={
            'SRCDIR': srcdir,'BUILDDIR':os.path.dirname(srcdir),'INSTDIR':os.path.join(srcdir,'instdir'),'WORKDIR':os.path.join(srcdir,'workdir')
        }
    def tmp_json_env_var(self):
        pass

    def retrieve_toolset(self):
        return {'vs2013': 'v120', 'vs2015': 'v140', 'testIde':'v120'}.get(self.ide, None)

    def module_make_command(self, targets):
        return '%(sh)s -c "PATH=\\"/bin:$PATH\\";BUILDDIR=\\"%(builddir)s\\" %(makecmd)s -rsC %(location)s ' + targets + '"'

    class Project:

        def __init__(self, guid, target, project_path):
            self.guid = guid
            self.target = target
            self.path = project_path

    def emit(self):
        all_projects = []
        props_path=os.path.join(self.solution_directory,'PropertySheet.props')
        self.write_props(props_path)
        for module in self.gbuildparser.modules:
            projects = []
            module_directory = os.path.join(self.solution_directory, module)
            if module != 'include':  # FIXME
                project_path = os.path.join(module_directory, '%s.vcxproj' % module)
                project_guid = self.twrite_project(project_path, module)
                self.write_filters(project_path + '.filters', module, self.gbuildparser.modules[module]['headers'])
                for target in self.gbuildparser.modules[module]['targets']:
                    p = self.Project(project_guid, target, project_path)
                    projects.append(p)
                self.write_solution(os.path.join(module_directory, '%s.sln' % module), projects)
                all_projects += projects

        self.write_solution(os.path.join(self.solution_directory, 'LibreOffice.sln'), all_projects)

    nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'

    def get_dependency_libs(self, linked_libs, library_projects):
        dependency_libs = {}
        for linked_lib in linked_libs:
            for library_project in library_projects:
                if library_project.target['name'] == linked_lib:
                    dependency_libs[library_project.guid] = library_project
        return dependency_libs
    def write_props(self,props_path):
        ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
        ET.register_namespace('', ns)
        proj_node = ET.Element('{%s}Project' % ns, DefaultTargets='Build', ToolsVersion='4.0')
        imp_grp_node=ET.SubElement(proj_node,'{%s}ImportGroup' % ns, Label='PropertySheets')
        prop_grp_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='UserMacros')
        for key,value in self.env_variables.items():
            vsrcdir=ET.SubElement(prop_grp_node,key)
            vsrcdir.text=value
        prop_grp_node2 = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns)
        itm_def_node = ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)
        itm_grp = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
        for key, value in self.env_variables.items():
            build_macro_node = ET.SubElement(itm_grp, '{%s}BuildMacro' % ns, Include=key)
            value_node = ET.SubElement(build_macro_node, '{%s}Value' % ns)
            value_node.text='$(%s)' % key
        self.write_pretty_xml(proj_node,props_path)

    def write_solution(self, solution_path, projects):
        library_projects = [project for project in projects if project.target['build_type'] == 'Library']
        with open(solution_path, 'w') as f:
            f.write('Microsoft Visual Studio Solution File, Format Version 12.00\n')
            for project in projects:
                target = project.target
                proj_path = os.path.relpath(project.path, os.path.abspath(os.path.dirname(solution_path)))
                f.write('Project("{%s}") = "%s", "%s", "{%s}"\n' %
                        (VisualStudioIntegrationGenerator.nmake_project_guid,
                         target['target_name'], proj_path, project.guid))
                libs_in_solution = self.get_dependency_libs(target['LINKED_LIBS'], library_projects)
                if libs_in_solution:
                    f.write('\tProjectSection(ProjectDependencies) = postProject\n')
                    for lib_guid in libs_in_solution.keys():
                        f.write('\t\t{%(guid)s} = {%(guid)s}\n' % {'guid': lib_guid})
                    f.write('\tEndProjectSection\n')
                f.write('EndProject\n')
            f.write('Global\n')
            platform = 'Win32'
            f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
            for cfg in self.configurations:
                f.write('\t\t%(cfg)s|%(platform)s = %(cfg)s|%(platform)s\n' % {'cfg': cfg, 'platform': platform})
            f.write('\tEndGlobalSection\n')
            f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
            # Specifies project configurations for solution configuration
            for project in projects:
                for cfg in self.configurations:
                    params = {'guid': project.guid, 'sol_cfg': cfg, 'proj_cfg': cfg, 'platform': platform}
                    f.write(
                        '\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.ActiveCfg = %(proj_cfg)s|%(platform)s\n' % params)
                    # Build.0 is basically 'Build checkbox' in configuration manager
                    f.write(
                        '\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.Build.0 = %(proj_cfg)s|%(platform)s\n' % params)
            f.write('\tEndGlobalSection\n')
            f.write('EndGlobal\n')

    def write_project(self, project_path, target):
        # See info at http://blogs.msdn.com/b/visualstudio/archive/2010/05/14/a-guide-to-vcxproj-and-props-file-structure.aspx
        folder = os.path.dirname(project_path)
        if not os.path.exists(folder):
            os.makedirs(folder)
        project_guid = str(uuid.uuid4()).upper()
        ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
        ET.register_namespace('', ns)
        proj_node = ET.Element('{%s}Project' % ns, DefaultTargets='Build', ToolsVersion='4.0')
        proj_confs_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns, Label='ProjectConfigurations')
        platform = 'Win32'
        for configuration in self.configurations:
            proj_conf_node = ET.SubElement(proj_confs_node,
                                           '{%s}ProjectConfiguration' % ns,
                                           Include='%s|%s' % (configuration, platform))
            conf_node = ET.SubElement(proj_conf_node, '{%s}Configuration' % ns)
            conf_node.text = configuration
            platform_node = ET.SubElement(proj_conf_node, '{%s}Platform' % ns)
            platform_node.text = platform

        globals_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='Globals')
        proj_guid_node = ET.SubElement(globals_node, '{%s}ProjectGuid' % ns)
        proj_guid_node.text = '{%s}' % project_guid
        proj_keyword_node = ET.SubElement(globals_node, '{%s}Keyword' % ns)
        proj_keyword_node.text = 'MakeFileProj'
        proj_name_node = ET.SubElement(globals_node, '{%s}ProjectName' % ns)
        proj_name_node.text = target['target_name']

        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
        for configuration in self.configurations:
            conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label="Configuration",
                                      Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (
                                      configuration, platform))
            # Type of project used by the MSBuild to determine build process, see Microsoft.Makefile.targets
            conf_type_node = ET.SubElement(conf_node, '{%s}ConfigurationType' % ns)
            conf_type_node.text = 'Makefile'
            # VS2012: I need to have this otherwise the names of projects will contain text Visual Studio 2010 in the Solution Explorer
            platform_toolset_node = ET.SubElement(conf_node, '{%s}PlatformToolset' % ns)
            platform_toolset_node.text = self.toolset

        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.props')
        ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionSettings')
        for configuration in self.configurations:
            prop_sheets_node = ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='Configuration',
                                             Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (
                                             configuration, platform))
            ET.SubElement(prop_sheets_node, '{%s}Import' % ns,
                          Project='$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props',
                          Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')",
                          Label='LocalAppDataPlatform')

        ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='UserMacros')
        for cfg_name, cfg_targets in self.configurations.items():
            conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns,
                                      Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (cfg_name, platform))
            nmake_params = {
                'sh': os.path.join(self.gbuildparser.binpath, 'dash.exe'),
                'builddir': self.gbuildparser.builddir,
                'location': target['location'],
                'makecmd': self.gbuildparser.makecmd,
                'target': target['target_name']}
            nmake_build_node = ET.SubElement(conf_node, '{%s}NMakeBuildCommandLine' % ns)
            nmake_build_node.text = cfg_targets['build'] % nmake_params
            nmake_clean_node = ET.SubElement(conf_node, '{%s}NMakeCleanCommandLine' % ns)
            nmake_clean_node.text = cfg_targets['clean'] % nmake_params
            nmake_rebuild_node = ET.SubElement(conf_node, '{%s}NMakeReBuildCommandLine' % ns)
            nmake_rebuild_node.text = cfg_targets['rebuild'] % nmake_params
            nmake_output_node = ET.SubElement(conf_node, '{%s}NMakeOutput' % ns)
            nmake_output_node.text = os.path.join('../..', 'program', 'soffice.exe')
            nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % ns)
            nmake_defs_node.text = ';'.join(list(target['DEFS']) + ['$(NMakePreprocessorDefinitions)'])
            include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % ns)
            includes=[os.path.join('../..',elem) if elem[1] != ':'  else elem for elem in target['include'] ]
            include_path_node.text = ';'.join(includes + ['$(IncludePath)'])

        ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)

        cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
        for cxxobject in target['CXXOBJECTS']:
            cxxrelpath= os.path.join('../..',target['location'].split('/')[-1], cxxobject)
            cxxabspath = os.path.join(self.gbuildparser.srcdir,target['location'].split('/')[-1], cxxobject)
            cxxfile = cxxabspath
            if os.path.isfile(cxxfile):
                ET.SubElement(cxxobjects_node, '{%s}ClCompile' % ns, Include=cxxrelpath)
            else:
                print('Source %s in project %s does not exist' % (cxxfile, target['target_name']))

        includes_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
        for cxxobject in target['CXXOBJECTS']:
            include_rel_path = os.path.join('../..',target['location'].split('/')[-1], cxxobject)
            include_abs_path = os.path.join(self.gbuildparser.srcdir,target['location'].split('/')[-1], cxxobject)
            hxxfile = include_abs_path
            if os.path.isfile(hxxfile):
                ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=include_rel_path)
            # Few files have corresponding .h files
            hfile = include_abs_path
            if os.path.isfile(hfile):
                ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=include_rel_path)
        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
        ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionTargets')
        self.write_pretty_xml(proj_node, project_path)

        return project_guid


    def twrite_project(self, project_path, module):
        folder = os.path.dirname(project_path)
        if not os.path.exists(folder):
            os.makedirs(folder)
        project_guid = str(uuid.uuid4()).upper()
        ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
        ET.register_namespace('', ns)
        proj_node = ET.Element('{%s}Project' % ns, DefaultTargets='Build', ToolsVersion='4.0')

        proj_confs_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns, Label='ProjectConfigurations')
        platform='Win32'
        for configuration in self.configurations:
            proj_conf_node = ET.SubElement(proj_confs_node,
                                           '{%s}ProjectConfiguration' % ns,
                                           Include='%s|%s' % (configuration, platform))
            conf_node = ET.SubElement(proj_conf_node, '{%s}Configuration' % ns)
            conf_node.text = configuration
            platform_node = ET.SubElement(proj_conf_node, '{%s}Platform' % ns)
            platform_node.text = platform
        #globals
        globals_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='Globals')
        proj_guid_node = ET.SubElement(globals_node, '{%s}ProjectGuid' % ns)
        proj_guid_node.text = '{%s}' % project_guid
        proj_root_namespace=ET.SubElement(globals_node, '{%s}RootNamespace' % ns)
        proj_root_namespace.text = module


        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
        for configuration in self.configurations:
            property_group_node=ET.SubElement(proj_node,'{%s}PropertyGroup' % ns, Label="Configuration", Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration,platform))
            conf_type=ET.SubElement(property_group_node,'{%s}ConfigurationType' % ns)
            conf_type.text='Application'
            use_dbg_lib=ET.SubElement(property_group_node,'{%s}UseDebugLibraries' % ns)
            use_dbg_lib.text='true'
            platform_toolset_node = ET.SubElement(property_group_node, '{%s}PlatformToolset' % ns)
            platform_toolset_node.text = self.toolset
            char_set_node=ET.SubElement(property_group_node,'{%s}CharacterSet' %ns)
            char_set_node.text='MultiByte'
            #on debug there ist a whole programoptimization

        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.props')
        ET.SubElement(proj_node,'{%s}ImportGroup' % ns,Label='ExtensionSettings')
        for configuration in self.configurations:
            prop_sheets=ET.SubElement(proj_node,'{%s}ImportGroup' % ns, Label='PropertySheets',Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration,platform))
            ET.SubElement(prop_sheets,'{%s}Import' % ns,Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props",Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')",Label="LocalAppDataPlatform")
            ET.SubElement(prop_sheets, '{%s}Import' % ns, Project="../PropertySheet.props")
        ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='UserMacros')
        for configuration in self.configurations:
            item_def_group=ET.SubElement(proj_node,'{%s}ItemDefinitionGroup' % ns,Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration,platform))
            #compiler options
            cl_compile=ET.SubElement(item_def_group,'{%s}ClCompile' % ns)
            warn_lvl=ET.SubElement(cl_compile,'{%s}WarningLevel' % ns)
            warn_lvl.text='Level4'
            opt_node=ET.SubElement(cl_compile,'{%s}Optimization' % ns)
            opt_node.text='Disabled'
            sdl_check=ET.SubElement(cl_compile,'{%s}SDLCheck' % ns)
            sdl_check.text='true'
            for target in self.gbuildparser.modules[module]['targets']:
                add_incl_dir=ET.SubElement(cl_compile,'{%s}AdditionalIncludeDirectories' % ns)
                add_incl_dir.text=self.get_include_dirs(target)
                add_incl_def_flag=ET.SubElement(cl_compile,'{%s}AdditionalOptions' % ns)
                add_incl_def_flag.text=self.get_flags_defs(target)

            dgb_info_form=ET.SubElement(cl_compile,'{%s}DebugInformationFormat' % ns)
            dgb_info_form.text='ProgramDatabase'
            warn_as_error=ET.SubElement(cl_compile,'{%s}TreatWarningAsError' % ns)
            warn_as_error.text='true'
            run_libs=ET.SubElement(cl_compile,'{%s}RuntimeLibrary' % ns)
            run_libs.text='MultiThreadedDLL'

            #linker options
            #linker_node=ET.SubElement(item_def_group,'{%s}Link' % ns)

            #gen_dbg_info=ET.SubElement(linker_node,'{%s}GenerateDebugInformation}' % ns)
            #gen_dbg_info.text='true'
            #add_lib_dirs=ET.SubElement(linker_node,'{%s}AdditionalLibraryDirectories}' % ns)
            #libname=target['ILIBTARGET'].split('/')[-1]
            #libpath='../' + target['ILIBTARGET'][:-(len(libname)+1)]
            #add_lib_dirs.text= libpath
            #add_dep=ET.SubElement(linker_node,'{%s}AdditionalDependencies}' % ns)
            #add_dep.text= libname +';kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)'

            #proj_ref_node=ET.SubElement(item_def_group,'{%s}ProjectReference' % ns)
            #use_lib_dep=ET.SubElement(proj_ref_node,'{%s}UseLibraryDependencyInputs}' % ns)
            #use_lib_dep.text='true'

        #cxx files
        cxx_node=ET.SubElement(proj_node,'{%s}ItemGroup' % ns)
        for target in self.gbuildparser.modules[module]['targets']:
            for cxx_elem in target['CXXOBJECTS']:
                modulename=target['module']
                cxx_cl_node=ET.SubElement(cxx_node,'{%s}ClCompile' % ns,Include=os.path.join('../..', modulename, cxx_elem))
        #miss headers
        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
        ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionTargets')
        self.write_pretty_xml(proj_node, project_path)
        return project_guid

    def get_flags_defs(self,target):
        flags=' '.join(target['CXXFLAGS']).replace('-','/')
        mdefs=''
        for elem_defs,elem_value in target['DEFS'].items():
            mdefs += '/D' + elem_defs
            if elem_value != None:
                mdefs += '=' + elem_value
            mdefs += ' '
        return flags + ' ' + mdefs + '-arch:SSE -DEXCEPTIONS_ON -EHs -Od -FS -Zi -DLIBO_INTERNAL_ONLY -WX'

    def get_include_dirs(self,target):
        includes=''
        for elem in target['include']:
            if elem[1] == ':':
                tmp_inc=elem
            else:
                tmp_inc ='../../' + elem
            tmp_inc +=';'
            includes +=tmp_inc
        return includes[:-1]


    def write_pretty_xml(self, node, file_path):
        xml_str = ET.tostring(node, encoding='unicode')
        pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
        with open(file_path, 'w') as f:
            f.write(pretty_str.decode())

    def write_filters(self,filters_path,module,headers):
        ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
        ET.register_namespace('', ns)
        proj_node = ET.Element('{%s}Project' % ns, ToolsVersion='4.0')

        filters_node=ET.SubElement(proj_node,'{%s}ItemGroup' % ns)
        filters={'sources' : 'c;cxx;cpp','headers':'h;hxx;hpp'}
        for filter_key,filter_value in filters.items():
            filter_node = ET.SubElement(filters_node,'{%s}Filter' % ns, Include='%s' % filter_key)
            filter_id_node = ET.SubElement(filter_node,'{%s}UniqueIdentifier' % ns)
            filter_id_node.text='{%s}' % str(uuid.uuid4())
            filter_ext_node = ET.SubElement(filter_node,'{%s}Extensions' % ns)
            filter_ext_node.text = '{%s}' % filter_value
        sources_node=ET.SubElement(proj_node,'{%s}ItemGroup' % ns)
        for target in self.gbuildparser.modules[module]['targets']:
            for cxxfile in target['CXXOBJECTS']:
                cxx_file_name = cxxfile.split('/')[-1]
                clinclude_node=ET.SubElement(sources_node,'{%s}ClInclude' % ns, Include='%s' % cxx_file_name)
                header_filter=ET.SubElement(clinclude_node,'{%s}Filter' % ns)
                header_filter.text="sources"

        headers_node=ET.SubElement(proj_node,'{%s}ItemGroup' % ns)
        for header in headers:
            header_file_name=header.split('/')[-1]

            clinclude_node=ET.SubElement(headers_node,'{%s}ClInclude' % ns, Include='%s' % header_file_name)
            header_filter=ET.SubElement(clinclude_node,'{%s}Filter' % ns)
            header_filter.text="headers"

        self.write_pretty_xml(proj_node, filters_path)

class XcodeIntegrationGenerator(IdeIntegrationGenerator):
    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)

    typeCounter = {'PBXProject'           : 000000,
                   'PBXGroup'             : 100000,
                   'PBXFileReference'     : 200000,
                   'PBXNativeTarget'      : 300000,
                   'XCConfigurationList'  : 400000,
                   'PBXSourcesBuildPhase' : 500000,
                   'XCBuildConfiguration' : 600000,
                   'PBXBuildFile'         : 700000}

    def emit(self):
        mainGroupId, mainGroup = self.generate_PBXGroup(None)
        rootId = self.generate_id('PBXProject')
        self.rootObj = {'attributes': {'LastUpgradeCheck': '0820',
                                       'ORGANIZATIONNAME': 'LibreOffice',
                                       'TargetAttributes': {}},
                        'compatibilityVersion': 'Xcode 3.2',
                        'developmentRegion': 'English',
                        'isa': 'PBXProject',
                        'hasScannedForEncodings': 0,
                        'knownRegions': ['en'],
                        'mainGroup': mainGroupId,
                        'projectDirPath': self.gbuildparser.srcdir,
                        'projectRoot': '',
                        'buildConfigurationList': '',
                        'targets': []}
        pbxproj = {'archiveVersion': 1,
                   'classes': {},
                   'objectVersion': 46,
                   'objects': {rootId: self.rootObj,
                               mainGroupId: mainGroup},
                   'rootObject': rootId}
        for module in self.gbuildparser.modules:
            if module == 'include':
                continue
            moduleId, moduleObj = self.generate_PBXGroup(module)
            sourceId, sourceObj = self.generate_PBXGroup('Sources')
            includeId, includeObj = self.generate_PBXGroup('Headers')
            targetId, targetObj = self.generate_PBXGroup('Targets')

            moduleObj['children'] = [sourceId, includeId, targetId]
            pbxproj['objects'].update({sourceId:  sourceObj,
                                       includeId: includeObj,
                                       moduleId: moduleObj,
                                       targetId: targetObj})
            mainGroup['children'].append(moduleId)

            for i in self.gbuildparser.modules[module]['headers']:
                ref = self.generate_id('PBXFileReference')
                pbxproj['objects'][ref] = self.generate_PBXFileReference(module, i)
                includeObj['children'].append(ref)
            for i in self.gbuildparser.modules[module]['sources']:
                ref = self.generate_id('PBXFileReference')
                pbxproj['objects'][ref] = self.generate_PBXFileReference(module, i)
                sourceObj['children'].append(ref)
            for target in self.gbuildparser.modules[module]['targets']:
                pbxproj['objects'].update(self.generate_target(target, module, targetObj, sourceObj['children']))

        xcodeprojdir = './osx/libreoffice.xcodeproj'
        try:
            os.mkdir(xcodeprojdir)
        except:
            pass
        with open(os.path.join(xcodeprojdir, 'project.pbxproj'), 'w') as f:
            f.write('// !$*UTF8*$!\n')
            self.write_object(pbxproj, f, 0)

    def indent(self, file, level):
        if level != 0:
            for i in range(0, level):
                file.write('\t')

    def write_object(self, object, file, indent):
        if isinstance(object, int):
            file.write('%d' % object)
        elif isinstance(object, str):
            if object == '':
                file.write('""')
            elif not re.search('[^A-Za-z0-9_]', object):
                file.write('%s' % object)
            else:
                file.write('"%s"' % object)
        elif isinstance(object, dict):
            file.write('{')
            file.write('\n')
            for key in sorted(object.keys()):
                self.indent(file, indent + 1)
                file.write('%s = ' % key)
                self.write_object(object[key], file, indent + 1)
                file.write(';\n')
            self.indent(file, indent)
            file.write('}')
        elif isinstance(object, list):
            file.write('(')
            for key in object:
                self.write_object(key, file, 1)
                file.write(',')
            file.write(')')

    def generate_id(self, id):
        self.typeCounter[id] += 1
        return str('X%06d' % self.typeCounter[id])

    def generate_target(self, target, module, targetObj, sourceObj):
        targetId = self.generate_id('PBXNativeTarget')
        configurationListId = self.generate_id('XCConfigurationList')
        configurationDebugId = self.generate_id('XCBuildConfiguration')
        fileId = self.generate_id('PBXFileReference')
        objects = {configurationListId: self.generate_XCBuildConfiguration(target, configurationDebugId),
#MAKE                   targetId: self.generate_PBXLegacyTarget(target, configurationListId),
                   targetId: self.generate_PBXNativeTarget(target, configurationListId),
                   configurationDebugId: self.generate_XCBuildConfiguration(target, configurationDebugId, debug=True),
                   fileId : self.generate_PBXFileReference(module, target['LINKTARGET'], explicit=target['build_type'])
                   }
        self.rootObj['attributes']['TargetAttributes'].update(
            {targetId: {'CreatedOnToolsVersion': '8.2', 'ProvisioningStyle': 'Automatic'}})
        self.rootObj['buildConfigurationList'] = configurationListId
        self.rootObj['targets'].append(targetId)
        targetObj['children'].append(fileId)
        return objects

    def generate_PBXGroup(self, name):
        obj = {'isa': 'PBXGroup', 'children': [], 'sourceTree': '<group>'}
        if not name is None:
            obj['name'] = name
        return self.generate_id('PBXGroup'), obj

    def generate_PBXLegacyTarget(self, modulename, configurationListId):
        if modulename['build_type'] == 'Library':
            product = 'com.apple.product-type.library.dynamic'
        elif modulename['build_type'] == 'Executable':
            product = 'com.apple.product-type.executable'
        elif modulename['build_type'] == 'CppunitTest':
            product = 'com.apple.product-type.cppunit'
        else:
            product = 'com.apple.product-type.something'

        return {'isa': 'PBXLegacyTarget',
                'buildConfigurationList': configurationListId,
                'buildArgumentsString': modulename['target_name'],
                'buildPhases': [],
                'dependencies': [],
                'buildToolPath': 'make',
                'buildWorkingDirectory': self.gbuildparser.builddir,
                'name': modulename['target_name'],
                'productName': modulename['name'],
                'passBuildSettingsEnvironment': 1}

    def generate_PBXNativeTarget(self, modulename, configurationListId):
        if modulename['build_type'] == 'Library':
            product = 'com.apple.product-type.library.dynamic'
        elif modulename['build_type'] == 'Executable':
            product = 'com.apple.product-type.tool'
        elif modulename['build_type'] == 'CppunitTest':
            product = 'com.apple.product-type.cppunit'
        else:
            product = 'com.apple.product-type.something'

        return {'isa': 'PBXNativeTarget',
                'buildRules': [],
                'dependencies': [],
                'name': modulename['target_name'],
                'productName': modulename['name'],
                'productType': product,
                'buildConfigurationList': configurationListId,
                'buildPhases': [],
                'productReference': ''}

    def generate_XCBuildConfiguration(self, modulename, configurationDebugId, debug=False):
        if debug:
            result = {'isa': 'XCBuildConfiguration',
                      'buildSettings': {
                            'ALWAYS_SEARCH_USER_PATHS': 'NO',
                            'CLANG_ANALYZER_NONNULL': 'YES',
                            'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++0x',
                            'CLANG_CXX_LIBRARY': 'libc++',
                            'CLANG_ENABLE_MODULES': 'YES',
                            'CLANG_ENABLE_OBJC_ARC': 'YES',
                            'CLANG_WARN_BOOL_CONVERSION': 'YES',
                            'CLANG_WARN_CONSTANT_CONVERSION': 'YES',
                            'CLANG_WARN_DIRECT_OBJC_ISA_USAGE': 'YES_ERROR',
                            'CLANG_WARN_DOCUMENTATION_COMMENTS': 'YES',
                            'CLANG_WARN_EMPTY_BODY': 'YES',
                            'CLANG_WARN_ENUM_CONVERSION': 'YES',
                            'CLANG_WARN_INFINITE_RECURSION': 'YES',
                            'CLANG_WARN_INT_CONVERSION': 'YES',
                            'CLANG_WARN_OBJC_ROOT_CLASS': 'YES_ERROR',
                            'CLANG_WARN_SUSPICIOUS_MOVE': 'YES',
                            'CLANG_WARN_UNREACHABLE_CODE': 'YES',
                            'CLANG_WARN__DUPLICATE_METHOD_MATCH': 'YES',
                            'CODE_SIGN_IDENTITY': '-',
                            'COPY_PHASE_STRIP': 'NO',
                            'DEBUG_INFORMATION_FORMAT': 'dwarf',
                            'ENABLE_STRICT_OBJC_MSGSEND': 'YES',
                            'ENABLE_TESTABILITY': 'YES',
                            'GCC_C_LANGUAGE_STANDARD': 'gnu99',
                            'GCC_DYNAMIC_NO_PIC': 'NO',
                            'GCC_NO_COMMON_BLOCKS': 'YES',
                            'GCC_OPTIMIZATION_LEVEL': 0,
                            'GCC_PREPROCESSOR_DEFINITIONS': ['DEBUG=1', '$(inherited)'],
                            'GCC_WARN_64_TO_32_BIT_CONVERSION': 'YES',
                            'GCC_WARN_ABOUT_RETURN_TYPE': 'YES_ERROR',
                            'GCC_WARN_UNDECLARED_SELECTOR': 'YES',
                            'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE',
                            'GCC_WARN_UNUSED_FUNCTION': 'YES',
                            'GCC_WARN_UNUSED_VARIABLE': 'YES',
                            'MACOSX_DEPLOYMENT_TARGET': '10.12',
                            'MTL_ENABLE_DEBUG_INFO': 'YES',
                            'ONLY_ACTIVE_ARCH': 'YES',
                            'PRODUCT_NAME': '$(TARGET_NAME)',
                            'SDKROOT': 'macosx',
                            'HEADER_SEARCH_PATHS': modulename['include']},
                      'name': 'Debug'}
        else:
            result = {'isa': 'XCConfigurationList',
                      'buildConfigurations': [configurationDebugId],
                      'defaultConfigurationIsVisible': 0,
                      'defaultConfigurationName': 'Debug'}
        return result

    def generate_PBXFileReference(self, module, filepath, explicit=None):
        obj =  {'isa': 'PBXFileReference',
                'path': module + '/' + filepath,
                'name': filepath,
                'sourceTree': '<group>'}
        if not explicit is None:
            if explicit == 'Library':
                obj['explicitFileType'] = 'compiled.mach-o.dylib'
            else:
                obj['explicitFileType'] = 'compiled.executable'
            obj['includeInIndex'] = 0
            obj['path'] = filepath
        else:
            obj['path'] = module + '/' + filepath
        return obj



class VisualStudioIntegrationGenerator(IdeIntegrationGenerator):

    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
        self.toolset = self.retrieve_toolset()
        self.solution_directory = './windows'
        self.configurations = {
            'Build': {
                'build': self.module_make_command('%(target)s'),
                'clean': self.module_make_command('%(target)s.clean'),
                'rebuild': self.module_make_command('%(target)s.clean %(target)s')
            },
            'Unit Tests': {
                'build': self.module_make_command('unitcheck'),
                'clean': self.module_make_command('clean'),
                'rebuild': self.module_make_command('clean unitcheck'),
            },
            'Integration tests': {
                'build': self.module_make_command('unitcheck slowcheck screenshot subsequentcheck'),
                'clean': self.module_make_command('clean'),
                'rebuild': self.module_make_command('clean unitcheck slowcheck screenshot subsequentcheck')
            }
        }

    def retrieve_toolset(self):
        return {'vs2013': 'v120', 'vs2015': 'v140'}.get(self.ide, None)

    def module_make_command(self, targets):
        return '%(sh)s -c "PATH=\\"/bin:$PATH\\";BUILDDIR=\\"%(builddir)s\\" %(makecmd)s -rsC %(location)s ' + targets + '"'

    class Project:

        def __init__(self, guid, target, project_path):
            self.guid = guid
            self.target = target
            self.path = project_path

    def emit(self):
        all_projects = []
        for module in self.gbuildparser.modules:
            projects = []
            module_directory = os.path.join(self.solution_directory, module)
            if module != 'include': #FIXME
                for target in self.gbuildparser.modules[module]['targets']:
                    project_path = os.path.join(module_directory, '%s.vcxproj' % target['target_name'])
                    project_guid = self.write_project(project_path, target)
                    p = VisualStudioIntegrationGenerator.Project(project_guid, target, project_path)
                    projects.append(p)
                self.write_solution(os.path.join(module_directory, '%s.sln' % module), projects)
                all_projects += projects

        self.write_solution(os.path.join(self.solution_directory, 'LibreOffice.sln'), all_projects)

    nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'

    def get_dependency_libs(self, linked_libs, library_projects):
        dependency_libs = {}
        for linked_lib in linked_libs:
            for library_project in library_projects:
                if library_project.target['name'] == linked_lib:
                    dependency_libs[library_project.guid] = library_project
        return dependency_libs

    def write_solution(self, solution_path, projects):
        library_projects = [project for project in projects if project.target['build_type'] == 'Library']
        with open(solution_path, 'w') as f:
            f.write('Microsoft Visual Studio Solution File, Format Version 12.00\n')
            for project in projects:
                target = project.target
                proj_path = os.path.relpath(project.path, os.path.abspath(os.path.dirname(solution_path)))
                f.write('Project("{%s}") = "%s", "%s", "{%s}"\n' %
                        (VisualStudioIntegrationGenerator.nmake_project_guid,
                         target['target_name'], proj_path, project.guid))
                libs_in_solution = self.get_dependency_libs(target['LINKED_LIBS'], library_projects)
                if libs_in_solution:
                    f.write('\tProjectSection(ProjectDependencies) = postProject\n')
                    for lib_guid in libs_in_solution.keys():
                        f.write('\t\t{%(guid)s} = {%(guid)s}\n' % {'guid': lib_guid})
                    f.write('\tEndProjectSection\n')
                f.write('EndProject\n')
            f.write('Global\n')
            platform = 'Win32'
            f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
            for cfg in self.configurations:
                f.write('\t\t%(cfg)s|%(platform)s = %(cfg)s|%(platform)s\n' % {'cfg': cfg, 'platform': platform})
            f.write('\tEndGlobalSection\n')
            f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
            # Specifies project configurations for solution configuration
            for project in projects:
                for cfg in self.configurations:
                    params = {'guid': project.guid, 'sol_cfg': cfg, 'proj_cfg': cfg, 'platform': platform}
                    f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.ActiveCfg = %(proj_cfg)s|%(platform)s\n' % params)
                    # Build.0 is basically 'Build checkbox' in configuration manager
                    f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.Build.0 = %(proj_cfg)s|%(platform)s\n' % params)
            f.write('\tEndGlobalSection\n')
            f.write('EndGlobal\n')

    def write_project(self, project_path, target):
        # See info at http://blogs.msdn.com/b/visualstudio/archive/2010/05/14/a-guide-to-vcxproj-and-props-file-structure.aspx
        folder = os.path.dirname(project_path)
        if not os.path.exists(folder):
            os.makedirs(folder)
        project_guid = str(uuid.uuid4()).upper()
        ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
        ET.register_namespace('', ns)
        proj_node = ET.Element('{%s}Project' % ns, DefaultTargets='Build', ToolsVersion='4.0')
        proj_confs_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns, Label='ProjectConfigurations')
        platform = 'Win32'
        for configuration in self.configurations:
            proj_conf_node = ET.SubElement(proj_confs_node,
                                           '{%s}ProjectConfiguration' % ns,
                                           Include='%s|%s' % (configuration, platform))
            conf_node = ET.SubElement(proj_conf_node, '{%s}Configuration' % ns)
            conf_node.text = configuration
            platform_node = ET.SubElement(proj_conf_node, '{%s}Platform' % ns)
            platform_node.text = platform

        globals_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='Globals')
        proj_guid_node = ET.SubElement(globals_node, '{%s}ProjectGuid' % ns)
        proj_guid_node.text = '{%s}' % project_guid
        proj_keyword_node = ET.SubElement(globals_node, '{%s}Keyword' % ns)
        proj_keyword_node.text = 'MakeFileProj'
        proj_name_node = ET.SubElement(globals_node, '{%s}ProjectName' % ns)
        proj_name_node.text = target['target_name']

        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
        for configuration in self.configurations:
            conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label="Configuration",
                                      Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
            # Type of project used by the MSBuild to determine build process, see Microsoft.Makefile.targets
            conf_type_node = ET.SubElement(conf_node, '{%s}ConfigurationType' % ns)
            conf_type_node.text = 'Makefile'
            # VS2012: I need to have this otherwise the names of projects will contain text Visual Studio 2010 in the Solution Explorer
            platform_toolset_node = ET.SubElement(conf_node, '{%s}PlatformToolset' % ns)
            platform_toolset_node.text = self.toolset

        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.props')
        ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionSettings')
        for configuration in self.configurations:
            prop_sheets_node = ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='Configuration',
                                             Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
            ET.SubElement(prop_sheets_node, '{%s}Import' % ns,
                          Project='$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props',
                          Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')",
                          Label='LocalAppDataPlatform')

        ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='UserMacros')
        for cfg_name, cfg_targets in self.configurations.items():
            conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns,
                                      Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (cfg_name, platform))
            nmake_params = {
                'sh': os.path.join(self.gbuildparser.binpath, 'dash.exe'),
                'builddir': self.gbuildparser.builddir,
                'location': target['location'],
                'makecmd': self.gbuildparser.makecmd,
                'target': target['target_name']}
            nmake_build_node = ET.SubElement(conf_node, '{%s}NMakeBuildCommandLine' % ns)
            nmake_build_node.text = cfg_targets['build'] % nmake_params
            nmake_clean_node = ET.SubElement(conf_node, '{%s}NMakeCleanCommandLine' % ns)
            nmake_clean_node.text = cfg_targets['clean'] % nmake_params
            nmake_rebuild_node = ET.SubElement(conf_node, '{%s}NMakeReBuildCommandLine' % ns)
            nmake_rebuild_node.text = cfg_targets['rebuild'] % nmake_params
            nmake_output_node = ET.SubElement(conf_node, '{%s}NMakeOutput' % ns)
            nmake_output_node.text = os.path.join('../..', 'program', 'soffice.exe')
            nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % ns)
            nmake_defs_node.text = ';'.join(list(target['DEFS']) + ['$(NMakePreprocessorDefinitions)'])
            include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % ns)
            includes = [os.path.join('../..', elem) if elem[1] != ':'  else elem for elem in target['include']]
            include_path_node.text = ';'.join(includes + ['$(IncludePath)'])

        ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)

        cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
        for cxxobject in target['CXXOBJECTS']:
            cxxrelpath = os.path.join('../..', target['location'].split('/')[-1], cxxobject)
            cxxabspath = os.path.join(self.gbuildparser.srcdir, target['location'].split('/')[-1], cxxobject)
            cxxfile = cxxabspath
            if os.path.isfile(cxxfile):
                ET.SubElement(cxxobjects_node, '{%s}ClCompile' % ns, Include=cxxrelpath)
            else:
                print('Source %s in project %s does not exist' % (cxxfile, target['target_name']))

        includes_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
        for cxxobject in target['CXXOBJECTS']:
            include_rel_path = os.path.join('../..',target['location'].split('/')[-1], cxxobject)
            include_abs_path = os.path.join(self.gbuildparser.srcdir,target['location'].split('/')[-1], cxxobject)
            hxxfile = include_abs_path
            if os.path.isfile(hxxfile):
                ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=include_rel_path)
            # Few files have corresponding .h files
            hfile = include_abs_path
            if os.path.isfile(hfile):
                ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=include_rel_path)
        ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
        ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionTargets')
        self.write_pretty_xml(proj_node, project_path)
        self.write_filters(project_path + '.filters',
                           os.path.join(self.gbuildparser.srcdir, os.path.basename(target['location'])),
                           [cxx_node.get('Include') for cxx_node in cxxobjects_node.findall('{%s}ClCompile' % ns)],
                           [include_node.get('Include') for include_node in includes_node.findall('{%s}ClInclude' % ns)])
        return project_guid

    def get_filter(self, module_dir, proj_file):
        return '\\'.join(os.path.relpath(proj_file, module_dir).split('/')[:-1])

    def get_subfilters(self, proj_filter):
        parts = proj_filter.split('\\')
        subfilters = set([proj_filter])
        for i in range(1, len(parts)):
            subfilters.add('\\'.join(parts[:i]))
        return subfilters

    def write_pretty_xml(self, node, file_path):
        xml_str = ET.tostring(node, encoding='unicode')
        pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
        with open(file_path, 'w') as f:
            f.write(pretty_str.decode())

    def add_nodes(self, files_node, module_dir, tag, project_files):
        ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
        filters = set()
        for project_file in project_files:
            file_node = ET.SubElement(files_node, tag, Include=project_file)
            if os.path.commonprefix([module_dir, project_file]) == module_dir:
                project_filter = self.get_filter(module_dir, project_file)
                filter_node = ET.SubElement(file_node, '{%s}Filter' % ns)
                filter_node.text = project_filter
                filters |= self.get_subfilters(project_filter)
        return filters

    def write_filters(self, filters_path, module_dir, compile_files, include_files):
        ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
        ET.register_namespace('', ns)
        proj_node = ET.Element('{%s}Project' % ns, ToolsVersion='4.0')
        filters = set()
        compiles_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
        filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % ns, compile_files)
        include_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
        filters |= self.add_nodes(include_node, module_dir, '{%s}ClInclude' % ns, include_files)

        filters_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
        for proj_filter in filters:
            filter_node = ET.SubElement(filters_node, '{%s}Filter' % ns, Include=proj_filter)
            filter_id_node = ET.SubElement(filter_node, '{%s}UniqueIdentifier' % ns)
            filter_id_node.text = '{%s}' % str(uuid.uuid4())
        self.write_pretty_xml(proj_node, filters_path)


class DebugIntegrationGenerator(IdeIntegrationGenerator):

    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)

    def emit(self):
        print(self.gbuildparser.srcdir)
        print(self.gbuildparser.builddir)
        print("testWinIde test:")
        testWinIde(self.gbuildparser, self.ide).emit()
        print("VisualStudioIntegrationGenerator test:")
        VisualStudioIntegrationGenerator(self.gbuildparser, self.ide).emit()
        print("XcodeIntegrationGenerator test:")
        XcodeIntegrationGenerator(self.gbuildparser, self.ide).emit()
        print("EclipseCDTIntegrationGenerator test:")
        EclipseCDTIntegrationGenerator(self.gbuildparser, self.ide).emit()
        print("KdevelopIntegrationGenerator test:")
        KdevelopIntegrationGenerator(self.gbuildparser, self.ide).emit()
        print("VimIntegrationGenerator test:")
        VimIntegrationGenerator(self.gbuildparser, self.ide).emit()
        print("QtCreatorIntegrationGenerator test:")
        QtCreatorIntegrationGenerator(self.gbuildparser, self.ide).emit()



# ---- Classes below this point are not actively maintained -------



class EclipseCDTIntegrationGenerator(IdeIntegrationGenerator):

    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)

    def create_include_path(self):
        for module in self.gbuildparser.modules:
            if module == 'include':
                continue
            modulepath = os.path.join(self.gbuildparser.builddir, module)
            includedirfile = open(os.path.join(modulepath, '.eclipsesettingfile'), 'w')
            modulelibs = []
            for lib in self.target_path.keys():
                if lib.startswith(module+'/'):
                    modulelibs.append(lib)
            include = []
            for lib in modulelibs:
                for target in self.target_path[lib]:
                    include.extend(target[0]['include'])
            includedirfile.write('\n'.join(include))
            includedirfile.close()


    def create_macros(self):
        for module in self.gbuildparser.modules:
            if module == 'include':
                continue
            modulepath = os.path.join(self.gbuildparser.builddir, module)
            macrofile = open(os.path.join(modulepath, '.macros'), 'w')
            modulelibs = []
            for lib in self.target_path.keys():
                if lib.startswith(module+'/'):
                    modulelibs.append(lib)
            define = []
            defineset = set()
            for lib in modulelibs:
                for target in self.target_path[lib]:
                    for i in target[0]['DEFS'].keys():
                        tmp = str(i) +','+str(target[0]['DEFS'][i])
                        if tmp not in defineset:
                            defineset.add(tmp)
            macrofile.write('\n'.join(defineset))
            macrofile.close()


    def create_settings_file(self):

        settingsfiletemplate = """\
<?xml version="1.0" encoding="UTF-8"?>
<cdtprojectproperties>
<section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths">
<language name="C++ Source File">


</language>
<language name="C Source File">

</language>
<language name="Object File">

</language>
<language name="Assembly Source File">

</language>
</section>
<section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros">
<language name="C++ Source File">

</language>
<language name="C Source File">

</language>
<language name="Object File">

</language>
<language name="Assembly Source File">

</language>
</section>
</cdtprojectproperties>
"""

        for module in self.gbuildparser.modules:
            if module == 'include':
                continue
            tempxml = []
            modulepath = os.path.join(self.gbuildparser.builddir, module)

            settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
            settingsfile.write(settingsfiletemplate)
            settingsfile.close()

            settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'r')
            tempxml = settingsfile.readlines()
            tempinclude = open(os.path.join(modulepath, '.eclipsesettingfile'), 'r')
            tempmacro = open(os.path.join(modulepath, '.macros'), 'r')
            for includepath in tempinclude:
                if includepath[-1:] == "\n":
                    includepath = includepath[:-1]
                templine = "<includepath>%s</includepath>\n" % includepath
                tempxml.insert(5, templine)

            for line in tempmacro:
                macroskeyvalue = line.split(',')
                macrokey = macroskeyvalue[0]
                macrovalue = macroskeyvalue[1]
                if macrovalue[-1:] == "\n":
                    macrovalue = macrovalue[:-1]
                templine = "<macro><name>%s</name><value>%s</value></macro>\n" %(macrokey, macrovalue)
                tempxml.insert(-13, templine)
            tempxml="".join(tempxml)
            settingsfile.close

            settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
            settingsfile.write(tempxml)
            settingsfile.close()
            os.remove(os.path.join(modulepath, '.eclipsesettingfile'))
            os.remove(os.path.join(modulepath, '.macros'))

    def emit(self):
        self.target_path = {}
        for m in self.gbuildparser.modules:
            if m == 'include':
                continue
            for target in self.gbuildparser.modules[m]['targets']:
                for cxx in target['CXXOBJECTS']:
                    path = '/'.join(cxx.split('/')[:-1])
                    if path not in self.target_path:
                        self.target_path[path] = []
                    self.target_path[path].append([target])
        self.create_include_path()
        self.create_macros()
        self.create_settings_file()



class VimIntegrationGenerator(IdeIntegrationGenerator):

    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)

    def emit(self):
        global_list = []
        for m in self.gbuildparser.modules:
            for lib in self.gbuildparser.modules[m]['targets']:
                entries = []
                for file in lib['CXXOBJECTS']:
                    xFile = lib['module'] + '/' + file
                    filePath = os.path.join(self.gbuildparser.srcdir, xFile)
                    entry = {'directory': lib['location'], 'file': filePath, 'command': self.generateCommand(lib, filePath)}
                    entries.append(entry)
                global_list.extend(entries)
        export_file = open('compile_commands.json', 'w')
        json.dump(global_list, export_file)

    def generateCommand(self, lib, file):
        command = 'clang++ -Wall'
        for key, value in lib['DEFS'].items():
            command += ' -D'
            command += key
            if value is not None:
                command += '='
                command += value

        # The directory of the file is missing from lib's include list, as that
        # one is not the same for all source files in the lib.
        command += ' -I' + os.path.dirname(file)

        for include in lib['include']:
            command += ' -I'
            command += os.path.abspath(include)
        for isystem in lib['include_sys']:
            command += ' -isystem '
            command += isystem
        for cxxflag in lib['CXXFLAGS']:
            command += ' '
            command += cxxflag
        command += ' -c '
        command += file
        # Help clang when the tree is configured for gcc.
        for gnu in ('-std=gnu++11', '-std=gnu++1y'):
            command = command.replace(gnu, '-std=c++11')
        return command



class KdevelopIntegrationGenerator(IdeIntegrationGenerator):

    def encode_int(self, i):
        temp = '%08x' % i
        return '\\x%s\\x%s\\x%s\\x%s' % (temp[0:2], temp[2:4], temp[4:6], temp[6:8])

    def encode_string(self, string):
        result = self.encode_int(len(string) * 2)
        for c in string.encode('utf-16-be'):
            if c in range(32, 126):
                result += chr(c)
            else:
                result += '\\x%02x' % c
        return result

    def generate_buildsystemconfigtool(self, configid, tool, args, exe, typenr):
        return KdevelopIntegrationGenerator.buildsystemconfigtooltemplate % {'configid': configid, 'tool': tool,
                                                                             'args': args, 'exe': exe, 'typenr': typenr}

    buildsystemconfigtooltemplate = """
[CustomBuildSystem][BuildConfig%(configid)d][Tool%(tool)s]
Arguments=%(args)s
Enabled=true
Environment=
Executable=%(exe)s
Type=%(typenr)d

"""

    def generate_buildsystemconfig(self, configid, moduledir, builddir, title, buildparms=''):
        result = KdevelopIntegrationGenerator.buildsystemconfigtemplate % {'configid': configid, 'builddir': builddir,
                                                                           'title': title}
        result += self.generate_buildsystemconfigtool(configid, 'Clean', 'clean %s' % buildparms,
                                                      self.gbuildparser.makecmd, 3)
        result += self.generate_buildsystemconfigtool(configid, 'Build', 'all %s' % buildparms,
                                                      self.gbuildparser.makecmd, 0)
        return result

    buildsystemconfigtemplate = """
[CustomBuildSystem][BuildConfig%(configid)d]
BuildDir=file://%(builddir)s
Title=%(title)s

"""

    def generate_buildsystem(self, moduledir):
        result = KdevelopIntegrationGenerator.buildsystemtemplate % {'defaultconfigid': 0}
        result += self.generate_buildsystemconfig(0, moduledir, moduledir, 'Module Build -- Release')
        result += self.generate_buildsystemconfig(1, moduledir, self.gbuildparser.builddir, 'Full Build -- Release')
        result += self.generate_buildsystemconfig(2, moduledir, moduledir, 'Module Build -- Debug', 'debug=T')
        result += self.generate_buildsystemconfig(3, moduledir, self.gbuildparser.builddir, 'Full Build -- Debug',
                                                  'debug=T')
        return result

    buildsystemtemplate = """
[CustomBuildSystem]
CurrentConfiguration=BuildConfig%(defaultconfigid)d

"""

    def generate_launch(self, launchid, launchname, executablepath, args, workdir):
        return KdevelopIntegrationGenerator.launchtemplate % {'launchid': launchid, 'launchname': launchname,
                                                              'executablepath': executablepath, 'args': args,
                                                              'workdir': workdir}

    launchtemplate = """
[Launch][Launch Configuration %(launchid)d]
Configured Launch Modes=execute
Configured Launchers=nativeAppLauncher
Name=%(launchname)s
Type=Native Application

[Launch][Launch Configuration %(launchid)d][Data]
Arguments=%(args)s
Dependencies=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x00)
Dependency Action=Nothing
EnvironmentGroup=default
Executable=file://%(executablepath)s
External Terminal=konsole --noclose --workdir %%workdir -e %%exe
Project Target=
Use External Terminal=false
Working Directory=file://%(workdir)s
isExecutable=true

"""

    def generate_launches(self, moduledir):
        launches = ','.join(['Launch Configuration %d' % i for i in range(7)])
        result = KdevelopIntegrationGenerator.launchestemplate % {'launches': launches}
        result += self.generate_launch(0, 'Local tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
                                       'unitcheck', moduledir)
        result += self.generate_launch(1, 'Local tests -- slow tests (unitcheck, slowcheck, screenshot)', self.gbuildparser.makecmd,
                                       'unitcheck slowcheck screenshot', moduledir)
        result += self.generate_launch(2, 'Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
                                       self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck', moduledir)
        result += self.generate_launch(3, 'Global tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
                                       'unitcheck', self.gbuildparser.builddir)
        result += self.generate_launch(4, 'Global tests -- slow tests (unitcheck, slowcheck, screenshot)',
                                       self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot', self.gbuildparser.builddir)
        result += self.generate_launch(5, 'Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
                                       self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck',
                                       self.gbuildparser.builddir)
        result += self.generate_launch(6, 'Run LibreOffice',
                                       os.path.join(self.gbuildparser.instdir, 'program/soffice.bin'), '',
                                       self.gbuildparser.instdir)
        return result

    launchestemplate = """
[Launch]
Launch Configurations=%(launches)s

"""

    def write_modulebeef(self, moduledir, modulename):
        beefdir = os.path.join(moduledir, '.kdev4')
        os.mkdir(beefdir)
        beeffile = open(os.path.join(beefdir, 'Module_%s.kdev4' % modulename), 'w')
        beeffile.write(self.generate_buildsystem(moduledir))
        beeffile.write(self.generate_launches(moduledir))
        beeffile.close()

    def write_modulestub(self, moduledir, modulename):
        stubfile = open(os.path.join(moduledir, 'Module_%s.kdev4' % modulename), 'w')
        stubfile.write(KdevelopIntegrationGenerator.modulestubtemplate % {'modulename': modulename,
                                                                          'builditem': self.encode_string(
                                                                              'Module_%s' % modulename)})
        stubfile.close()

    modulestubtemplate = """
[Buildset]
BuildItems=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x0b\\x00\\x00\\x00\\x00\\x01%(builditem)s)

[Project]
Name=Module_%(modulename)s
Manager=KDevCustomBuildSystem
VersionControl=kdevgit
"""

    def write_includepaths(self, path):
        includedirfile = open(os.path.join(path, '.kdev_include_paths'), 'w')
        include = set()
        for target in self.target_path[path]:
            include |= set(target['include'])
        includedirfile.write('\n'.join(include))
        includedirfile.close()

    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)

    def emit(self):
        self.target_path = {}
        for m in self.gbuildparser.modules:
            for target in self.gbuildparser.modules[m]['targets']:
                for cxx in target['CXXOBJECTS']:
                    path = '/'.join(cxx.split('/')[:-1])
                    path = target['module'] + '/' + path
                    if path not in self.target_path:
                        self.target_path[path] = []
                    self.target_path[path].append(target)

        for path in self.target_path:
            self.write_includepaths(path)
        for modulename in self.gbuildparser.modules:
            if modulename=='include':
                continue
            location = self.gbuildparser.srcdir + '/' + modulename
            self.write_modulestub(location, modulename)
            self.write_modulebeef(location, modulename)
            for f in os.listdir(location):
                if f.endswith('.kdev4'):
                    try:
                        os.remove(os.path.join(location, f))
                    except OSError:
                        shutil.rmtree(os.path.join(location, f))



class QtCreatorIntegrationGenerator(IdeIntegrationGenerator):

    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
        self.target_by_location = {}
        for m in self.gbuildparser.modules:
            for target in self.gbuildparser.modules[m]['targets']:
                if target['location'] not in self.target_by_location:
                    self.target_by_location[target['location']] = []
                self.target_by_location[target['location']].append(target)

        self._do_log = False  # set to 'True' to activate log of QtCreatorIntegrationGenerator
        if self._do_log:
            qtlog_path = os.path.abspath('../qtlog_.txt')
            self.qtlog = open(qtlog_path, 'w')

    def _log(self, message):
        if self._do_log:
            self.qtlog.write(message)

    def log_close(self):
        if self._do_log:
            self.qtlog.close()

    def generate_build_configs(self, lib_folder):
        module_folder = os.path.join(self.base_folder, lib_folder)
        xml = ""
        # In QtCreator UI, build configs are listed alphabetically,
        # so it can be different from the creation order.
        # So we prefix the names with the index.
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '0',
            'base_folder': module_folder,
            'arg': "",
            'name': "1-Build %s" % lib_folder,
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '1',
            'base_folder': module_folder,
            'arg': "unitcheck",
            'name': "2-Local tests -- quick tests (unitcheck)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '2',
            'base_folder': module_folder,
            'arg': "unitcheck slowcheck screenshot",
            'name': "3-Local tests -- slow tests (unitcheck, slowcheck, screenshot)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '3',
            'base_folder': module_folder,
            'arg': "unitcheck slowcheck screenshot subsequentcheck",
            'name': "4-Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '4',
            'base_folder': self.base_folder,
            'arg': "unitcheck",
            'name': "5-Global tests -- quick tests (unitcheck)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '5',
            'base_folder': self.base_folder,
            'arg': "unitcheck slowcheck screenshot",
            'name': "6-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '6',
            'base_folder': self.base_folder,
            'arg': "unitcheck slowcheck screenshot subsequentcheck",
            'name': "7-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '7',
            'base_folder': self.base_folder,
            'arg': "build-nocheck",
            'name': "8-Global build -- nocheck",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '8',
            'base_folder': self.base_folder,
            'arg': "",
            'name': "9-Global build",
        }

        xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
            'nb': '9',
        }
        return xml

    def generate_meta_build_configs(self):
        xml = ""
        # In QtCreator UI, build configs are listed alphabetically,
        # so it can be different from the creation order.
        # So we prefix the names with the index.
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '0',
            'base_folder': self.base_folder,
            'arg': "",
            'name': "01-Global Build",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '1',
            'base_folder': self.base_folder,
            'arg': "unitcheck",
            'name': "02-Global tests -- quick tests (unitcheck)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '2',
            'base_folder': self.base_folder,
            'arg': "unitcheck slowcheck screenshot",
            'name': "03-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '3',
            'base_folder': self.base_folder,
            'arg': "unitcheck slowcheck screenshot subsequentcheck",
            'name': "04-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '4',
            'base_folder': self.base_folder,
            'arg': "perfcheck",
            'name': "05-Global tests -- performance tests (perfcheck)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '5',
            'base_folder': self.base_folder,
            'arg': "check",
            'name': "06-Global tests -- tests (check)",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '6',
            'base_folder': self.base_folder,
            'arg': "build-nocheck",
            'name': "07-Global build -- nocheck",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '7',
            'base_folder': self.base_folder,
            'arg': "build-l10n-only",
            'name': "08-Global build -- build-l10n-only",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '8',
            'base_folder': self.base_folder,
            'arg': "build-non-l10n-only",
            'name': "09-Global build -- build-non-l10n-only",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '9',
            'base_folder': self.base_folder,
            'arg': "clean",
            'name': "10-Global build -- clean",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '10',
            'base_folder': self.base_folder,
            'arg': "clean-build",
            'name': "11-Global build -- clean-build",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_template % {
            'index': '11',
            'base_folder': self.base_folder,
            'arg': "clean-host",
            'name': "12-Global build -- clean-host",
        }
        xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
            'nb': '12',
        }
        return xml

    # By default, QtCreator creates 2 BuildStepList : "Build" et "Clean"
    # but the "clean" can be empty.
    build_configs_template = """
    <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.%(index)s">
    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">%(base_folder)s</value>

    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">

     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
       <value type="QString">-w</value>
       <value type="QString">-r</value>
      </valuelist>
      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">%(arg)s</value>
      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
     </valuemap>

     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
    </valuemap>

    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">%(name)s</value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">%(index)s</value>
    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
   </valuemap>
   """

    build_configs_count_template = """
   <!-- nb build configurations -->
   <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">%(nb)s</value>
   """

    def generate_deploy_configs(self, lib_folder):
        xml = QtCreatorIntegrationGenerator.deploy_configs_template % {}
        return xml

    deploy_configs_template = """
   <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
    </valuemap>
    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
   </valuemap>
   <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
    """

    def generate_run_configs(self, lib_folder):

        # If we use 'soffice', it's ok only for "Run", not for "Debug".
        # So we put "soffice.bin" that is ok for both.
        loexec = "%s/instdir/program/soffice.bin" % self.base_folder
        xml = QtCreatorIntegrationGenerator.run_configs_template % {
            'loexec': loexec,
            'workdir': self.base_folder
        }
        return xml

    run_configs_template = """
   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
    <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
    <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
    <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
    <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
     <value type="int">0</value>
     <value type="int">1</value>
     <value type="int">2</value>
     <value type="int">3</value>
     <value type="int">4</value>
     <value type="int">5</value>
     <value type="int">6</value>
     <value type="int">7</value>
     <value type="int">8</value>
     <value type="int">9</value>
     <value type="int">10</value>
     <value type="int">11</value>
     <value type="int">12</value>
     <value type="int">13</value>
     <value type="int">14</value>
    </valuelist>
    <value type="int" key="PE.EnvironmentAspect.Base">2</value>
    <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>

    <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
    <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%(loexec)s</value>
    <value type="bool" key="ProjectExplorer.CustomExecutableRunConfiguration.UseTerminal">false</value>
    <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">%(workdir)s</value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run libreoffice/instdir/program/soffice</value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
    <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
    <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
    <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
    <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
    <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>

   </valuemap>
   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
    """

    def generate_pro_user_content(self, lib_folder):

        build_configs = self.generate_build_configs(lib_folder)
        deploy_configs = self.generate_deploy_configs(lib_folder)
        run_configs = self.generate_run_configs(lib_folder)

        xml = QtCreatorIntegrationGenerator.pro_user_template % {
            'build_configs': build_configs,
            'deploy_configs': deploy_configs,
            'run_configs': run_configs,
        }
        return xml

    def generate_meta_pro_user_content(self):

        build_configs = self.generate_meta_build_configs()
        deploy_configs = self.generate_deploy_configs("")
        run_configs = self.generate_run_configs("")

        xml = QtCreatorIntegrationGenerator.pro_user_template % {
            'build_configs': build_configs,
            'deploy_configs': deploy_configs,
            'run_configs': run_configs,
        }
        return xml

    pro_user_template = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.1.1, 2015-05-14T15:54:34. -->
<qtcreator>
 <data>
  <variable>ProjectExplorer.Project.ActiveTarget</variable>
  <value type="int">0</value>
 </data>

 <!-- editor settings -->
 <data>
  <variable>ProjectExplorer.Project.EditorSettings</variable>
  <valuemap type="QVariantMap">
   <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
   <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
   <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
    <value type="QString" key="language">Cpp</value>
    <valuemap type="QVariantMap" key="value">
     <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
    </valuemap>
   </valuemap>
   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
    <value type="QString" key="language">QmlJS</value>
    <valuemap type="QVariantMap" key="value">
     <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
    </valuemap>
   </valuemap>
   <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
   <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
   <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
   <value type="int" key="EditorConfiguration.IndentSize">4</value>
   <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
   <value type="int" key="EditorConfiguration.MarginColumn">80</value>
   <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
   <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
   <value type="int" key="EditorConfiguration.PaddingMode">1</value>
   <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
   <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
   <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
   <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
   <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
   <value type="int" key="EditorConfiguration.TabSize">8</value>
   <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
   <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
   <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
   <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
   <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
   <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
  </valuemap>
 </data>

 <data>
  <variable>ProjectExplorer.Project.PluginSettings</variable>
  <valuemap type="QVariantMap"/>
 </data>

 <!-- target -->
 <data>
  <variable>ProjectExplorer.Project.Target.0</variable>
  <valuemap type="QVariantMap">
   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{0701de51-c96e-4e4f-85c3-e70b223c5076}</value>
   <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
   <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
   <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>

   <!-- build configurations -->
   %(build_configs)s

   <!-- deploy configurations -->
   %(deploy_configs)s

   <!-- plugin settings -->
   <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>

   <!-- run configurations -->
   %(run_configs)s

  </valuemap>
 </data>
 <!-- nb targets : 1 -->
 <data>
  <variable>ProjectExplorer.Project.TargetCount</variable>
  <value type="int">1</value>
 </data>
 <data>
  <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
  <value type="QByteArray">{5abcafed-86f6-49f6-b1cb-380fadd21211}</value>
 </data>
 <data>
  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
  <value type="int">15</value>
 </data>
</qtcreator>
"""

    def remove_qt_files(self):

        def do_remove_file(loc, afile):
            try:
                os.remove(os.path.join(loc, afile))
                self._log("removed %s\n" % afile)
            except OSError:
                self._log("unable to remove %s\n" % afile)

        do_remove_file(self.base_folder, "lo.pro")
        do_remove_file(self.base_folder, "lo.pro.user")
        for location in self.target_by_location:
            for f in os.listdir(location):
                if f.endswith('.pro') or f.endswith('.pro.user'):
                    do_remove_file(location, f)

    def get_source_extension(self, src_file):
        path = os.path.join(self.base_folder, src_file)
        for ext in (".cxx", ".cpp", ".c", ".mm"):
            if os.path.isfile(path):
                return ext
        return ""

    def get_header_extension(self, src_file):
        path = os.path.join(self.base_folder, src_file)
        for ext in (".hxx", ".hpp", ".h"):
            if os.path.isfile(path + ext):
                return ext
        return ""

    def build_data_libs(self):

        self.data_libs = {}

        all_libs = []
        for m in self.gbuildparser.modules:
            for f in self.gbuildparser.modules[m]['targets']:
                all_libs.append(f)
        for lib in all_libs:
            self._log("\nlibrary : %s, loc=%s" % (lib['target_name'], lib['location']))
            lib_name = os.path.basename(lib['location'])
            lib_folder = os.path.relpath(lib['location'], self.base_folder)

            def lopath(path):
                return os.path.relpath(path, lib['location'])

            defines_list = []
            sources_list = []
            includepath_list = []
            # The explicit headers list is not mandatory :
            # QtCreator just needs 'include_path_list' to find all headers files.
            # But files listed in 'header_list' will be shown
            # in a specific "Headers" folder in QtCreator's Project panel.
            # We will list here only headers files of current lib.
            headers_list = []
            for file_ in lib['CXXOBJECTS']:
                # the file has no extension : search it
                # self._log("\n    file : %s" % file_)
                ext = self.get_source_extension(file_)
                if ext:
                    sources_list.append(lopath(file_ + ext))

                # few cxxobject files have a header beside
                ext = self.get_header_extension(file_)
                if ext:
                    headers_list.append(lopath(file_ + ext))

            # List all include paths
            for hdir in lib['include']:
                hf_lopath = lopath(hdir)
                includepath_list.append(hf_lopath)

            # List headers files from current lib
            for hdir in lib['include']:
                if hdir.startswith(lib['location']):
                    for hf in os.listdir(hdir):
                        if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
                            hf_lopath = lopath(os.path.join(hdir, hf))
                            headers_list.append(hf_lopath)

            # List defines
            for key, value in lib['DEFS'].items():
                define = key
                if value is not None:
                    define += '=' + value
                defines_list.append(define)

            # All datas are prepared, store them for the lib.
            if lib_folder in self.data_libs:
                self.data_libs[lib_folder]['sources'] |= set(sources_list)
                self.data_libs[lib_folder]['headers'] |= set(headers_list)
                self.data_libs[lib_folder]['includepath'] |= set(includepath_list)
                self.data_libs[lib_folder]['defines'] |= set(defines_list)
            else:
                self.data_libs[lib_folder] = {
                    'sources': set(sources_list),
                    'headers': set(headers_list),
                    'includepath': set(includepath_list),
                    'defines': set(defines_list),
                    'loc': lib['location'],
                    'name': lib_name
                }

    def emit(self):

        self.base_folder = self.gbuildparser.builddir

        # we remove existing '.pro' and '.pro.user' files
        self.remove_qt_files()

        # for .pro files, we must explicitly list all files (.c, .h)
        # so we can't reuse directly the same method than for kde integration.
        self.build_data_libs()

        subdirs_list = self.data_libs.keys()
        # Now we can create Qt files
        for lib_folder in subdirs_list:
            sources_list = sorted(self.data_libs[lib_folder]['sources'])
            headers_list = sorted(self.data_libs[lib_folder]['headers'])
            includepath_list = sorted(self.data_libs[lib_folder]['includepath'])
            defines_list = sorted(self.data_libs[lib_folder]['defines'])
            lib_loc = self.data_libs[lib_folder]['loc']
            lib_name = self.data_libs[lib_folder]['name']

            sources = " \\\n".join(sources_list)
            headers = " \\\n".join(headers_list)
            includepath = " \\\n".join(includepath_list)
            defines = " \\\n".join(defines_list)

            # create .pro file
            qt_pro_file = '%s/%s.pro' % (lib_loc, lib_name)
            try:
                content = QtCreatorIntegrationGenerator.pro_template % {'sources': sources, 'headers': headers, 'includepath': includepath, 'defines': defines}
                mode = 'w+'
                with open(qt_pro_file, mode) as fpro:
                    fpro.write(content)
                self._log("created %s\n" % qt_pro_file)

            except Exception as e:
                print("ERROR : creating pro file=" + qt_pro_file, file=sys.stderr)
                print(e, file=sys.stderr)
                temp = traceback.format_exc()  # .decode('utf8')
                print(temp, file=sys.stderr)
                print("\n\n", file=sys.stderr)

            # create .pro.user file
            qt_pro_user_file = '%s/%s.pro.user' % (lib_loc, lib_name)
            try:
                with open(qt_pro_user_file, mode) as fprouser:
                    fprouser.write(self.generate_pro_user_content(lib_folder))
                self._log("created %s\n" % qt_pro_user_file)

            except Exception as e:
                print("ERROR : creating pro.user file=" + qt_pro_user_file, file=sys.stderr)
                print(e, file=sys.stderr)
                temp = traceback.format_exc()
                print(temp, file=sys.stderr)
                print("\n\n", file=sys.stderr)

        # create meta .pro file (lists all sub projects)
        qt_meta_pro_file = 'lo.pro'
        try:
            subdirs = " \\\n".join(subdirs_list)
            content = QtCreatorIntegrationGenerator.pro_meta_template % {'subdirs': subdirs}
            with open(qt_meta_pro_file, 'w+') as fmpro:
                fmpro.write(content)

        except Exception as e:
            print("ERROR : creating lo.pro file=" + qt_meta_pro_file, file=sys.stderr)
            print(e, file=sys.stderr)
            temp = traceback.format_exc()
            print(temp, file=sys.stderr)
            print("\n\n", file=sys.stderr)

        # create meta .pro.user file
        qt_meta_pro_user_file = 'lo.pro.user'
        try:
            with open(qt_meta_pro_user_file, mode) as fmprouser:
                fmprouser.write(self.generate_meta_pro_user_content())
            self._log("created %s\n" % qt_meta_pro_user_file)

        except Exception as e:
            print("ERROR : creating lo.pro.user file=" + qt_meta_pro_user_file, file=sys.stderr)
            print(e, file=sys.stderr)
            temp = traceback.format_exc()
            print(temp, file=sys.stderr)
            print("\n\n", file=sys.stderr)

        self.log_close()

    pro_template = """TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt

INCLUDEPATH += %(includepath)s

SOURCES += %(sources)s

HEADERS += %(headers)s

DEFINES += %(defines)s

"""
    pro_meta_template = """TEMPLATE = subdirs

SUBDIRS = %(subdirs)s
"""



class CodeliteIntegrationGenerator(IdeIntegrationGenerator):

    def __init__(self, gbuildparser, ide):
        IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
        self.target_by_location = {}
        for target in set(self.gbuildparser.libs) | set(self.gbuildparser.exes):
            if target.location not in self.target_by_location:
                self.target_by_location[target.location] = set()
            self.target_by_location[target.location] |= set([target])


    def emit(self):
        # create main workspace file
        codelite_workspace_file = 'lo.workspace1'
        with open(codelite_workspace_file, 'w+') as f:
            f.write(self.generate_workspace_content())

    def generate_workspace_content(self):
        projects1 = ''
        projects2 = ''
        projects3 = ''
        for module in self.gbuildparser.modulenamelist:
            projects1 += CodeliteIntegrationGenerator.codelite_projects1_template.format(
                name = module
            )
            projects2 += CodeliteIntegrationGenerator.codelite_projects2_template.format(
                name = module,
                config = 'Debug'
            )
            projects3 += CodeliteIntegrationGenerator.codelite_projects2_template.format(
                name = module,
                config = 'Release'
            )
        xml = CodeliteIntegrationGenerator.codelite_workspace_template.format(
            projects1,
            projects2,
            projects3
        )
        return xml


    codelite_workspace_template = """<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="lo" Database="" SWTLW="Yes">
  <WorkspaceParserMacros/>
  <WorkspaceParserPaths>
    <Include Path="${{WorkspacePath}}/include"/>
  </WorkspaceParserPaths>
    {0}
  <BuildMatrix>
    <WorkspaceConfiguration Name="Debug" Selected="yes">
      <Environment/>
      {1}
    </WorkspaceConfiguration>
    <WorkspaceConfiguration Name="Release" Selected="yes">
      <Environment/>
      {2}
    </WorkspaceConfiguration>
  </BuildMatrix>
</CodeLite_Workspace>
"""
    codelite_projects1_template = """<Project Name="{name}" Path="{name}/{name}.project" Active="No"/>
"""

    codelite_projects2_template = """<Project Name="{name}" ConfigName="{config}"/>
"""

def get_options():
    parser = argparse.ArgumentParser(
        description='LibreOffice gbuild IDE project generator')
    parser.add_argument('--ide', dest='ide', required=True,
                        help='the IDE to generate project files for')
    parser.add_argument('--make', dest='makecmd', required=True,
                        help='the command to execute make')
    #add to debug a new functions in the project keeping contributors
    parser.add_argument('--debug',dest='debug',required=False,
                        help='debug the new functions')
    return parser.parse_args()



if __name__ == '__main__':
    args = get_options()
    # FIXME: Hack
    if args.makecmd == 'make':
        args.makecmd = '/usr/bin/make'
    if args.debug=='test':

        pass
    paths = {}
    generators = {
        # Supported platforms
        'vs2013': VisualStudioIntegrationGenerator,
        'xcode': XcodeIntegrationGenerator,
        'debug': DebugIntegrationGenerator,
        'testIde': testVS2013Ide,

        # Old platforms
        'eclipsecdt': EclipseCDTIntegrationGenerator,
        'kdevelop': KdevelopIntegrationGenerator,
        'vs2015': VisualStudioIntegrationGenerator,
        'vim': VimIntegrationGenerator,
        'qtcreator': QtCreatorIntegrationGenerator,
        'codelite'  : CodeliteIntegrationGenerator,
    }

    if args.ide not in generators.keys():
        print("Invalid ide. valid values are %s" % ','.join(generators.keys()))
        sys.exit(1)

    gbuildparser = GbuildParser(args.makecmd).parse()

    generators[args.ide](gbuildparser, args.ide).emit()
    print("Successfully created the project files.")

# Local Variables:
# indent-tabs-mode: nil
# End:
#
# vim: set et sw=4 ts=4: