# Path: zfs_autobackup/Thinner.py
# class Thinner:
#     """progressive thinner (universal, used for cleaning up snapshots)"""
# 
#     def __init__(self, schedule_str=""):
#         """
#         Args:
#             schedule_str: comma seperated list of ThinnerRules. A plain number specifies how many snapshots to always keep.
#         """
# 
#         self.rules = []
#         self.always_keep = 0
# 
#         if schedule_str == "":
#             return
# 
#         rule_strs = schedule_str.split(",")
#         for rule_str in rule_strs:
#             if rule_str.lstrip('-').isdigit():
#                 self.always_keep = int(rule_str)
#                 if self.always_keep < 0:
#                     raise (Exception("Number of snapshots to keep cant be negative: {}".format(self.always_keep)))
#             else:
#                 self.rules.append(ThinnerRule(rule_str))
# 
#     def human_rules(self):
#         """get list of human readable rules"""
#         ret = []
#         if self.always_keep:
#             ret.append("Keep the last {} snapshot{}.".format(self.always_keep, self.always_keep != 1 and "s" or ""))
#         for rule in self.rules:
#             ret.append(rule.human_str)
# 
#         return ret
# 
#     def thin(self, objects, keep_objects=None, now=None):
#         """thin list of objects with current schedule rules. objects: list of
#         objects to thin. every object should have timestamp attribute.
# 
#             return( keeps, removes )
# 
#         Args:
#             objects: list of objects to check (should have a timestamp attribute)
#             keep_objects: objects to always keep (if they also are in the in the normal objects list)
#             now: if specified, use this time as current time
#         """
# 
#         if not keep_objects:
#             keep_objects = []
# 
#         # always keep a number of the last objets?
#         if self.always_keep:
#             # all of them
#             if len(objects) <= self.always_keep:
#                 return objects, []
# 
#             # determine which ones
#             always_keep_objects = objects[-self.always_keep:]
#         else:
#             always_keep_objects = []
# 
#         # determine time blocks
#         time_blocks = {}
#         for rule in self.rules:
#             time_blocks[rule.period] = {}
# 
#         if not now:
#             now = int(time.time())
# 
#         keeps = []
#         removes = []
# 
#         # traverse objects
#         for thisobject in objects:
#             # important they are ints!
#             timestamp = int(thisobject.timestamp)
#             age = int(now) - timestamp
# 
#             # store in the correct time blocks, per period-size, if not too old yet
#             # e.g.: look if there is ANY timeblock that wants to keep this object
#             keep = False
#             for rule in self.rules:
#                 if age <= rule.ttl:
#                     block_nr = int(timestamp / rule.period)
#                     if block_nr not in time_blocks[rule.period]:
#                         time_blocks[rule.period][block_nr] = True
#                         keep = True
# 
#             # keep it according to schedule, or keep it because it is in the keep_objects list
#             if keep or thisobject in keep_objects or thisobject in always_keep_objects:
#                 keeps.append(thisobject)
#             else:
#                 removes.append(thisobject)
# 
#         return keeps, removes


from basetest import *
from zfs_autobackup.Thinner import Thinner
import pprint
            '2025-01-01 06:15:32',
            '2026-01-01 02:48:23',
            '2026-03-14 09:08:04',
            '2026-04-07 20:07:36',
            '2026-05-07 02:30:29',
            '2026-06-06 01:19:46',
            '2026-07-06 06:38:09',
            '2026-08-05 05:08:53',
            '2026-09-04 03:33:04',
            '2026-10-04 05:27:09',
            '2026-11-04 04:01:17',
            '2026-12-03 13:49:56',
            '2027-01-01 17:02:00',
            '2027-01-03 04:26:42',
            '2027-02-01 14:16:02',
            '2027-02-08 02:41:14',
            '2027-02-12 03:31:02',
            '2027-02-18 00:33:10',
            '2027-02-26 21:09:54',
            '2027-03-02 08:05:18',
            '2027-03-03 16:46:09',
            '2027-03-04 06:39:14',
            '2027-03-06 03:35:41',
            '2027-03-08 12:24:42',
            '2027-03-08 20:34:57']

        #some arbitrary date
        now=1589229252
        #we want deterministic results
        random.seed(1337)

# Path: zfs_autobackup/Thinner.py
# class Thinner:
#     """progressive thinner (universal, used for cleaning up snapshots)"""
# 
#     def __init__(self, schedule_str=""):
#         """
#         Args:
#             schedule_str: comma seperated list of ThinnerRules. A plain number specifies how many snapshots to always keep.
#         """
# 
#         self.rules = []
#         self.always_keep = 0
# 
#         if schedule_str == "":
#             return
# 
#         rule_strs = schedule_str.split(",")
#         for rule_str in rule_strs:
#             if rule_str.lstrip('-').isdigit():
#                 self.always_keep = int(rule_str)
#                 if self.always_keep < 0:
#                     raise (Exception("Number of snapshots to keep cant be negative: {}".format(self.always_keep)))
#             else:
#                 self.rules.append(ThinnerRule(rule_str))
# 
#     def human_rules(self):
#         """get list of human readable rules"""
#         ret = []
#         if self.always_keep:
#             ret.append("Keep the last {} snapshot{}.".format(self.always_keep, self.always_keep != 1 and "s" or ""))
#         for rule in self.rules:
#             ret.append(rule.human_str)
# 
#         return ret
# 
#     def thin(self, objects, keep_objects=None, now=None):
#         """thin list of objects with current schedule rules. objects: list of
#         objects to thin. every object should have timestamp attribute.
# 
#             return( keeps, removes )
# 
#         Args:
#             objects: list of objects to check (should have a timestamp attribute)
#             keep_objects: objects to always keep (if they also are in the in the normal objects list)
#             now: if specified, use this time as current time
#         """
# 
#         if not keep_objects:
#             keep_objects = []
# 
#         # always keep a number of the last objets?
#         if self.always_keep:
#             # all of them
#             if len(objects) <= self.always_keep:
#                 return objects, []
# 
#             # determine which ones
#             always_keep_objects = objects[-self.always_keep:]
#         else:
#             always_keep_objects = []
# 
#         # determine time blocks
#         time_blocks = {}
#         for rule in self.rules:
#             time_blocks[rule.period] = {}
# 
#         if not now:
#             now = int(time.time())
# 
#         keeps = []
#         removes = []
# 
#         # traverse objects
#         for thisobject in objects:
#             # important they are ints!
#             timestamp = int(thisobject.timestamp)
#             age = int(now) - timestamp
# 
#             # store in the correct time blocks, per period-size, if not too old yet
#             # e.g.: look if there is ANY timeblock that wants to keep this object
#             keep = False
#             for rule in self.rules:
#                 if age <= rule.ttl:
#                     block_nr = int(timestamp / rule.period)
#                     if block_nr not in time_blocks[rule.period]:
#                         time_blocks[rule.period][block_nr] = True
#                         keep = True
# 
#             # keep it according to schedule, or keep it because it is in the keep_objects list
#             if keep or thisobject in keep_objects or thisobject in always_keep_objects:
#                 keeps.append(thisobject)
#             else:
#                 removes.append(thisobject)
# 
#         return keeps, removes


# Path: tests/test_thinner.py
from basetest import *
from zfs_autobackup.Thinner import Thinner
import pprint

            '2025-01-01 06:15:32',
            '2026-01-01 02:48:23',
            '2026-03-14 09:08:04',
            '2026-04-07 20:07:36',
            '2026-05-07 02:30:29',
            '2026-06-06 01:19:46',
            '2026-07-06 06:38:09',
            '2026-08-05 05:08:53',
            '2026-09-04 03:33:04',
            '2026-10-04 05:27:09',
            '2026-11-04 04:01:17',
            '2026-12-03 13:49:56',
            '2027-01-01 17:02:00',
            '2027-01-03 04:26:42',
            '2027-02-01 14:16:02',
            '2027-02-08 02:41:14',
            '2027-02-12 03:31:02',
            '2027-02-18 00:33:10',
            '2027-02-26 21:09:54',
            '2027-03-02 08:05:18',
            '2027-03-03 16:46:09',
            '2027-03-04 06:39:14',
            '2027-03-06 03:35:41',
            '2027-03-08 12:24:42',
            '2027-03-08 20:34:57']

        #some arbitrary date
        now=1589229252
        #we want deterministic results
        random.seed(1337)

        thinner=Thinner("5,10s1min,1d1w,1w1m,1m12m,1y5y")