###################################################################################
# LAVA QA tool - Command to show the job output (log)
# Copyright (C) 2015, 2016 Collabora Ltd.

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  US
###################################################################################

import sys
import time
from xmlrpclib import Fault

from lqa_api.exit_codes import APPLICATION_ERROR
from lqa_api.job import Job
from lqa_tool.settings import lqa_logger
from lqa_tool.commands import Command

class OutputCmd(Command):

    def __init__(self, args):
        Command.__init__(self, args)

    def run(self):
        try:
            self._run()
        except EnvironmentError as e:
            lqa_logger.error("lqa output: error: {}".format(e))
            exit(APPLICATION_ERROR)

    def _run(self):
        job = Job(self.args.job_id, self.server)
        if self.args.live:
            # If the --live option is passed, read incrementing offset of the
            # output to show live.
            # Wait for the job to start if it is in a submitted state.
            if job.is_submitted():
                lqa_logger.info("Waiting for job to start: {}".format(job))
                while job.is_submitted():
                    time.sleep(1)

            offset = 0
            while job.is_running():
                offset = self._fetch_and_write_output(offset, job)
                time.sleep(0.5)
            # Run one more time to catch any left data from the time.sleep delay.
            # This call also helps to fetch the output for non-running states.
            self._fetch_and_write_output(offset, job)
        else:
            # Otherwise just fetch and show the output file at once.
            try:
                output_data = job.output()
                if self.args.file:
                    with open(self.args.file, 'w+') as f:
                        f.write(output_data)
                else:
                    # Print to stdout
                    sys.stdout.write(output_data)
                    sys.stdout.flush()
            except Fault as e:
                # 404 Job output not found.
                if e.faultCode == 404:
                    err_msg(e, job)
                else:
                    lqa_logger.error("lqa output: error: {}".format(e))
                exit(APPLICATION_ERROR)

    def _fetch_and_write_output(self, offset, job):
        try:
            output_data = job.output(offset)
            if output_data:
                sys.stdout.write(output_data)
                offset = offset + len(output_data)
        except Fault as e:
            if e.faultCode == 404:
                # Skip this error code only during the short time when the job
                # started running but the log is not yet available.
                if job.is_running():
                    return offset
                err_msg(e, job)
            else:
                lqa_logger.error("lqa output: error: {}".format(e))
            exit(APPLICATION_ERROR)
        return offset

def err_msg(e, job):
    lqa_logger.error("{}: Status for job '{}': {}"\
                     .format(e.faultString, job, job.status))
