import urlparse
import sys
import util
import json
import cgi
import multiprocessing
from multiprocessing import Queue
from multiprocessing import Manager
sys.path.append('../')
from util import BackgroundWorker
from urlparse import urlparse, parse_qs
import config as gc

# async_request_queue holds list of active async requests
async_request_queue = {}
#active_threads = []


####################
## ASYNC REQUESTS ##
####################

def project_request(request_handler):
    '''
        POST /project
        {
            "project_name"  : "my project name"
            "username"      : "mm@force.com",
            "password"      : "force",
            "org_type"      : "developer",
            "package"       : {
                "ApexClass"     : "*",
                "ApexTrigger"   : ["Trigger1", "Trigger2"]
            }
        }
    '''
    run_async_operation(request_handler, 'new_project')

def project_edit_request(request_handler):
    '''
        POST /project/edit
        (body same as project_request)
    '''
    run_async_operation(request_handler, 'edit_project')

def project_upgrade_request(request_handler):
    '''
        POST /project/upgrade
        {
            "project_name"  : "my project name"
            "username"      : "mm@force.com",
            "password"      : "force",
            "org_type"      : "developer"
        }
    '''
    run_async_operation(request_handler, 'upgrade_project')

def execute_apex_request(request_handler):
    '''
        POST /apex/execute
        {
            "project_name"    : "my project name"
            "log_level"       : "DEBUG",
            "log_category"    : "APEX_CODE",
            "body"            : "String foo = 'bar';",
        }
    '''
    run_async_operation(request_handler, 'execute_apex')


def deploy_request(request_handler):
    '''
        POST /project/deploy
        call to deploy metadata to a server
        {
            "check_only"            : true,
            "rollback_on_error"     : true,
            "destinations"          : [
                {
                    "username"              : "username1@force.com",
                    "org_type"              : "developer"
                }
            ],
            "package"               : {
                "ApexClass" : "*"
            }
        }
    '''
    run_async_operation(request_handler, 'deploy')

def unit_test_request(request_handler):
    '''
        POST /project/unit_test
        {
            "classes" : [
                "UnitTestClass1", "UnitTestClass2"
            ],
            "run_all_tests" : false
        }
    '''
    gc.logger.debug('in unit test method!')
    run_async_operation(request_handler, 'unit_test')
    
def metadata_index_request(request_handler):
    '''
        call to update the project .metadata index
    '''
    run_async_operation(request_handler, 'index_metadata')



##########################
## SYNCHRONOUS REQUESTS ##
##########################

def get_active_session_request(request_handler):
    '''
        GET /session?username=mm@force.com&password=force&org_type=developer
    '''
    request_id = util.generate_request_id()
    params, json_body = get_request_params(request_handler)
    worker = BackgroundWorker('get_active_session', params, False, request_id, json_body)
    response = worker.run()
    respond(request_handler, response)

def update_credentials_request(request_handler):
    '''
        POST /project/creds
        {
            "project_name"  : "my project name"
            "username"      : "mm@force.com",
            "password"      : "force",
            "org_type"      : "developer",
        }
        NOTE: project name should not be updated, as it is used to find the project in question
        TODO: maybe we assign a unique ID to each project which will give users the flexibility
              to change the project name??
        TODO: we may need to implement a "clean" flag which will clean the project after creds
              have been updated
    '''
    request_id = util.generate_request_id()
    params, raw_post_body = get_request_params(request_handler)
    worker = BackgroundWorker('update_credentials', params, False, request_id, raw_post_body)
    response = worker.run()
    respond(request_handler, response)

def connections_list_request(request_handler):
    request_id = util.generate_request_id()
    params, raw_post_body = get_request_params(request_handler)
    worker = BackgroundWorker('list_connections', params, False, request_id, raw_post_body)
    response = worker.run()
    respond(request_handler, response)

def connections_new_request(request_handler):
    request_id = util.generate_request_id()
    params, raw_post_body = get_request_params(request_handler)
    worker = BackgroundWorker('new_connection', params, False, request_id, raw_post_body)
    response = worker.run()
    respond(request_handler, response)

def connections_delete_request(request_handler):
    request_id = util.generate_request_id()
    params, raw_post_body = get_request_params(request_handler)
    worker = BackgroundWorker('delete_connection', params, False, request_id, raw_post_body)
    response = worker.run()
    respond(request_handler, response)

def metadata_list_request(request_handler):
    '''
        GET /metadata/list
        {
            "sid"             : "",
            "metadata_type"   : "",
            "murl"            : ""
        }
        call to get a list of metadata of a certain type
    '''
    request_id = util.generate_request_id()
    params, json_body = get_request_params(request_handler)
    worker = BackgroundWorker('list_metadata', params, False, request_id, json_body)
    response = worker.run()
    respond(request_handler, response)

##########################
## END REQUEST HANDLERS ##
##########################




def run_async_operation(request_handler, operation_name):
    gc.logger.debug('>>> running an async operation')
    request_id = util.generate_request_id()
    params, raw_post_body = get_request_params(request_handler)
    gc.logger.debug(request_id)
    gc.logger.debug(params)
    gc.logger.debug(raw_post_body)
    
    worker_thread = BackgroundWorker(operation_name, params, True, request_id, raw_post_body)
    gc.logger.debug('worker created')
    worker_thread.start()
    gc.logger.debug('worker thread started')
    async_request_queue[request_id] = worker_thread
    gc.logger.debug('placed into queue')

    #q = Queue() #on larger object puts, process would hang
    #using manager based on this recommendation:
    #http://stackoverflow.com/questions/11442892/python-multiprocessing-queue-failure
    # manager = Manager()
    # q = manager.Queue() #TODO: request is failing here many times
    # gc.logger.debug('finished with queue')
    #worker = BackgroundWorker(operation_name, params, True, request_id, raw_post_body, q)
    #gc.logger.debug('worker created')
    #p = multiprocessing.Process(target=process_request_in_background,args=(worker,))
    #p.start()
    #gc.logger.debug('started process!')
    #add_to_request_queue(request_id, p, q)
    #gc.logger.debug('preparing to response with the async id!')
    return respond_with_async_request_id(request_handler, request_id)

#client polls this servlet to determine whether the request is done
#if the request IS done, it will respond with the body of the request
def status_request(request_handler):
    gc.logger.debug('>>> status request')
    params, json_string = get_request_params(request_handler)
    gc.logger.debug('>>> params: ')
    gc.logger.debug(params)
    try:
        request_id = params['id']
    except:
        request_id = params['id'][0]
    gc.logger.debug('>>> request id: ' + request_id)
    gc.logger.debug('>>> async queue: ')
    gc.logger.debug(async_request_queue)

    if request_id not in async_request_queue:
        response = { 'status' : 'error', 'id' : request_id, 'body' : 'Request ID was not found' }
        response_body = json.dumps(response)
        respond(request_handler, response_body, 'text/json')
    else:
        async_thread = async_request_queue[request_id]
        gc.logger.debug('found async thread')
        gc.logger.debug(async_thread)
        if async_thread.is_alive():
            gc.logger.debug('>>> request is not ready')
            print '>>>> NOT READY....'
            respond_with_async_request_id(request_handler, request_id)
        elif async_thread.is_alive() == False:
            gc.logger.debug('>>> request is probably ready, returning response!!')
            print '>>>> DONE!!!'
            async_request_queue.pop(request_id, None)