#!/usr/bin/env python
from wsgiref.simple_server import make_server
import sys
import json
import traceback
import datetime
from multiprocessing import Process
from getopt import getopt, GetoptError
from jsonrpcbase import JSONRPCService, InvalidParamsError, KeywordError,\
    JSONRPCError, ServerError, InvalidRequestError
from os import environ
from ConfigParser import ConfigParser
from biokbase import log
import biokbase.nexus
import requests as _requests
import urlparse as _urlparse
import random as _random
import os
import requests.packages.urllib3

DEPLOY = 'KB_DEPLOYMENT_CONFIG'
SERVICE = 'KB_SERVICE_NAME'

# Note that the error fields do not match the 2.0 JSONRPC spec

def get_config_file():
    return environ.get(DEPLOY, None)


def get_service_name():
    return environ.get(SERVICE, None)


def get_config():
    if not get_config_file():
        return None
    retconfig = {}
    config = ConfigParser()
    config.read(get_config_file())
    for nameval in config.items(get_service_name() or 'mcashman_FS'):
        retconfig[nameval[0]] = nameval[1]
    return retconfig

config = get_config()

from mcashman_FS.mcashman_FSImpl import mcashman_FS
impl_mcashman_FS = mcashman_FS(config)


class JSONObjectEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, set):
            return list(obj)
        if isinstance(obj, frozenset):
            return list(obj)
        if hasattr(obj, 'toJSONable'):
            return obj.toJSONable()
        return json.JSONEncoder.default(self, obj)

sync_methods = {}
async_run_methods = {}
async_check_methods = {}
async_run_methods['mcashman_FS.FeatureSelection_async'] = ['mcashman_FS', 'FeatureSelection']
async_check_methods['mcashman_FS.FeatureSelection_check'] = ['mcashman_FS', 'FeatureSelection']
sync_methods['mcashman_FS.FeatureSelection'] = True

class AsyncJobServiceClient(object):

    def __init__(self, timeout=30 * 60, token=None,
                 ignore_authrc=True, trust_all_ssl_certificates=False):
        url = environ.get('KB_JOB_SERVICE_URL', None)
        if url is None and config is not None:
            url = config.get('job-service-url')
        if url is None:
            raise ValueError('Neither \'job-service-url\' parameter is defined in '+
                    'configuration nor \'KB_JOB_SERVICE_URL\' variable is defined in system')
        scheme, _, _, _, _, _ = _urlparse.urlparse(url)
        if scheme not in ['http', 'https']:
            raise ValueError(url + " isn't a valid http url")
        self.url = url
        self.timeout = int(timeout)
        self._headers = dict()
        self.trust_all_ssl_certificates = trust_all_ssl_certificates
        if token is None:
            raise ValueError('Authentication is required for async methods')        
        self._headers['AUTHORIZATION'] = token
        if self.timeout < 1:
            raise ValueError('Timeout value must be at least 1 second')

    def _call(self, method, params, json_rpc_call_context = None):
        arg_hash = {'method': method,
                    'params': params,
                    'version': '1.1',
                    'id': str(_random.random())[2:]
                    }
        if json_rpc_call_context:
            arg_hash['context'] = json_rpc_call_context
        body = json.dumps(arg_hash, cls=JSONObjectEncoder)
        ret = _requests.post(self.url, data=body, headers=self._headers,
                             timeout=self.timeout,
                             verify=not self.trust_all_ssl_certificates)
        if ret.status_code == _requests.codes.server_error:
            if 'content-type' in ret.headers and ret.headers['content-type'] == 'application/json':
                err = json.loads(ret.text)
                if 'error' in err:
                    raise ServerError(**err['error'])
                else:
                    raise ServerError('Unknown', 0, ret.text)
            else:
                raise ServerError('Unknown', 0, ret.text)
        if ret.status_code != _requests.codes.OK:
            ret.raise_for_status()
        resp = json.loads(ret.text)
        if 'result' not in resp:
            raise ServerError('Unknown', 0, 'An unknown server error occurred')
        return resp['result']

    def run_job(self, run_job_params, json_rpc_call_context = None):
        return self._call('KBaseJobService.run_job', [run_job_params], json_rpc_call_context)[0]

    def check_job(self, job_id, json_rpc_call_context = None):
        return self._call('KBaseJobService.check_job', [job_id], json_rpc_call_context)[0]


class JSONRPCServiceCustom(JSONRPCService):

    def call(self, ctx, jsondata):
        """
        Calls jsonrpc service's method and returns its return value in a JSON
        string or None if there is none.

        Arguments:
        jsondata -- remote method call in jsonrpc format
        """
        result = self.call_py(ctx, jsondata)
        if result is not None:
            return json.dumps(result, cls=JSONObjectEncoder)

        return None

    def _call_method(self, ctx, request):
        """Calls given method with given params and returns it value."""
        method = self.method_data[request['method']]['method']
        params = request['params']
        result = None
        try:
            if isinstance(params, list):
                # Does it have enough arguments?
                if len(params) < self._man_args(method) - 1:
                    raise InvalidParamsError('not enough arguments')
                # Does it have too many arguments?
                if(not self._vargs(method) and len(params) >
                        self._max_args(method) - 1):