def __init__(self, dataDirectory):
        self.log = logging.getLogger('RoundtripTester')
        self.dataDirectory = dataDirectory
        self.skipExport = False
        self.skipCompare = False
        self.comparer = FtlDiff()

        self.arxFiles = ArxFiles(self.dataDirectory)
        self.arxFiles.updateAll()
    def __init__(self, dataDirectory):
        self.log = logging.getLogger('RoundtripTester')
        self.dataDirectory = dataDirectory
        self.skipExport = False
        self.skipCompare = False
        self.comparer = FtlDiff()

        self.arxFiles = ArxFiles(self.dataDirectory)
        self.arxFiles.updateAll()
        cinematic = cinSerializer.read(cinematicFile)
        for keyframe in cinematic.keyframes:
            img = keyframe.image[1]
            if img not in arxFiles.cinematics.textures.keys():
                log.warning('Texture {} not found !', img)

            if keyframe.sound:
                for lang, files in arxFiles.audioSpeech.speeches.items():
                    if keyframe.sound not in files:
                        log.warning('Sound {} for Lang {} not found !'.format(
                            keyframe.sound, lang))
                    #else:
                    #    log.info('Sound {} found'.format(keyframe.sound))

    log.info('Done')


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-d',
                        '--data-dir',
                        help='Where to find the data files',
                        required=True)
    args = parser.parse_args()
    print("Using data dir: " + args.data_dir)

    arxFiles = ArxFiles(args.data_dir)
    arxFiles.updateAll()

    checkCinematics()
                log.info("Portal Poly: bad poly.area value: {}".format(portal.poly.area))
            
            if portal.poly.room != 0 and portal.poly.room != 26988 and portal.poly.room != 3:
                log.info("Portal Poly: bad poly.room value: {}".format(portal.poly.room))
            
            if portal.poly.misc != 0 and portal.poly.misc != 25978:
                log.info("Portal Poly: bad poly.misc value: {}".format(portal.poly.misc))
    
    print("Scene data Stats:")
    print("Tris: {} Quads: {} ratio: {}".format(str(totalTriangles), str(totalQuads), str(totalTriangles / totalQuads)))
    print("maxPolyPerTile: {}".format(maxPolyPerTile))
    print("minPolyPerTile: {}".format(minPolyPerTile))
    print("avgPolyPerTile: {}".format(avgPolyPerTileSum / avgPolyPerTileCount))

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--data-dir', help='Where to find the data files', required=True)
    args = parser.parse_args()
    print("Using data dir: " + args.data_dir)
    
    arxFiles = ArxFiles(args.data_dir)
    arxFiles.updateAll()
    
    # TODO Currently too verbose readd later
    if arxFiles.danglingPaths and False:
        print("Found unexpected files:")
        for p in arxFiles.danglingPaths:
            print(p);
    
    validateScenes()
class RoundtripTester(object):
    def __init__(self, dataDirectory):
        self.log = logging.getLogger('RoundtripTester')
        self.dataDirectory = dataDirectory
        self.skipExport = False
        self.skipCompare = False
        self.comparer = FtlDiff()

        self.arxFiles = ArxFiles(self.dataDirectory)
        self.arxFiles.updateAll()

    def setupCleanBlenderEnvironment(self):
        name = 'arx_addon'

        import addon_utils
        from bpy import context

        # Disable the module first to prevent log spam
        for module in addon_utils.modules():
            if module.__name__ == name:
                is_enabled, is_loaded = addon_utils.check(name)
                if is_loaded:
                    addon_utils.disable(name)

        #bpy.ops.wm.read_homefile()
        bpy.ops.wm.read_factory_settings()

        #addon_utils.modules_refresh()

        moduleFound = False
        for module in addon_utils.modules():
            if module.__name__ == name:
                default, enable = addon_utils.check(name)
                if not enable:
                    addon_utils.enable(name, default_set=True, persistent=False, handle_error=None)
                    context.user_preferences.addons[name].preferences.arxAssetPath = self.dataDirectory
                moduleFound = True

        if not moduleFound:
            raise Exception("Addon not found: {0}".format(name))

        # Cleanup the default scene
        def removeObj(name):
            defaultCube = bpy.context.scene.objects.get(name)
            if defaultCube:
                defaultCube.select = True
                bpy.ops.object.delete()

        removeObj('Cube')
        removeObj('Camera')
        removeObj('Lamp')

    def roundtripModels(self):
        print("Roundtrip Models")

        result_file = open("test_files.txt", "w")
        result_file.write(formatColumns(["Import", "Export", "Compare", "File"]))
        error_file = open("test_errors.txt", "w")

        current_error_id = 0

        for key, val in sorted(self.arxFiles.models.data.items()):
            import_file = os.path.join(val.path, val.model)
            import_file_relative = os.path.relpath(import_file, self.dataDirectory)
            export_file = "test.ftl"

            self.setupCleanBlenderEnvironment()

            try:
                bpy.ops.arx.import_ftl(filepath=import_file)
                import_status = "Ok"
                import_ok = True
            except RuntimeError as e:
                import_ok = False
                error_file.write(formatError(current_error_id, import_file_relative, e.args[0]))
                error_file.flush()
                import_status = formatFailedStatus(current_error_id)
                current_error_id += 1

            if not self.skipExport and import_ok:
                try:
                    bpy.ops.arx.export_ftl(filepath=export_file)
                    export_ok = True
                    export_status = "Ok"
                except RuntimeError as e:
                    export_ok = False
                    error_file.write(formatError(current_error_id, import_file_relative, e.args[0]))
                    error_file.flush()
                    export_status = formatFailedStatus(current_error_id)
                    current_error_id += 1
            else:
                export_ok = False
                export_status = "Skip"

            if not self.skipCompare and import_ok and export_ok:
                result = self.comparer.compareFiles(import_file, export_file)
                if result and not result.children:
                    compare_status = "Ok"
                else:
                    error_file.write(formatError(current_error_id, import_file_relative, str(result)))
                    error_file.flush()
                    compare_status = formatFailedStatus(current_error_id)
                    current_error_id += 1
            else:
                compare_status = "Skip"

            result_file.write(formatColumns([import_status, export_status, compare_status, str(import_file_relative)]))
            result_file.flush()

        result_file.close()
        error_file.close()

    def loadAnimations(self):
        print("Load Animations")

        for key, val in sorted(self.arxFiles.entities.data.items()):
            usedAnimations = []

            scriptPath = os.path.join(val.path, val.script)
            with open(scriptPath, 'rt', encoding='iso-8859-1') as scriptData:
                for line in scriptData:
                    line = line.strip().lower()
                    commentSplit = line.split("//", 2)
                    if commentSplit[0]:
                        commandSplit = commentSplit[0].split()
                        if commandSplit[0] == "loadanim":
                            # anim slot name is in [1]
                            animName = commandSplit[2].strip("\"")
                            # we can't resolve variable values here, ignore ...
                            if not animName.startswith("~"):
                                usedAnimations.append(animName)
                            else:
                                #print("Ignored anim variable: {}".format(animName))
                                pass

            if not usedAnimations:
                self.log.debug("No used animations for {}".format(key))
                pass
            else:
                if not key in self.arxFiles.models.data:
                    self.log.info("No model found for entity: {}".format(key))
                    pass
                else:
                    model = self.arxFiles.models.data[key]
                    import_file = os.path.join(model.path, model.model)

                    for anim in usedAnimations:
                        if not anim in self.arxFiles.animations.data:
                            self.log.warning("Animation {} not found for model {}".format(anim, key))
                            continue

                        animFileName = self.arxFiles.animations.data[anim]
                        self.log.info("Checking model [{}] anim [{}] ".format(key, anim))

                        self.setupCleanBlenderEnvironment()
                        bpy.ops.arx.import_ftl(filepath=import_file)
                        bpy.ops.object.mode_set(mode='OBJECT')

                        #Find root object
                        root = None
                        for o in bpy.data.objects:
                            if not o.parent:
                                root = o

                        root.select = True
                        bpy.context.scene.objects.active = root

                        try:
                            bpy.ops.arx.import_tea(filepath=animFileName)
                        except:
                        #except InconsistentStateException as ise:
                            pass
    def run(self):
        self.loadAddon('arx_addon', (0, 0, 1))

        arxFiles = ArxFiles(args.data)
        arxFiles.updateAll()

        result_file = open("test_files.txt", "w")
        result_file.write(formatColumns(["Import", "Export", "Compare", "File"]))

        error_file = open("test_errors.txt", "w")

        current_error_id = 0

        for key, val in sorted(arxFiles.models.data.items()):
            import_file = os.path.join(val.path, val.model)
            import_file_relative = os.path.relpath(import_file, self.dataDirectory)
            export_file = "test.ftl"

            bpy.ops.wm.read_homefile()

            try:
                self.doImport(import_file)
                import_status = "Ok"
                import_ok = True
            except RuntimeError as e:
                import_ok = False
                error_file.write(formatError(current_error_id, import_file_relative, e.args[0]))
                error_file.flush()
                import_status = formatFailedStatus(current_error_id)
                current_error_id += 1

            if not self.skipExport and import_ok:
                try:
                    self.doExport(export_file)
                    export_ok = True
                    export_status = "Ok"
                except RuntimeError as e:
                    export_ok = False
                    error_file.write(formatError(current_error_id, import_file_relative, e.args[0]))
                    error_file.flush()
                    export_status = formatFailedStatus(current_error_id)
                    current_error_id += 1
            else:
                export_ok = False
                export_status = "Skip"

            if not self.skipCompare and import_ok and export_ok:
                result = self.comparer.compareFiles(import_file, export_file)
                if result and not result.children:
                    compare_status = "Ok"
                else:
                    error_file.write(formatError(current_error_id, import_file_relative, str(result)))
                    error_file.flush()
                    compare_status = formatFailedStatus(current_error_id)
                    current_error_id += 1
            else:
                compare_status = "Skip"

            result_file.write(formatColumns([import_status, export_status, compare_status, str(import_file_relative)]))
            result_file.flush()

        result_file.close()
        error_file.close()
class RoundtripTester(object):
    def __init__(self, dataDirectory):
        self.log = logging.getLogger('RoundtripTester')
        self.dataDirectory = dataDirectory
        self.skipExport = False
        self.skipCompare = False
        self.comparer = FtlDiff()

        self.arxFiles = ArxFiles(self.dataDirectory)
        self.arxFiles.updateAll()

    def setupCleanBlenderEnvironment(self):
        name = 'arx_addon'

        import addon_utils
        from bpy import context

        # Disable the module first to prevent log spam
        for module in addon_utils.modules():
            if module.__name__ == name:
                is_enabled, is_loaded = addon_utils.check(name)
                if is_loaded:
                    addon_utils.disable(name)

        #bpy.ops.wm.read_homefile()
        bpy.ops.wm.read_factory_settings()

        #addon_utils.modules_refresh()

        moduleFound = False
        for module in addon_utils.modules():
            if module.__name__ == name:
                default, enable = addon_utils.check(name)
                if not enable:
                    addon_utils.enable(name,
                                       default_set=True,
                                       persistent=False,
                                       handle_error=None)
                    context.user_preferences.addons[
                        name].preferences.arxAssetPath = self.dataDirectory
                moduleFound = True

        if not moduleFound:
            raise Exception("Addon not found: {0}".format(name))

        # Cleanup the default scene
        def removeObj(name):
            defaultCube = bpy.context.scene.objects.get(name)
            if defaultCube:
                defaultCube.select = True
                bpy.ops.object.delete()

        removeObj('Cube')
        removeObj('Camera')
        removeObj('Lamp')

    def roundtripModels(self):
        print("Roundtrip Models")

        result_file = open("test_files.txt", "w")
        result_file.write(
            formatColumns(["Import", "Export", "Compare", "File"]))
        error_file = open("test_errors.txt", "w")

        current_error_id = 0

        for key, val in sorted(self.arxFiles.models.data.items()):
            import_file = os.path.join(val.path, val.model)
            import_file_relative = os.path.relpath(import_file,
                                                   self.dataDirectory)
            export_file = "test.ftl"

            self.setupCleanBlenderEnvironment()

            try:
                bpy.ops.arx.import_ftl(filepath=import_file)
                import_status = "Ok"
                import_ok = True
            except RuntimeError as e:
                import_ok = False
                error_file.write(
                    formatError(current_error_id, import_file_relative,
                                e.args[0]))
                error_file.flush()
                import_status = formatFailedStatus(current_error_id)
                current_error_id += 1

            if not self.skipExport and import_ok:
                try:
                    bpy.ops.arx.export_ftl(filepath=export_file)
                    export_ok = True
                    export_status = "Ok"
                except RuntimeError as e:
                    export_ok = False
                    error_file.write(
                        formatError(current_error_id, import_file_relative,
                                    e.args[0]))
                    error_file.flush()
                    export_status = formatFailedStatus(current_error_id)
                    current_error_id += 1
            else:
                export_ok = False
                export_status = "Skip"

            if not self.skipCompare and import_ok and export_ok:
                result = self.comparer.compareFiles(import_file, export_file)
                if result and not result.children:
                    compare_status = "Ok"
                else:
                    error_file.write(
                        formatError(current_error_id, import_file_relative,
                                    str(result)))
                    error_file.flush()
                    compare_status = formatFailedStatus(current_error_id)
                    current_error_id += 1
            else:
                compare_status = "Skip"

            result_file.write(
                formatColumns([
                    import_status, export_status, compare_status,
                    str(import_file_relative)
                ]))
            result_file.flush()

        result_file.close()
        error_file.close()

    def loadAnimations(self):
        print("Load Animations")

        for key, val in sorted(self.arxFiles.entities.data.items()):
            usedAnimations = []

            scriptPath = os.path.join(val.path, val.script)
            with open(scriptPath, 'rt', encoding='iso-8859-1') as scriptData:
                for line in scriptData:
                    line = line.strip().lower()
                    commentSplit = line.split("//", 2)
                    if commentSplit[0]:
                        commandSplit = commentSplit[0].split()
                        if commandSplit[0] == "loadanim":
                            # anim slot name is in [1]
                            animName = commandSplit[2].strip("\"")
                            # we can't resolve variable values here, ignore ...
                            if not animName.startswith("~"):
                                usedAnimations.append(animName)
                            else:
                                #print("Ignored anim variable: {}".format(animName))
                                pass

            if not usedAnimations:
                self.log.debug("No used animations for {}".format(key))
                pass
            else:
                if not key in self.arxFiles.models.data:
                    self.log.info("No model found for entity: {}".format(key))
                    pass
                else:
                    model = self.arxFiles.models.data[key]
                    import_file = os.path.join(model.path, model.model)

                    for anim in usedAnimations:
                        if not anim in self.arxFiles.animations.data:
                            self.log.warning(
                                "Animation {} not found for model {}".format(
                                    anim, key))
                            continue

                        animFileName = self.arxFiles.animations.data[anim]
                        self.log.info("Checking model [{}] anim [{}] ".format(
                            key, anim))

                        self.setupCleanBlenderEnvironment()
                        bpy.ops.arx.import_ftl(filepath=import_file)
                        bpy.ops.object.mode_set(mode='OBJECT')

                        #Find root object
                        root = None
                        for o in bpy.data.objects:
                            if not o.parent:
                                root = o

                        root.select = True
                        bpy.context.scene.objects.active = root

                        try:
                            bpy.ops.arx.import_tea(filepath=animFileName)
                        except:
                            #except InconsistentStateException as ise:
                            pass
    def run(self):
        self.loadAddon('arx_addon', (0, 0, 1))

        arxFiles = ArxFiles(args.data)
        arxFiles.updateAll()

        result_file = open("test_files.txt", "w")
        result_file.write(
            formatColumns(["Import", "Export", "Compare", "File"]))

        error_file = open("test_errors.txt", "w")

        current_error_id = 0

        for key, val in sorted(arxFiles.models.data.items()):
            import_file = os.path.join(val.path, val.model)
            import_file_relative = os.path.relpath(import_file,
                                                   self.dataDirectory)
            export_file = "test.ftl"

            bpy.ops.wm.read_homefile()

            try:
                self.doImport(import_file)
                import_status = "Ok"
                import_ok = True
            except RuntimeError as e:
                import_ok = False
                error_file.write(
                    formatError(current_error_id, import_file_relative,
                                e.args[0]))
                error_file.flush()
                import_status = formatFailedStatus(current_error_id)
                current_error_id += 1

            if not self.skipExport and import_ok:
                try:
                    self.doExport(export_file)
                    export_ok = True
                    export_status = "Ok"
                except RuntimeError as e:
                    export_ok = False
                    error_file.write(
                        formatError(current_error_id, import_file_relative,
                                    e.args[0]))
                    error_file.flush()
                    export_status = formatFailedStatus(current_error_id)
                    current_error_id += 1
            else:
                export_ok = False
                export_status = "Skip"

            if not self.skipCompare and import_ok and export_ok:
                result = self.comparer.compareFiles(import_file, export_file)
                if result and not result.children:
                    compare_status = "Ok"
                else:
                    error_file.write(
                        formatError(current_error_id, import_file_relative,
                                    str(result)))
                    error_file.flush()
                    compare_status = formatFailedStatus(current_error_id)
                    current_error_id += 1
            else:
                compare_status = "Skip"

            result_file.write(
                formatColumns([
                    import_status, export_status, compare_status,
                    str(import_file_relative)
                ]))
            result_file.flush()

        result_file.close()
        error_file.close()