import re

from parallels.core.logging import get_logger
from parallels.core.runners.base import BaseRunner

logger = get_logger(__name__)


class LogWatch(object):
    """
    Remote server log monitoring utility.
    
    Logwatch purpose is to retrieve new records written to domain logs since
    watch is started.
    """
    def __init__(self, domain):
        """
        Object constructor.

        :type domain: parallels.hosting_check.DomainWebService
        """
        self.domain = domain
        self.log_data = {}
    
    def start(self):
        if not self.domain.server:
            logger.debug("Cannot read log files without a server object.")
            return
        if not self.domain.error_logs:
            logger.debug("There are no log files specified.")
            return
        for error_log in self.domain.error_logs:
            file_size = self._get_file_size(error_log)
            logger.debug(
                u"Error log '%s' length: '%s'" % (error_log, file_size)
            )
            # remember log file position
            self.log_data[error_log] = file_size

    def get_log_files(self):
        """List the log files, which are currently being watched."""
        return self.log_data.keys()

    def get_new_records(self, filename):
        """
        Return new log records.

        Arguments:
            filename: log file name
        Returns:
            New records, that were written into the log file since
            LogWatch.start() is called.
        """
        if not self.domain.server:
            return
        if filename not in self.log_data:
            raise LogWatchError(
                u"Logwatch has no data on file '%s'." % filename
            )

        position = self.log_data[filename]
        if not position > 0:
            search_position = "+0"
        else:
            search_position = "+%d" % (position+1)
        with self.domain.server.runner() as runner:
            assert isinstance(runner, BaseRunner)
            stdout = runner.execute_command(
                '/usr/bin/test ! -f {filename} || tail -c {position} {filename}',
                dict(filename=filename, position=search_position)
            ).stdout
        logger.fdebug(
            "New records in '{filename}' start from > '{start}'", filename=filename, start=stdout[:76]
        )
        return stdout

    def _get_file_size(self, filename):
        if not self.domain.server:
            return
        with self.domain.server.runner() as runner:
            assert isinstance(runner, BaseRunner)
            stdout = runner.execute_command(
                '/usr/bin/test ! -f {filename} || wc -c {filename}',
                dict(filename=filename)
            ).stdout
        # parse a string like '2048 filename', where '2048' is the file size
        match = re.search('^\d+', stdout)
        if match:
            return int(match.group(0))
        else:
            logger.debug("Cannot get size of '%s'" % filename)


class LogWatchError(Exception):
    pass
