# -*- coding: utf-8 -*-

from __future__ import unicode_literals

__Name__ = 'Highlight Common parts'
__Comment__ = 'Compute the common parts between selected shapes'
__Author__ = 'JMG, galou and other contributors'
__Version__ = '2.3.2'
__Date__ = '2021-07-01'
__License__ = 'CC0-1.0'
__Web__ = 'https://freecadweb.org/wiki/Macro_HighlightCommon'
__Wiki__ = 'https://freecadweb.org/wiki/Macro_HighlightCommon'
__Icon__ = 'HighlightCommon.png'
__Help__ = 'Select at least two objects and run'
__Status__ = 'Production'
__Requires__ = 'FreeCAD V0.17+'
__Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
__Files__ = 'HighlightCommon.png'

from PySide.QtGui import QMessageBox  # FreeCAD's special PySide!

import FreeCAD as app
import FreeCADGui as gui


PREFERENCE_PATH = 'User parameter:BaseApp/Preferences/Mod/HighlightCommon'


def load_and_save_settings():
    param_change = 'change_transparency'
    param_transparency = 'transparency'
    p = app.ParamGet(PREFERENCE_PATH)
    change_transparency = p.GetBool(param_change, True)
    transparency = p.GetInt(param_transparency, 80)
    p.SetBool(param_change, change_transparency)
    p.SetInt(param_transparency, transparency)
    return change_transparency, transparency


def main():
    # Store active doc in case it may change during run.
    doc = app.activeDocument()

    if doc is None:
        return

    change_transparency, transparency = load_and_save_settings()

    colli_grp = None  # Group object to group collisions.
    colli_max = 0  # Maximum collision volume.

    # Open a transaction in undo pile.
    doc.openTransaction('Seeking collisions')

    objectsToEnumerate = gui.Selection.getSelection()
    if len(objectsToEnumerate) < 2:
        objectsToEnumerate = doc.Objects

    # Ensure list of unique objects.
    object_list = []
    for obj in objectsToEnumerate:
        if ((obj not in object_list)
                and hasattr(obj, 'Shape')
                and hasattr(obj, 'getGlobalPlacement')
                and hasattr(obj, 'Label')):
            object_list.append(obj)

    # Going through selected objects (object A).
    for i, object_a in enumerate(object_list):
        shape_a = object_a.Shape.copy()
        shape_a.Placement = object_a.getGlobalPlacement()
        label_a = object_a.Label

        # Making selected objects transparent.
        if change_transparency:
            try:
                object_a.ViewObject.Transparency = transparency
            except AttributeError:
                pass

        # Comparing object A with all
        # following ones in the list (object B).
        for object_b in object_list[(i + 1):]:

            shape_b = object_b.Shape.copy()
            shape_b.Placement = object_b.getGlobalPlacement()
            label_b = object_b.Label
            common = shape_a.common(shape_b)

            # Making selected objects transparent.
            if change_transparency:
                try:
                    object_b.ViewObject.Transparency = transparency
                except AttributeError:
                    pass

            # If object A & object B have a collision
            # display a message with collision volume and
            # add a new representative shape in the group.
            if common.Volume > 1e-6:
                app.Console.PrintMessage(
                    'Volume of the intersection between {} and {}: {:.3f} mm³\n'.format(
                        label_a,
                        label_b,
                        common.Volume))
                colli_max = common.Volume if common.Volume > colli_max else colli_max
                if not colli_grp:
                    # Create group if it doesn't already exist.
                    colli_grp = doc.addObject('App::DocumentObjectGroup',
                                              'Collisions')
                intersection_object = doc.addObject(
                    'Part::Feature')
                intersection_object.Label = '{} - {}'.format(
                    label_a, label_b)
                intersection_object.Shape = common
                intersection_object.ViewObject.ShapeColor = (1.0, 0.0, 0.0, 1.0)
                colli_grp.addObject(intersection_object)
            else:
                # If no collision, just inform the user.
                app.Console.PrintMessage(
                    'No intersection between {} and {}\n'.format(
                        label_a,
                        label_b))

    # If collisions have been found, commit the undo transaction and
    # give a summary (count + max value) to the user.
    if colli_grp:
        doc.commitTransaction()
        app.Console.PrintMessage(
            '{} collision(s) found between selected objects\nMaximum collision: {:.3f} mm³\n'.format(
                len(colli_grp.Group),
                colli_max))
        doc.recompute()
    else:
        # If no collision has been found, just inform the user about it.
        doc.abortTransaction()
        if len(object_list) >= 2:
            app.Console.PrintWarning('No collision found between selected objects\n')
        else:
            app.Console.PrintWarning('No suitable objects selected, select at least two objects\n')


if __name__ == '__main__':
    main()
