# For Http calls
import httplib
import urllib
import json

# For reading passwords without echoing
import getpass


def getClusters(serverName,serverPort,token,clusterURL="/arcgis/admin/clusters"):
    """Return a list of clusters (as dict) on a site

    Example: getClusters(*inputTokenParams())

    """
    clustersObj = getClustersObject(serverName,serverPort,token,clusterURL="/arcgis/admin/clusters")
    return clustersObj['clusters']

def getStartedClusters(serverName,serverPort,token,clusterURL="/arcgis/admin/clusters"):
    """Return a list of started clusters (as dict) on a site

    Example: getStartedClusters(*inputTokenParams())

    """
    clustersObj = getClustersObject(serverName,serverPort,token,clusterURL="/arcgis/admin/clusters")
    return [i for i in clustersObj['clusters'] if i['configuredState'] == 'STARTED']
    
def getClusterName(cluster):
    """Return name for a cluster given a cluster dictionary

    Useful for mapping a list of clusters to a list of cluster names
    Example: map(getClusterName,getClusters(*inputTokenParams()))

    """
    if isinstance(cluster,dict):
        return cluster.get('clusterName')
    else:
        return None

def getMachines(cluster):
    """Return list of machines in a cluster given a cluster dictionary

    Useful for mapping a list of clusters to a list of lists of machines in each cluster
    Example: map(getClusterName,getClusters(*inputTokenParams()))

    """
    if isinstance(cluster,dict):
        return cluster.get('machineNames')
    else:
        return None

def getClustersObject(serverName,serverPort,token,clusterURL="/arcgis/admin/clusters"):
    """Return dict representation of clusters given connection information for a site

    Example: clustersObj = getClustersObject(*inputTokenParams())

    """
    params = urllib.urlencode({'token': token, 'f': 'json'})
    httpConn = httplib.HTTPConnection(serverName, serverPort)
    httpConn.request("POST",clusterURL,params,getHttpHeaders())
    clusterResponse = httpConn.getresponse()
    if (clusterResponse.status != 200):
        httpConn.close()
        print "Error while reading service." + str(service) + "Please check the URL and try again."
        return
    else:
        clusterData = clusterResponse.read()
        
        # Check that data returned is not an error object
        if not assertJsonSuccess(clusterData):
            print "Error when reading service information. " + str(clusterData)                    
        else:
            print "\tCluster information from server " + serverName + " read successfully."
    clustersObj = json.loads(clusterData)
    httpConn.close()
    return clustersObj

def inputTokenParams(tokenURL="/arcgis/admin/generateToken"):
    """Return tuple of serverName, serverPort,and token from raw_input parameters.

    token is None if getToken is unable to authenticate.

    """
    # Ask for admin/publisher user name and password
    username = raw_input("Enter user name: ")
    password = getpass.getpass("Enter password: ")
    
    # Ask for server name
    serverName = raw_input("Enter Server name: ")
    serverPort = 6080

    print "Obtaining token"

    # Get a token
    token = getToken(username, password, serverName, serverPort, tokenURL)
    if (token[2] == "" or token[2] == None):
        print "Could not generate a token with the username and password provided."
        token[2] == None
    else:
        print "Authenticated."
    return token

def getHttpHeaders():
    """Return the applicable http header used for all requests generated by this module."""
    return {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}

def getFolderURL(folder="ROOT"):
    """Return the correct folder url given a folder name.
    
    Keyword arguments:
    folder -- the folder name (default "ROOT")

    """
    
    return "/arcgis/admin/services/" + getFolder(folder)

def getFolder(folder):
    """Return folder url in correct format given a folder name,
    
    Keyword arguments:
    folder -- the folder name (default "ROOT")

    """
    if (str.upper(str(folder)) == "ROOT" or str(folder) ==""):
        return ""
    else:
        return str(folder) + "/"

def getToken(username, password, serverName, serverPort=6080,tokenURL="/arcgis/admin/generateToken"):
    """Return an ArcGIS Server token as (serverName,serverPort,token) given username, password and adminURL.

    token is None if an error is returned during authentication

    Keyword arguemnts:
    username -- administrative login username
    password -- administrative login password, may be echoed in terminal
    serverName -- name of a server within the site
    serverPort -- server administrative communication port (default 6080)
    tokenURL -- the adminURL for token generation( default "/arcgis/admin/generateToken")

    """  
    params = urllib.urlencode({'username': username, 'password': password, 'client': 'requestip', 'f': 'json'})
    
    # Connect to URL and post parameters
    httpConn = httplib.HTTPConnection(serverName, serverPort)
    httpConn.request("POST", tokenURL, params, getHttpHeaders())
    
    # Read response
    response = httpConn.getresponse()
    if (response.status != 200):
        httpConn.close()
        print "Error while fetching tokens from admin URL. Please check the URL and try again."
        return (serverName,serverPort,None)
    else:
        data = response.read()
        httpConn.close()
        
        # Check that data returned is not an error object
        if not assertJsonSuccess(data):            
            return (serverName,serverPort,None)
        
        # Extract the token from it
        token = json.loads(data)
        return (serverName,serverPort,token['token'])
        
def assertJsonSuccess(data):
    """Check that the input JSON object is not an error object."""
    obj = json.loads(data)
    if 'status' in obj and obj['status'] == "error":
        print "Error: JSON object returns an error. " + str(obj)
        return False
    else:
        return True
