import re

from . import util


class Stats:
    def __init__(self):
        # Pepare some regex for parsing
        self.re_path_tracing = re.compile(
            ".*(Rendered|Path Tracing Tile) ([0-9]+)/([0-9]+)( Tiles)?" +
            "(, Sample ([0-9]+)\/([0-9]+))?$")
        self.re_total_render_time = re.compile(
            ".*Total render time: ([0-9]+(\.[0-9]+)?)")
        self.re_render_time_no_sync = re.compile(
            ".*Render time \(without synchronization\): ([0-9]+(\.[0-9]+)?)")
        self.re_pipeline_time = re.compile(
            "Time: ([0-9:\.]+) \(Saving: ([0-9:\.]+)\)")
        self.re_cycles_memory = re.compile(
            ".*\| Mem:([0-9.]+[KM]?), Peak:([0-9.]+[KM]?) \|.*")

        # Render time stats.
        self.total_render_time = "N/A"
        self.render_time_no_sync = "N/A"
        self.pipeline_render_time = "N/A"

        # Render memory stats.
        self.device_peak_memory = "N/A"
        self.device_memory_usage = "N/A"

        # Current stats.
        self.path_tracing = ""
        self.current_tiles = 0
        self.total_tiles = 0
        self.current_sample = None
        self.total_samples = None

    def update(self, line):
        # Current tile progress.
        match = self.re_path_tracing.match(line)
        if match:
            self.path_tracing = match.group(1)
            self.current_tiles = int(match.group(2))
            self.total_tiles = int(match.group(3))
            self.current_sample = match.group(6)
            if self.current_sample is not None:
                self.current_sample = int(self.current_sample)
            self.total_samples = match.group(7)
            if self.total_samples is not None:
                self.total_samples = int(self.total_samples)
        # Total render time.
        match = self.re_total_render_time.match(line)
        if match:
            self.total_render_time = float(match.group(1))
        # Render time without sync.
        match = self.re_render_time_no_sync.match(line)
        if match:
            self.render_time_no_sync = float(match.group(1))
        # Total pipeline time.
        match = self.re_pipeline_time.match(line)
        if match:
            self.pipeline_render_time = \
                util.humanReadableTimeToSeconds(match.group(1))
        # Memory usage.
        match = self.re_cycles_memory.match(line)
        if match:
            mem = util.humanReadableSizeToMegabytes(match.group(1))
            peak = util.humanReadableSizeToMegabytes(match.group(1))
            if self.device_memory_usage == "N/A" or \
               mem > self.device_memory_usage:
                self.device_memory_usage = mem
            if self.device_peak_memory == "N/A" or \
               mem > self.device_peak_memory:
                self.device_peak_memory = mem

    def getCurrentProgress(self):
        if self.total_tiles == 0:
            return 0
        if not self.total_samples:
            return float(self.current_tiles) / float(self.total_tiles) * 100
        current_tile = self.current_tiles
        # Workaround for current master.
        if self.total_samples == self.current_sample:
            current_tile = max(current_tile - 1, 0)
        total_samples = self.total_tiles * self.total_samples
        current_sample = current_tile * self.total_samples + self.current_sample
        return float(current_sample) / float(total_samples) * 100

    def print(self):
        # TODO(sergey): Check that all stats are available.
        print("Total pipeline render time: {} ({} sec)"
              . format(util.humanReadableTimeDifference(
                           self.pipeline_render_time),
                       self.pipeline_render_time))
        print("Total Cycles render time: {} ({} sec)"
              . format(util.humanReadableTimeDifference(
                           self.total_render_time),
                       self.total_render_time))
        print("Pure Cycles render time (without sync): {} ({} sec)"
              . format(util.humanReadableTimeDifference(
                           self.render_time_no_sync),
                       self.render_time_no_sync))
        print("Cycles memoty usage: {} ({} peak)"
              . format(self.device_memory_usage,
                       self.device_peak_memory))

    def asDict(self):
        return {'total_render_time': self.total_render_time,
                'render_time_no_sync': self.render_time_no_sync,
                'pipeline_render_time': self.pipeline_render_time,
                'device_peak_memory': self.device_peak_memory,
                'device_memory_usage': self.device_memory_usage}
