#!/usr/bin/env python
import logging
import io
from time import sleep
import json
import requests

from . import *

logging.basicConfig(filename='terminal.log', level=logging.DEBUG)


class PyTerminal():
    



class CommandOutput():
    """
     Class representing the output of the command execution
    """


    def __init__(self, response, http_code, success, terminal=None):
        """
        :param response:   command response format
        :param http_code:       http_response code
        """
        self._http_response_code = http_code
        self._success = success
        if success and response is not None:
            self._response = response

        self._files = []
        self.terminal = terminal

    def is_success_sent(self):
        """
        :return:                boolean, true if the request was successfully sent to the server
        """
        return self._success

    def http_response_code(self):
        """
        :return:                http_response code from the underlying request
        """
        return self._http_response_code

    def get_output(self):
        """
        :return:                list of strings representing the output from the command
                                lines are single strings
                                table rows are single strings with tabs delimiting columns
        """
        logging.debug('get_output')
        logging.debug(self._http_response_code)
        logging.debug(self._success)
        if not self._success:
            logging.warn('There is no output to parse, because command execution failed: raising IllegalStateException')
            raise IllegalStateException('There is no output to parse, because command execution failed')

        if self._response is not None:
            # Result is a list of strings representing the output from the command
            return self._response
        else:
            logging.warn('Illegal server response. Raising InternalError')
            raise InternalError('Illegal server response')

        logging.debug('get_output returning lines')
        return ""


"""
    This class allows the execution of a command in the same way as the web-cli does. The return is a
    CommandOutput instance which holds the text lines generated by the command execution. The content is the same as it
    would be in the web-cli.
    """
    _content_type = "application/text"
    _se_post_command_headers = {'X-Requested-With': 'XMLHttpRequest', 'Accept': _content_type}

    _se_poll_command_headers = {'X-Requested-With': 'XMLHttpRequest', 'Accept': _content_type,
                                'Accept-Encoding': 'gzip, deflate, sdch'}

    _content_type_octectstream = "application/octet-stream"

    def __init__(self, url, session):
        """
        Default
        """
        self.session = session
        self.url = url
        self._set_se_urls(url)
        self._response=""

    def execute(self, command_str, file=None, timeout_seconds=600):
        """
        Execute the command and return the result from Server.

        :param command_str:    command to be executed. For more information about a command's syntax, please
        check the online help
        :param file:       file object to be imported  - optional parameter - needed if the command requires a file for
        upload
        :return CommandOutput: CommandOutput instance
        """
        logging.debug('Executing command...')

        try:
            self._response = self._se_command_post(command_str, file)
        except requests.exceptions.ConnectionError as e:
            if str(e) == '(\'Connection aborted.\', BadStatusLine(\"\'\'\",))':
                logging.debug('Re-trying post request.' + str(e))
                self._response = self._se_command_post(command_str, file)
            else:
                raise e

        if self.is_download_present() is True:
            logging.info("Download request")
            bytes = self._get_bytes(self._response.text)
            return bytes

        if self._response.status_code is 200:
            logging.debug('Command executed successfully: ' + command_str)
            return CommandOutput(self._response.text, self._response.status_code, True)

        logging.debug('Command executed successfully: ' + command_str)
        return CommandOutput(self._response.text, self._response.status_code, True, self)

    def _header(self, content_type):
        return {'X-Requested-With': 'XMLHttpRequest', 'Accept': content_type}

    def _download(self, file_id, path):
        logging.debug('Downloading file from Server')
        response = self._se_download_result(file_id)
        with io.open(path, 'wb') as handle:
            for block in response.iter_content(1024):
                if not block:
                    break
                handle.write(block)
            logging.debug('Wrote file {} to disk'.format(path))

    def _get_bytes(self, file_id):
        logging.debug('Downloading file from Server')
        response = self._se_download_result(file_id)
        filename = response.headers['content-disposition'].split("\"")[1]
        buf = bytearray()
        for b in response.iter_content():
            if not b:
                break
            buf.extend(b)
        logging.debug('Wrote {} bytes to memory'.format(len(buf)))
        return filename,buf

    def _set_se_urls(self, url):
        self._uri_server_command_execute = url + '/Certificate/rest/certapi/execute/'
        self._uri_server_command_download = url + '/Certificate/rest/certapi/download/'

    def _se_command_post(self, command, file_in=None):
        logging.debug('POST command request')

        file_data = {'name': 'command', 'command': command}
        req_data = None

        response = self.session.post(
            self._uri_server_command_execute+command,
            headers=self._se_post_command_headers,
            files=file_data,
            data=req_data,
            verify=False,
            allow_redirects=False)

        logging.debug('POST command request executed')
        return response

    def _se_download_result(self, file_id):
        response = self.session.get(
            self._uri_server_command_download + file_id
        			, stream=True, headers=self._header(self._content_type_octectstream))
        return response

    def is_download_present(self):
        if "http" in self._response.text:
            return True
        return False