# Example for how to override hiero versioning

import os.path
import glob
import re


from hiero.core import BinItem
from hiero.core import VersionScanner


# We want to redefine some of the methods of VersionScanner, but may still need to use the default functionality within our custom methods.
# Therefore, we need to save a reference to the default methods, and then we will be able to call them from ours.
if not hasattr(VersionScanner, "default_filterVersion"):
    VersionScanner.default_filterVersion = VersionScanner.filterVersion
if not hasattr(VersionScanner, "default_versionLessThan"):
    VersionScanner.default_versionLessThan = VersionScanner.versionLessThan
if not hasattr(VersionScanner, "default_findNewVersions"):
    VersionScanner.default_findNewVersions = VersionScanner.findNewVersions



# Determine whether the file newVersionFile should be included as a new version of originalVersion
# This filtering method only allows to add versions that have the same file format as the active one.
def filterVersionSameFormat(self, binItem, newVersionFile):
    activeVersion = binItem.activeItem()
    if binItem.activeItem() and binItem.activeItem().mediaSource():
        # Obtain active item's filename
        activeVersionFile = binItem.activeItem().mediaSource().firstpath()
        # Obtain extensions:
        ext1 = os.path.splitext(activeVersionFile)[1]
        ext2 = os.path.splitext(newVersionFile)[1]
        return ext1 == ext2
    return False

# Compare method for sorting.
# Sort according to file formats first, then default to Hiero's original sorting (which uses version indices as first criterion).
def versionLessThanOrderByFormat(self, filename1, filename2):
    # Obtain extensions:
    ext1 = os.path.splitext(filename1)[1]
    ext2 = os.path.splitext(filename2)[1]

    # If extensions are different, then sort according to extension:
    if ext1 != ext2:
        return ext1 < ext2

    # If extensions are equal, then default to Hiero's original sorting.
    # NB: For this to work, ensure that the original method has been saved with a different name as shown above!
    return self.default_versionLessThan(filename1, filename2)


# Scan for additional versions that belong to the specified version
# We are having a simple system that looks for new versions in a naming convention where artists add their name
# to the version, e.g: "/files/clip_v1.Mike.mov", "/files/clip_v2.Andrew.0000.dpx"
def findNewVersionsWithArtistName(self, version):
    if not(version.item() and version.item().mediaSource()):
        return

    activeVersionFilename = version.item().mediaSource().firstpath()

    # We use the glob function to find files that look similar to ours.
    # We start with the active version file, and substitute relevant bits with * or ? wildcards.
    globExpression = activeVersionFilename

    # Substitute version index with * wildcard.
    # This will also allow for artist names to appear right after the version index
    versionRegex = "v\\d+[a-zA-Z]*" # e.g.: "v1", "v002Alex", "v100Bella", "v3Clark42", "v4a"
    globExpression = re.sub(versionRegex, "v*", globExpression)

    # Substitute extension with * wildcard.
    # This will also allow for frame numbers to be present before the extension if they were not before
    globExpression = os.path.splitext(globExpression)[0] + ".*"

    # Substitute frame number with * wildcard
    # Need to match files with different frame numbers.
    # This will also allow for frame numbers not to be present before the extension when they were before
    frameNumberRegex = "(\\.|_)\\d+\\." # e.g.: ".000.", "_001.", ".1000."
    globExpression = re.sub(frameNumberRegex, "*.", globExpression)

    # Use glob to find files that match globExpression.
    # We store found files in 'files', and we use 'visitedSequences' to avoid adding more than one frame of the same sequence.
    files = set()
    visitedSequences = set()
    for foundFile in glob.iglob(globExpression):
        # Fix path separators if on Windows!
        foundFile = re.sub("\\\\", "/", foundFile)
        # Now we need to make sure that we only add one frame from each sequence:
        trimmedFileName = re.sub(frameNumberRegex, "", foundFile)
        if not trimmedFileName in visitedSequences:
            visitedSequences.add(trimmedFileName)
            # Finally add the new found file!
            files.add(foundFile)

    return files


# Override the default VersionScanner functions with the custom ones.
VersionScanner.filterVersion = filterVersionSameFormat
VersionScanner.versionLessThan = versionLessThanOrderByFormat
VersionScanner.findNewVersions = findNewVersionsWithArtistName
